diff options
author | Hans Goudey <h.goudey@me.com> | 2022-08-27 04:41:14 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-08-27 05:02:13 +0300 |
commit | 9b2338f686d47e0a04e4903d1345ded1332cd4ab (patch) | |
tree | fbd628c8a7384301bc125db8f538d46099664cc1 /source | |
parent | cca8b650947494db6ab79dcecb88508d34516b57 (diff) | |
parent | 37d835f0bca28a7cbf577385d9828636e7811cc5 (diff) |
Merge branch 'master' into refactor-mesh-bevel-weight-generic
Diffstat (limited to 'source')
559 files changed, 10857 insertions, 6293 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 75824ae056f..d3226a8f609 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -353,6 +353,8 @@ enum { BLF_LAST_RESORT = 1 << 15, /** Failure to load this font. Don't try again. */ BLF_BAD_FONT = 1 << 16, + /** This font is managed by the FreeType cache subsystem. */ + BLF_CACHED = 1 << 17, }; #define BLF_DRAW_STR_DUMMY_MAX 1024 diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index a2b84290e67..986a261dc4b 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../imbuf ../makesdna ../makesrna - ../../../intern/glew-mx ../../../intern/guardedalloc ) diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 36475321d4c..6fcb74e9cb0 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -22,6 +22,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_string.h" #include "BLI_threads.h" #include "BLF_api.h" @@ -885,12 +886,21 @@ void BLF_draw_buffer(int fontid, const char *str, const size_t str_len) char *BLF_display_name_from_file(const char *filepath) { - FontBLF *font = blf_font_new("font_name", filepath); - if (!font) { - return NULL; + /* While listing font directories this function can be called simultaneously from a greater + * number of threads than we want the FreeType cache to keep open at a time. Therefore open + * with own FT_Library object and use FreeType calls directly to avoid any contention. */ + char *name = NULL; + FT_Library ft_library; + if (FT_Init_FreeType(&ft_library) == FT_Err_Ok) { + FT_Face face; + if (FT_New_Face(ft_library, filepath, 0, &face) == FT_Err_Ok) { + if (face->family_name) { + name = BLI_sprintfN("%s %s", face->family_name, face->style_name); + } + FT_Done_Face(face); + } + FT_Done_FreeType(ft_library); } - char *name = blf_display_name(font); - blf_font_free(font); return name; } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index b3729b7a673..8941eb01d3a 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -17,9 +17,10 @@ #include <ft2build.h> #include FT_FREETYPE_H +#include FT_CACHE_H /* FreeType Cache. */ #include FT_GLYPH_H #include FT_MULTIPLE_MASTERS_H /* Variable font support. */ -#include FT_TRUETYPE_IDS_H /* Codepoint coverage constants. */ +#include FT_TRUETYPE_IDS_H /* Code-point coverage constants. */ #include FT_TRUETYPE_TABLES_H /* For TT_OS2 */ #include "MEM_guardedalloc.h" @@ -55,6 +56,8 @@ BatchBLF g_batch; /* freetype2 handle ONLY for this file! */ static FT_Library ft_lib = NULL; +static FTC_Manager ftc_manager = NULL; +static FTC_CMapCache ftc_charmap_cache = NULL; /* Lock for FreeType library, used around face creation and deletion. */ static ThreadMutex ft_lib_mutex; @@ -67,19 +70,81 @@ 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) +/** \name FreeType Caching + * \{ */ + +/** + * Called when a face is removed by the cache. FreeType will call #FT_Done_Face. + */ +static void blf_face_finalizer(void *object) { - return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0; + FT_Face face = object; + FontBLF *font = (FontBLF *)face->generic.data; + font->face = NULL; +} + +/** + * Called in response to #FTC_Manager_LookupFace. Now add a face to our font. + * + * \note Unused arguments are kept to match #FTC_Face_Requester function signature. + */ +static FT_Error blf_cache_face_requester(FTC_FaceID faceID, + FT_Library lib, + FT_Pointer UNUSED(reqData), + FT_Face *face) +{ + FontBLF *font = (FontBLF *)faceID; + int err = FT_Err_Cannot_Open_Resource; + + BLI_mutex_lock(&ft_lib_mutex); + if (font->filepath) { + err = FT_New_Face(lib, font->filepath, 0, face); + } + else if (font->mem) { + err = FT_New_Memory_Face(lib, font->mem, (FT_Long)font->mem_size, 0, face); + } + BLI_mutex_unlock(&ft_lib_mutex); + + if (err == FT_Err_Ok) { + font->face = *face; + font->face->generic.data = font; + font->face->generic.finalizer = blf_face_finalizer; + } + + return err; +} + +/** + * Called when the FreeType cache is removing a font size. + */ +static void blf_size_finalizer(void *object) +{ + FT_Size size = object; + FontBLF *font = (FontBLF *)size->generic.data; + font->ft_size = NULL; } /* -------------------------------------------------------------------- */ /** \name FreeType Utilities (Internal) * \{ */ +/* Return glyph id from charcode. */ +uint blf_get_char_index(struct FontBLF *font, uint charcode) +{ + if (font->flags & BLF_CACHED) { + /* Use charmap cache for much faster lookup. */ + return FTC_CMapCache_Lookup(ftc_charmap_cache, font, -1, charcode); + } + /* Fonts that are not cached need to use the regular lookup function. */ + return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0; +} + /* 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) { + /* Make sure we have a valid font->ft_size. */ + blf_ensure_size(font); + /* Scale value by font size using integer-optimized multiplication. */ FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale); @@ -344,7 +409,7 @@ static void blf_font_draw_ex(FontBLF *font, const char *str, const size_t str_len, struct ResultBLF *r_info, - ft_pix pen_y) + const ft_pix pen_y) { GlyphBLF *g, *g_prev = NULL; ft_pix pen_x = 0; @@ -445,7 +510,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, /* buffer specific vars */ FontBufInfoBLF *buf_info = &font->buf_info; const float *b_col_float = buf_info->col_float; - const unsigned char *b_col_char = buf_info->col_char; + const uchar *b_col_char = buf_info->col_char; int chx, chy; int y, x; @@ -534,7 +599,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, const size_t buf_ofs = (((size_t)(chx + x) + ((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) * (size_t)buf_info->ch); - unsigned char *cbuf = buf_info->cbuf + buf_ofs; + uchar *cbuf = buf_info->cbuf + buf_ofs; uchar font_pixel[4]; font_pixel[0] = b_col_char[0]; @@ -1091,7 +1156,7 @@ int blf_font_count_missing_chars(FontBLF *font, *r_tot_chars = 0; while (i < str_len) { - unsigned int c; + uint c; if ((c = str[i]) < GLYPH_ASCII_TABLE_SIZE) { i++; @@ -1115,6 +1180,7 @@ int blf_font_count_missing_chars(FontBLF *font, static ft_pix blf_font_height_max_ft_pix(FontBLF *font) { + blf_ensure_size(font); /* 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)); } @@ -1126,6 +1192,7 @@ int blf_font_height_max(FontBLF *font) static ft_pix blf_font_width_max_ft_pix(FontBLF *font) { + blf_ensure_size(font); /* 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)); } @@ -1137,11 +1204,13 @@ int blf_font_width_max(FontBLF *font) int blf_font_descender(FontBLF *font) { + blf_ensure_size(font); return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender); } int blf_font_ascender(FontBLF *font) { + blf_ensure_size(font); return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender); } @@ -1164,12 +1233,29 @@ int blf_font_init(void) memset(&g_batch, 0, sizeof(g_batch)); BLI_mutex_init(&ft_lib_mutex); int err = FT_Init_FreeType(&ft_lib); + if (err == FT_Err_Ok) { + /* Create a FreeType cache manager. */ + err = FTC_Manager_New(ft_lib, + BLF_CACHE_MAX_FACES, + BLF_CACHE_MAX_SIZES, + BLF_CACHE_BYTES, + blf_cache_face_requester, + NULL, + &ftc_manager); + if (err == FT_Err_Ok) { + /* Create a charmap cache to speed up glyph index lookups. */ + err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache); + } + } return err; } void blf_font_exit(void) { BLI_mutex_end(&ft_lib_mutex); + if (ftc_manager) { + FTC_Manager_Done(ftc_manager); + } if (ft_lib) { FT_Done_FreeType(ft_lib); } @@ -1229,8 +1315,6 @@ static void blf_font_fill(FontBLF *font) font->buf_info.col_init[1] = 0; font->buf_info.col_init[2] = 0; font->buf_info.col_init[3] = 0; - - font->ft_lib = ft_lib; } /** @@ -1248,14 +1332,20 @@ bool blf_ensure_face(FontBLF *font) FT_Error err; - BLI_mutex_lock(&ft_lib_mutex); - if (font->filepath) { - err = FT_New_Face(ft_lib, font->filepath, 0, &font->face); + if (font->flags & BLF_CACHED) { + err = FTC_Manager_LookupFace(ftc_manager, font, &font->face); } - if (font->mem) { - err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face); + else { + BLI_mutex_lock(&ft_lib_mutex); + if (font->filepath) { + err = FT_New_Face(font->ft_lib, font->filepath, 0, &font->face); + } + if (font->mem) { + err = FT_New_Memory_Face(font->ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face); + } + font->face->generic.data = font; + BLI_mutex_unlock(&ft_lib_mutex); } - BLI_mutex_unlock(&ft_lib_mutex); if (err) { if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) { @@ -1295,7 +1385,11 @@ bool blf_ensure_face(FontBLF *font) } } - font->ft_size = font->face->size; + if (!(font->flags & BLF_CACHED)) { + /* Not cached so point at the face's size for convenience. */ + font->ft_size = font->face->size; + } + font->face_flags = font->face->face_flags; if (FT_HAS_MULTIPLE_MASTERS(font)) { @@ -1305,10 +1399,10 @@ bool blf_ensure_face(FontBLF *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) { - font->UnicodeRanges[0] = (uint)os2_table->ulUnicodeRange1; - font->UnicodeRanges[1] = (uint)os2_table->ulUnicodeRange2; - font->UnicodeRanges[2] = (uint)os2_table->ulUnicodeRange3; - font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4; + font->unicode_ranges[0] = (uint)os2_table->ulUnicodeRange1; + font->unicode_ranges[1] = (uint)os2_table->ulUnicodeRange2; + font->unicode_ranges[2] = (uint)os2_table->ulUnicodeRange3; + font->unicode_ranges[3] = (uint)os2_table->ulUnicodeRange4; } if (FT_IS_FIXED_WIDTH(font)) { @@ -1328,16 +1422,16 @@ bool blf_ensure_face(FontBLF *font) return true; } -typedef struct eFaceDetails { +struct FaceDetails { char name[50]; - unsigned int coverage1; - unsigned int coverage2; - unsigned int coverage3; - unsigned int coverage4; -} eFaceDetails; + uint coverage1; + uint coverage2; + uint coverage3; + uint coverage4; +}; /* Details about the fallback fonts we ship, so that we can load only when needed. */ -static const eFaceDetails static_face_details[] = { +static const struct FaceDetails 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}, @@ -1366,11 +1460,16 @@ static const eFaceDetails static_face_details[] = { {"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) +/** + * Create a new font from filename OR memory pointer. + * For normal operation pass NULL as FT_Library object. Pass a custom FT_Library if you + * want to use the font without its lifetime being managed by the FreeType cache subsystem. + */ +FontBLF *blf_font_new_ex(const char *name, + const char *filepath, + const uchar *mem, + const size_t mem_size, + void *ft_library) { FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); @@ -1382,24 +1481,39 @@ static FontBLF *blf_font_new_ex(const char *name, } blf_font_fill(font); + if (ft_library && ((FT_Library)ft_library != ft_lib)) { + font->ft_lib = (FT_Library)ft_library; + } + else { + font->ft_lib = ft_lib; + font->flags |= BLF_CACHED; + } + + font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib; + BLI_mutex_init(&font->glyph_cache_mutex); - /* 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; + /* If we have static details about this font file, we don't have to load the Face yet. */ + bool face_needed = true; + + if (font->filepath) { + const struct FaceDetails *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->unicode_ranges[0] = static_details->coverage1; + font->unicode_ranges[1] = static_details->coverage2; + font->unicode_ranges[2] = static_details->coverage3; + font->unicode_ranges[3] = static_details->coverage4; + face_needed = false; + break; + } } } - if (!static_details) { + if (face_needed) { if (!blf_ensure_face(font)) { blf_font_free(font); return NULL; @@ -1407,25 +1521,25 @@ static FontBLF *blf_font_new_ex(const char *name, } /* 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) { + if (font->unicode_ranges[0] == 0xffffffffU && font->unicode_ranges[1] == 0xffffffffU && + font->unicode_ranges[2] == 0xffffffffU && font->unicode_ranges[3] >= 0x7FFFFFFU) { font->flags |= BLF_LAST_RESORT; } return font; } -FontBLF *blf_font_new(const char *name, const char *filename) +FontBLF *blf_font_new(const char *name, const char *filepath) { - return blf_font_new_ex(name, filename, NULL, 0); + return blf_font_new_ex(name, filepath, NULL, 0, NULL); } -FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, const size_t mem_size) +FontBLF *blf_font_new_from_mem(const char *name, const uchar *mem, const size_t mem_size) { - return blf_font_new_ex(name, NULL, mem, mem_size); + return blf_font_new_ex(name, NULL, mem, mem_size, NULL); } -void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, const size_t mem_size) +void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_size) { FT_Open_Args open; @@ -1446,12 +1560,17 @@ void blf_font_free(FontBLF *font) } if (font->variations) { - FT_Done_MM_Var(ft_lib, font->variations); + FT_Done_MM_Var(font->ft_lib, font->variations); } if (font->face) { BLI_mutex_lock(&ft_lib_mutex); - FT_Done_Face(font->face); + if (font->flags & BLF_CACHED) { + FTC_Manager_RemoveFaceID(ftc_manager, font); + } + else { + FT_Done_Face(font->face); + } BLI_mutex_unlock(&ft_lib_mutex); font->face = NULL; } @@ -1473,7 +1592,29 @@ void blf_font_free(FontBLF *font) /** \name Font Configure * \{ */ -bool blf_font_size(FontBLF *font, float size, unsigned int dpi) +void blf_ensure_size(FontBLF *font) +{ + if (font->ft_size || !(font->flags & BLF_CACHED)) { + return; + } + + FTC_ScalerRec scaler = {0}; + scaler.face_id = font; + scaler.width = 0; + scaler.height = round_fl_to_uint(font->size * 64.0f); + scaler.pixel = 0; + scaler.x_res = font->dpi; + scaler.y_res = font->dpi; + if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) == FT_Err_Ok) { + font->ft_size->generic.data = (void *)font; + font->ft_size->generic.finalizer = blf_size_finalizer; + return; + } + + BLI_assert_unreachable(); +} + +bool blf_font_size(FontBLF *font, float size, uint dpi) { if (!blf_ensure_face(font)) { return false; @@ -1485,16 +1626,30 @@ bool blf_font_size(FontBLF *font, float size, unsigned int dpi) size = (float)ft_size / 64.0f; if (font->size != size || font->dpi != dpi) { - if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) == FT_Err_Ok) { - font->size = size; - font->dpi = dpi; + if (font->flags & BLF_CACHED) { + FTC_ScalerRec scaler = {0}; + scaler.face_id = font; + scaler.width = 0; + scaler.height = ft_size; + scaler.pixel = 0; + scaler.x_res = dpi; + scaler.y_res = dpi; + if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) != FT_Err_Ok) { + return false; + } + font->ft_size->generic.data = (void *)font; + font->ft_size->generic.finalizer = blf_size_finalizer; } else { - printf("The current font does not support the size, %f and DPI, %u\n", size, dpi); - return false; + if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) != FT_Err_Ok) { + return false; + } + font->ft_size = font->face->size; } } + font->size = size; + font->dpi = dpi; return true; } diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index 63957fad003..a88da6099e5 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -53,8 +53,15 @@ void BLF_load_font_stack() BLF_load_default(false); BLF_load_mono_default(false); - const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR SEP_STR); - if (path && BLI_exists(path)) { + const char *datafiles_fonts_dir = BLF_DATAFILES_FONTS_DIR SEP_STR; + const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, datafiles_fonts_dir); + if (UNLIKELY(!path)) { + fprintf(stderr, "Font data directory \"%s\" could not be detected!\n", datafiles_fonts_dir); + } + else if (UNLIKELY(!BLI_exists(path))) { + fprintf(stderr, "Font data directory \"%s\" does not exist!\n", path); + } + else { struct direntry *dir; uint num_files = BLI_filelist_dir_contents(path, &dir); for (int f = 0; f < num_files; f++) { @@ -72,7 +79,4 @@ void BLF_load_font_stack() } BLI_filelist_free(dir, num_files); } - else { - fprintf(stderr, "Fonts not found at %s\n", path); - } } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index f938174f92e..18f372c666b 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -23,9 +23,6 @@ #include "MEM_guardedalloc.h" -#include "DNA_userdef_types.h" -#include "DNA_vec_types.h" - #include "BLI_listbase.h" #include "BLI_rect.h" #include "BLI_threads.h" @@ -33,7 +30,6 @@ #include "BLF_api.h" #include "GPU_capabilities.h" -#include "GPU_immediate.h" #include "blf_internal.h" #include "blf_internal_types.h" @@ -42,6 +38,13 @@ #include "BLI_strict_flags.h" #include "BLI_string_utf8.h" +/** + * Convert glyph coverage amounts to lightness values. Uses a LUT that perceptually improves + * anti-aliasing and results in text that looks a bit fuller and slightly brighter. This should + * be reconsidered in some - or all - cases when we transform the entire UI. + */ +#define BLF_GAMMA_CORRECT_GLYPHS + /* -------------------------------------------------------------------- */ /** \name Internal Utilities * \{ */ @@ -60,7 +63,7 @@ static FT_Fixed to_16dot16(double val) /** \name Glyph Cache * \{ */ -static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi) +static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, const float size, uint dpi) { GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first; while (gc) { @@ -93,6 +96,8 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table)); memset(gc->bucket, 0, sizeof(gc->bucket)); + blf_ensure_size(font); + /* Determine ideal fixed-width size for monospaced output. */ FT_UInt gindex = blf_get_char_index(font, U'0'); if (gindex && font->face) { @@ -166,7 +171,7 @@ void blf_glyph_cache_clear(FontBLF *font) * * \return NULL if not found. */ -static GlyphBLF *blf_glyph_cache_find_glyph(GlyphCacheBLF *gc, uint charcode) +static GlyphBLF *blf_glyph_cache_find_glyph(const GlyphCacheBLF *gc, uint charcode) { if (charcode < GLYPH_ASCII_TABLE_SIZE) { return gc->glyph_ascii_table[charcode]; @@ -182,6 +187,43 @@ static GlyphBLF *blf_glyph_cache_find_glyph(GlyphCacheBLF *gc, uint charcode) return NULL; } +#ifdef BLF_GAMMA_CORRECT_GLYPHS + +/** + * Gamma correction of glyph coverage values with widely-recommended gamma of 1.43. + * "The reasons are historical. Because so many programmers have neglected gamma blending for so + * long, people who have created fonts have tried to work around the problem of fonts looking too + * thin by just making the fonts thicker! Obviously it doesn't help the jaggedness, but it does + * make them look the proper weight, as originally intended. The obvious problem with this is + * that if we want to gamma blend correctly many older fonts will look wrong. So we compromise, + * and use a lower gamma value, so we get a bit better anti-aliasing, but the fonts don't look too + * heavy." + * https://www.puredevsoftware.com/blog/2019/01/22/sub-pixel-gamma-correct-font-rendering/ + */ +static uchar blf_glyph_gamma(uchar c) +{ + /* The following is `(char)(powf(c / 256.0f, 1.0f / 1.43f) * 256.0f)`. */ + static const uchar gamma[256] = { + 0, 5, 9, 11, 14, 16, 19, 21, 23, 25, 26, 28, 30, 32, 34, 35, 37, 38, + 40, 41, 43, 44, 46, 47, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 62, 64, + 65, 66, 67, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, + 86, 87, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, + 156, 157, 157, 158, 159, 160, 161, 162, 163, 163, 164, 165, 166, 167, 168, 168, 169, 170, + 171, 172, 173, 173, 174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 182, 183, 184, 185, + 186, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 194, 195, 196, 197, 198, 198, 199, + 200, 201, 201, 202, 203, 204, 205, 205, 206, 207, 208, 208, 209, 210, 211, 211, 212, 213, + 214, 214, 215, 216, 217, 217, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 226, 226, + 227, 228, 229, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 239, + 240, 241, 242, 242, 243, 244, 244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, + 253, 254, 254, 255}; + return gamma[c]; +} + +#endif /* BLF_GAMMA_CORRECT_GLYPHS */ + /** * Add a rendered glyph to a cache. */ @@ -217,11 +259,19 @@ static GlyphBLF *blf_glyph_cache_add_glyph( glyph->bitmap.buffer[i] = glyph->bitmap.buffer[i] ? 255 : 0; } } + else { +#ifdef BLF_GAMMA_CORRECT_GLYPHS + /* Convert coverage amounts to perceptually-improved lightness values. */ + for (int i = 0; i < buffer_size; i++) { + glyph->bitmap.buffer[i] = blf_glyph_gamma(glyph->bitmap.buffer[i]); + } +#endif /* BLF_GAMMA_CORRECT_GLYPHS */ + } g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap"); memcpy(g->bitmap, glyph->bitmap.buffer, (size_t)buffer_size); } - unsigned int key = blf_hash(g->c); + const uint key = blf_hash(g->c); BLI_addhead(&(gc->bucket[key]), g); if (charcode < GLYPH_ASCII_TABLE_SIZE) { gc->glyph_ascii_table[charcode] = g; @@ -230,18 +280,24 @@ static GlyphBLF *blf_glyph_cache_add_glyph( return g; } -/* This table can be used to find a coverage bit based on a charcode. later we can get default - * language and script from codepoint. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Unicode Block Lookup + * + * This table can be used to find a coverage bit based on a charcode. + * Later we can get default language and script from `codepoint`. + */ -typedef struct eUnicodeBlock { - unsigned int first; - unsigned int last; +struct UnicodeBlock { + uint first; + uint last; int coverage_bit; /* 0-122. -1 is N/A. */ /* Later we add primary script and language for Harfbuzz, data from * https://en.wikipedia.org/wiki/Unicode_block */ -} eUnicodeBlock; +}; -static eUnicodeBlock unicode_blocks[] = { +static const struct UnicodeBlock unicode_blocks[] = { /* Must be in ascending order by start of range. */ {0x0, 0x7F, 0}, /* Basic Latin. */ {0x80, 0xFF, 1}, /* Latin-1 Supplement. */ @@ -500,8 +556,10 @@ static eUnicodeBlock unicode_blocks[] = { {0xE0100, 0xE01EF, 91}, /* Variation Selectors. */ {0xF0000, 0x10FFFD, 90}}; /* Private Use Supplementary. */ -/* Find a unicode block that a charcode belongs to. */ -static eUnicodeBlock *blf_charcode_to_unicode_block(uint charcode) +/** + * Find a unicode block that a `charcode` belongs to. + */ +static const struct UnicodeBlock *blf_charcode_to_unicode_block(const uint charcode) { if (charcode < 0x80) { /* Shortcut to Basic Latin. */ @@ -512,14 +570,13 @@ static eUnicodeBlock *blf_charcode_to_unicode_block(uint charcode) int min = 0; int max = ARRAY_SIZE(unicode_blocks) - 1; - int mid; if (charcode < unicode_blocks[0].first || charcode > unicode_blocks[max].last) { return NULL; } while (max >= min) { - mid = (min + max) / 2; + const int mid = (min + max) / 2; if (charcode > unicode_blocks[mid].last) { min = mid + 1; } @@ -537,26 +594,26 @@ static eUnicodeBlock *blf_charcode_to_unicode_block(uint charcode) static int blf_charcode_to_coverage_bit(uint charcode) { int coverage_bit = -1; - eUnicodeBlock *block = blf_charcode_to_unicode_block(charcode); + const struct UnicodeBlock *block = blf_charcode_to_unicode_block(charcode); if (block) { coverage_bit = block->coverage_bit; } if (coverage_bit < 0 && charcode > 0xFFFF) { /* No coverage bit, but OpenType specs v.1.3+ says bit 57 implies that there - * are codepoints supported beyond the BMP, so only check fonts with this set. */ + * are code-points supported beyond the BMP, so only check fonts with this set. */ coverage_bit = 57; } return coverage_bit; } -static bool blf_font_has_coverage_bit(FontBLF *font, int coverage_bit) +static bool blf_font_has_coverage_bit(const FontBLF *font, int coverage_bit) { if (coverage_bit < 0) { return false; } - return (font->UnicodeRanges[(uint)coverage_bit >> 5] & (1u << ((uint)coverage_bit % 32))); + return (font->unicode_ranges[(uint)coverage_bit >> 5] & (1u << ((uint)coverage_bit % 32))); } /** @@ -570,6 +627,11 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode return glyph_index; } + /* Only fonts managed by the cache can fallback. */ + if (!((*font)->flags & BLF_CACHED)) { + return 0; + } + /* Not found in main font, so look in the others. */ FontBLF *last_resort = NULL; int coverage_bit = blf_charcode_to_coverage_bit(charcode); @@ -608,6 +670,12 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode return 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Load + * \{ */ + /** * Load a glyph into the glyph slot of a font's face object. */ @@ -642,19 +710,19 @@ static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index) return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Render + * \{ */ + /** * Convert a glyph from outlines to a bitmap that we can display. */ static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph) { - int render_mode; - - if (font->flags & BLF_MONOCHROME) { - render_mode = FT_RENDER_MODE_MONO; - } - else { - render_mode = FT_RENDER_MODE_NORMAL; - } + const int render_mode = (font->flags & BLF_MONOCHROME) ? FT_RENDER_MODE_MONO : + FT_RENDER_MODE_NORMAL; /* Render the glyph curves to a bitmap. */ FT_Error err = FT_Render_Glyph(glyph, render_mode); @@ -693,17 +761,19 @@ static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph) * * \param variations: Variation descriptors from `FT_Get_MM_Var`. * \param tag: Axis tag (4-character string as uint), like 'wght' - * \param axis_index: returns index of axis in variations array. + * \param r_axis_index: returns index of axis in variations array. */ -static FT_Var_Axis *blf_var_axis_by_tag(FT_MM_Var *variations, uint tag, int *axis_index) +static const FT_Var_Axis *blf_var_axis_by_tag(const FT_MM_Var *variations, + const uint tag, + int *r_axis_index) { - *axis_index = -1; + *r_axis_index = -1; if (!variations) { return NULL; } for (int i = 0; i < (int)variations->num_axis; i++) { if (variations->axis[i].tag == tag) { - *axis_index = i; + *r_axis_index = i; return &(variations->axis)[i]; break; } @@ -717,7 +787,7 @@ static FT_Var_Axis *blf_var_axis_by_tag(FT_MM_Var *variations, uint tag, int *ax * \param axis: Pointer to a design space axis structure. * \param factor: -1 to 1 with 0 meaning "default" */ -static FT_Fixed blf_factor_to_coordinate(FT_Var_Axis *axis, float factor) +static FT_Fixed blf_factor_to_coordinate(const FT_Var_Axis *axis, const float factor) { FT_Fixed value = axis->def; if (factor > 0) { @@ -738,13 +808,13 @@ static FT_Fixed blf_factor_to_coordinate(FT_Var_Axis *axis, float factor) * \param tag: Axis tag (4-character string as uint), like 'wght' * \param factor: -1 to 1 with 0 meaning "default" */ -static bool blf_glyph_set_variation_normalized(FontBLF *font, +static bool blf_glyph_set_variation_normalized(const FontBLF *font, FT_Fixed coords[], - uint tag, - float factor) + const uint tag, + const float factor) { int axis_index; - FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index); + const FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index); if (axis && (axis_index < BLF_VARIATIONS_MAX)) { coords[axis_index] = blf_factor_to_coordinate(axis, factor); return true; @@ -762,7 +832,7 @@ static bool blf_glyph_set_variation_normalized(FontBLF *font, static bool blf_glyph_set_variation_float(FontBLF *font, FT_Fixed coords[], uint tag, float value) { int axis_index; - FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index); + const FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index); if (axis && (axis_index < BLF_VARIATIONS_MAX)) { FT_Fixed int_value = to_16dot16(value); CLAMP(int_value, axis->minimum, axis->maximum); @@ -787,8 +857,8 @@ static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool mo { if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { /* Fake bold if the font does not have this variable axis. */ - const FT_Pos average_width = FT_MulFix(glyph->face->units_per_EM, - glyph->face->size->metrics.x_scale); + const FontBLF *font = (FontBLF *)glyph->face->generic.data; + const FT_Pos average_width = font->ft_size->metrics.height; FT_Pos change = (FT_Pos)((float)average_width * factor * 0.1f); FT_Outline_EmboldenXY(&glyph->outline, change, change / 2); if (monospaced) { @@ -847,7 +917,8 @@ static bool blf_glyph_transform_width(FT_GlyphSlot glyph, float factor) static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor) { if (glyph->advance.x > 0) { - const long int size = glyph->face->size->metrics.height; + const FontBLF *font = (FontBLF *)glyph->face->generic.data; + const long int size = font->ft_size->metrics.height; glyph->advance.x += (FT_Pos)(factor * (float)size / 6.0f); return true; } @@ -899,6 +970,8 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, blf_font_size(glyph_font, settings_font->size, settings_font->dpi); } + blf_ensure_size(glyph_font); + /* We need to keep track if changes are still needed. */ bool weight_done = false; bool slant_done = false; @@ -927,16 +1000,16 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, FT_Get_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]); /* Update design coordinates with new values. */ weight_done = blf_glyph_set_variation_normalized( - glyph_font, coords, blf_variation_axis_weight, weight); + glyph_font, coords, BLF_VARIATION_AXIS_WEIGHT, weight); slant_done = blf_glyph_set_variation_normalized( - glyph_font, coords, blf_variation_axis_slant, slant); + glyph_font, coords, BLF_VARIATION_AXIS_SLANT, slant); width_done = blf_glyph_set_variation_normalized( - glyph_font, coords, blf_variation_axis_width, width); + glyph_font, coords, BLF_VARIATION_AXIS_WIDTH, width); spacing_done = blf_glyph_set_variation_normalized( - glyph_font, coords, blf_variation_axis_spacing, spacing); + glyph_font, coords, BLF_VARIATION_AXIS_SPACING, spacing); /* Optical size, if available, is set to current font size. */ blf_glyph_set_variation_float( - glyph_font, coords, blf_variation_axis_optsize, settings_font->size); + glyph_font, coords, BLF_VARIATION_AXIS_OPTSIZE, settings_font->size); /* Save updated design coordinates. */ FT_Set_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]); } @@ -971,7 +1044,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, return NULL; } -GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode) +GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode) { GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode); if (g) { @@ -1042,7 +1115,7 @@ static void blf_glyph_calc_rect_shadow( /** \name Glyph Drawing * \{ */ -static void blf_texture_draw(const unsigned char color[4], +static void blf_texture_draw(const uchar color[4], const int glyph_size[2], const int offset, const int x1, @@ -1068,7 +1141,7 @@ static void blf_texture_draw(const unsigned char color[4], } } -static void blf_texture5_draw(const unsigned char color_in[4], +static void blf_texture5_draw(const uchar color_in[4], const int glyph_size[2], const int offset, const int x1, @@ -1084,7 +1157,7 @@ static void blf_texture5_draw(const unsigned char color_in[4], blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2); } -static void blf_texture3_draw(const unsigned char color_in[4], +static void blf_texture3_draw(const uchar color_in[4], const int glyph_size[2], const int offset, const int x1, diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 221e656f096..5c1099d6386 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -16,7 +16,14 @@ struct rcti; /* 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 +#define BLF_MAX_FONT 64 + +/* Maximum number of opened FT_Face objects managed by cache. 0 is default of 2. */ +#define BLF_CACHE_MAX_FACES 4 +/* Maximum number of opened FT_Size objects managed by cache. 0 is default of 4 */ +#define BLF_CACHE_MAX_SIZES 8 +/* Maximum number of bytes to use for cached data nodes. 0 is default of 200,000. */ +#define BLF_CACHE_BYTES 400000 extern struct FontBLF *global_font[BLF_MAX_FONT]; @@ -42,10 +49,17 @@ 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_ensure_size(struct FontBLF *font); void blf_draw_buffer__start(struct FontBLF *font); void blf_draw_buffer__end(void); +struct FontBLF *blf_font_new_ex(const char *name, + const char *filepath, + const unsigned char *mem, + size_t mem_size, + void *ft_library); + 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, size_t mem_size); void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, size_t mem_size); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index dfe24c1aa47..d64bd9c5452 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -12,16 +12,17 @@ #include FT_MULTIPLE_MASTERS_H /* Variable font support. */ -#define BLF_VARIATIONS_MAX 16 /* Maximum variation axes per font. */ +/** Maximum variation axes per font. */ +#define BLF_VARIATIONS_MAX 16 #define MAKE_DVAR_TAG(a, b, c, d) \ (((uint32_t)a << 24u) | ((uint32_t)b << 16u) | ((uint32_t)c << 8u) | ((uint32_t)d)) -#define blf_variation_axis_weight MAKE_DVAR_TAG('w', 'g', 'h', 't') /* 'wght' weight axis. */ -#define blf_variation_axis_slant MAKE_DVAR_TAG('s', 'l', 'n', 't') /* 'slnt' slant axis. */ -#define blf_variation_axis_width MAKE_DVAR_TAG('w', 'd', 't', 'h') /* 'wdth' width axis. */ -#define blf_variation_axis_spacing MAKE_DVAR_TAG('s', 'p', 'a', 'c') /* 'spac' spacing axis. */ -#define blf_variation_axis_optsize MAKE_DVAR_TAG('o', 'p', 's', 'z') /* 'opsz' optical size. */ +#define BLF_VARIATION_AXIS_WEIGHT MAKE_DVAR_TAG('w', 'g', 'h', 't') /* 'wght' weight axis. */ +#define BLF_VARIATION_AXIS_SLANT MAKE_DVAR_TAG('s', 'l', 'n', 't') /* 'slnt' slant axis. */ +#define BLF_VARIATION_AXIS_WIDTH MAKE_DVAR_TAG('w', 'd', 't', 'h') /* 'wdth' width axis. */ +#define BLF_VARIATION_AXIS_SPACING MAKE_DVAR_TAG('s', 'p', 'a', 'c') /* 'spac' spacing axis. */ +#define BLF_VARIATION_AXIS_OPTSIZE MAKE_DVAR_TAG('o', 'p', 's', 'z') /* 'opsz' optical size. */ /* -------------------------------------------------------------------- */ /** \name Sub-Pixel Offset & Utilities @@ -38,10 +39,12 @@ typedef int32_t ft_pix; /* Macros copied from `include/freetype/internal/ftobjs.h`. */ -/* FIXME(@campbellbarton): Follow rounding from Blender 3.1x and older. +/** + * FIXME(@campbellbarton): Follow rounding from Blender 3.1x and older. * This is what users will expect and changing this creates wider spaced text. * Use this macro to communicate that rounding should be used, using floor is to avoid - * user visible changes, which can be reviewed and handled separately. */ + * user visible changes, which can be reviewed and handled separately. + */ #define USE_LEGACY_SPACING #define FT_PIX_FLOOR(x) ((x) & ~63) @@ -85,7 +88,7 @@ BLI_INLINE ft_pix ft_pix_from_float(float v) BLI_INLINE ft_pix ft_pix_round_advance(ft_pix v, ft_pix step) { - /* See #USE_LEGACY_SPACING, rounding logic could change here. */ + /** See #USE_LEGACY_SPACING, rounding logic could change here. */ return FT_PIX_DEFAULT_ROUNDING(v) + FT_PIX_DEFAULT_ROUNDING(step); } @@ -97,24 +100,27 @@ BLI_INLINE ft_pix ft_pix_round_advance(ft_pix v, ft_pix step) #define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */ -/* Number of characters in GlyphCacheBLF.glyph_ascii_table. */ +/** Number of characters in #GlyphCacheBLF.glyph_ascii_table. */ #define GLYPH_ASCII_TABLE_SIZE 128 -/* Number of characters in KerningCacheBLF.table. */ +/** Number of characters in #KerningCacheBLF.table. */ #define KERNING_CACHE_TABLE_SIZE 128 -/* A value in the kerning cache that indicates it is not yet set. */ +/** A value in the kerning cache that indicates it is not yet set. */ #define KERNING_ENTRY_UNSET INT_MAX typedef struct BatchBLF { - struct FontBLF *font; /* can only batch glyph from the same font */ + /** Can only batch glyph from the same font. */ + struct FontBLF *font; struct GPUBatch *batch; struct GPUVertBuf *verts; struct GPUVertBufRaw pos_step, col_step, offset_step, glyph_size_step; unsigned int pos_loc, col_loc, offset_loc, glyph_size_loc; unsigned int glyph_len; - int ofs[2]; /* copy of font->pos */ - float mat[4][4]; /* previous call modelmatrix. */ + /** Copy of `font->pos`. */ + int ofs[2]; + /* Previous call `modelmatrix`. */ + float mat[4][4]; bool enabled, active, simple_shader; struct GlyphCacheBLF *glyph_cache; } BatchBLF; @@ -133,11 +139,12 @@ typedef struct GlyphCacheBLF { struct GlyphCacheBLF *next; struct GlyphCacheBLF *prev; - /* font size. */ + /** Font size. */ float size; - /* and DPI. */ + /** DPI. */ unsigned int dpi; + float char_weight; float char_slant; float char_width; @@ -146,16 +153,16 @@ typedef struct GlyphCacheBLF { bool bold; bool italic; - /* Column width when printing monospaced. */ + /** Column width when printing monospaced. */ int fixed_width; - /* and the glyphs. */ + /** The glyphs. */ ListBase bucket[257]; - /* fast ascii lookup */ + /** Fast ascii lookup */ struct GlyphBLF *glyph_ascii_table[GLYPH_ASCII_TABLE_SIZE]; - /* texture array, to draw the glyphs. */ + /** Texture array, to draw the glyphs. */ GPUTexture *texture; char *bitmap_result; int bitmap_len; @@ -168,13 +175,13 @@ typedef struct GlyphBLF { struct GlyphBLF *next; struct GlyphBLF *prev; - /* and the character, as UTF-32 */ + /** The character, as UTF-32. */ unsigned int c; - /* freetype2 index, to speed-up the search. */ + /** Freetype2 index, to speed-up the search. */ FT_UInt idx; - /* glyph box. */ + /** Glyph bounding-box. */ ft_pix box_xmin; ft_pix box_xmax; ft_pix box_ymin; @@ -182,19 +189,20 @@ typedef struct GlyphBLF { ft_pix advance_x; - /* The difference in bearings when hinting is active, zero otherwise. */ + /** The difference in bearings when hinting is active, zero otherwise. */ ft_pix lsb_delta; ft_pix rsb_delta; - /* position inside the texture where this glyph is store. */ + /** Position inside the texture where this glyph is store. */ int offset; - /* Bitmap data, from freetype. Take care that this + /** + * Bitmap data, from freetype. Take care that this * can be NULL. */ unsigned char *bitmap; - /* Glyph width and height. */ + /** Glyph width and height. */ int dims[2]; int pitch; @@ -209,56 +217,57 @@ typedef struct GlyphBLF { } GlyphBLF; typedef struct FontBufInfoBLF { - /* for draw to buffer, always set this to NULL after finish! */ + /** For draw to buffer, always set this to NULL after finish! */ float *fbuf; - /* the same but unsigned char */ + /** The same but unsigned char. */ unsigned char *cbuf; /** Buffer size, keep signed so comparisons with negative values work. */ int dims[2]; - /* number of channels. */ + /** Number of channels. */ int ch; - /* display device used for color management */ + /** Display device used for color management. */ struct ColorManagedDisplay *display; - /* and the color, the alphas is get from the glyph! - * color is sRGB space */ + /** The color, the alphas is get from the glyph! (color is sRGB space). */ float col_init[4]; - /* cached conversion from 'col_init' */ + /** Cached conversion from 'col_init'. */ unsigned char col_char[4]; float col_float[4]; } FontBufInfoBLF; typedef struct FontBLF { - /* font name. */ + /** Font name. */ char *name; - /* # of times this font was loaded */ - unsigned int reference_count; - - /* Full path to font file or NULL if from memory. */ + /** Full path to font file or NULL if from memory. */ char *filepath; - /* Pointer to in-memory font, or NULL if from file. */ + /** 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 + /** + * 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 */ - uint UnicodeRanges[4]; + * See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur + */ + uint unicode_ranges[4]; - /* aspect ratio or scale. */ + /** Number of times this font was loaded. */ + unsigned int reference_count; + + /** Aspect ratio or scale. */ float aspect[3]; - /* initial position for draw the text. */ + /** Initial position for draw the text. */ int pos[3]; - /* angle in radians. */ + /** Angle in radians. */ float angle; #if 0 /* BLF_BLUR_ENABLE */ @@ -266,49 +275,50 @@ typedef struct FontBLF { int blur; #endif - /* shadow level. */ + /** Shadow level. */ int shadow; - /* and shadow offset. */ + /** And shadow offset. */ int shadow_x; int shadow_y; - /* shadow color. */ + /** Shadow color. */ unsigned char shadow_color[4]; - /* main text color. */ + /** Main text color. */ unsigned char color[4]; - /* Multiplied this matrix with the current one before - * draw the text! see blf_draw__start. + /** + * Multiplied this matrix with the current one before draw the text! + * see #blf_draw_gl__start. */ float m[16]; - /* clipping rectangle. */ + /** Clipping rectangle. */ rcti clip_rec; - /* the width to wrap the text, see BLF_WORD_WRAP */ + /** The width to wrap the text, see #BLF_WORD_WRAP. */ int wrap_width; - /* Font DPI (default 72). */ + /** Font DPI (default 72). */ unsigned int dpi; - /* font size. */ + /** Font size. */ float size; - /* Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */ + /** Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */ FT_MM_Var *variations; - /* Character variation; 0=default, -1=min, +1=max. */ + /** Character variation; 0=default, -1=min, +1=max. */ float char_weight; float char_slant; float char_width; float char_spacing; - /* max texture size. */ + /** Max texture size. */ int tex_size_max; - /* font options. */ + /** Font options. */ int flags; /** @@ -317,25 +327,25 @@ typedef struct FontBLF { */ ListBase cache; - /* Cache of unscaled kerning values. Will be NULL if font does not have kerning. */ + /** Cache of unscaled kerning values. Will be NULL if font does not have kerning. */ KerningCacheBLF *kerning_cache; - /* freetype2 lib handle. */ + /** Freetype2 lib handle. */ FT_Library ft_lib; - /* freetype2 face. */ + /** Freetype2 face. */ FT_Face face; - /* Point to face->size or to cache's size. */ + /** 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. */ + /** 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) */ + /** Data for buffer usage (drawing into a texture buffer) */ FontBufInfoBLF buf_info; - /* Mutex lock for glyph cache. */ + /** Mutex lock for glyph cache. */ ThreadMutex glyph_cache_mutex; } FontBLF; @@ -343,6 +353,6 @@ typedef struct DirBLF { struct DirBLF *next; struct DirBLF *prev; - /* full path where search fonts. */ + /** Full path where search fonts. */ char *path; } DirBLF; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 9460e9413d1..bafa927a440 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -32,26 +32,34 @@ void BLF_thumb_preview(const char *filepath, const char **draw_str, const char **i18n_draw_str, - const unsigned char draw_str_lines, + const uchar draw_str_lines, const float font_color[4], const int font_size, - unsigned char *buf, - int w, - int h, - int channels) + uchar *buf, + const int w, + const int h, + const int channels) { - const unsigned int dpi = 72; + const uint dpi = 72; const int font_size_min = 6; int font_size_curr; /* shrink 1/th each line */ int font_shrink = 4; - FontBLF *font; + /* While viewing thumbnails in font directories this function can be called simultaneously from a + * greater number of threads than we want the FreeType cache to keep open at a time. Therefore + * pass own FT_Library to font creation so that it is not managed by the FreeType cache system. + */ - /* Create a new blender font obj and fill it with default values */ - font = blf_font_new("thumb_font", filepath); + FT_Library ft_library = NULL; + if (FT_Init_FreeType(&ft_library) != FT_Err_Ok) { + return; + } + + FontBLF *font = blf_font_new_ex("thumb_font", filepath, NULL, 0, ft_library); if (!font) { printf("Info: Can't load font '%s', no preview possible\n", filepath); + FT_Done_FreeType(ft_library); return; } @@ -102,4 +110,5 @@ void BLF_thumb_preview(const char *filepath, blf_draw_buffer__end(); blf_font_free(font); + FT_Done_FreeType(ft_library); } diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index 1e61e477759..d29c60a7373 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -150,7 +150,7 @@ template<typename T> struct AttributeReader { }; /** - * Result when looking up an attribute from some geometry with read an write access. After writing + * Result when looking up an attribute from some geometry with read and write access. After writing * to the attribute, the #finish method has to be called. This may invalidate caches based on this * attribute. */ diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index fc8a00af4a1..4b0fc293b54 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -150,7 +150,13 @@ class CurvesGeometry : public ::CurvesGeometry { * Accessors. */ + /** + * The total number of control points in all curves. + */ int points_num() const; + /** + * The number of curves in the data-block. + */ int curves_num() const; IndexRange points_range() const; IndexRange curves_range() const; @@ -338,12 +344,14 @@ class CurvesGeometry : public ::CurvesGeometry { /** Calculates the data described by #evaluated_lengths_for_curve if necessary. */ void ensure_evaluated_lengths() const; + void ensure_can_interpolate_to_evaluated() const; + /** * Evaluate a generic data to the standard evaluated points of a specific curve, * defined by the resolution attribute or other factors, depending on the curve type. * * \warning This function expects offsets to the evaluated points for each curve to be - * calculated. That can be ensured with #ensure_evaluated_offsets. + * calculated. That can be ensured with #ensure_can_interpolate_to_evaluated. */ void interpolate_to_evaluated(int curve_index, GSpan src, GMutableSpan dst) const; /** @@ -551,7 +559,7 @@ void calculate_evaluated_offsets(Span<int8_t> handle_types_left, int resolution, MutableSpan<int> evaluated_offsets); -/** See #insert. */ +/** Knot insertion result, see #insert. */ struct Insertion { float3 handle_prev; float3 left_handle; @@ -561,8 +569,12 @@ struct Insertion { }; /** - * Compute the Bezier segment insertion for the given parameter on the segment, returning - * the position and handles of the new point and the updated existing handle positions. + * Compute the insertion of a control point and handles in a Bezier segment without changing its + * shape. + * \param parameter: Factor in from 0 to 1 defining the insertion point within the segment. + * \return Inserted point parameters including position, and both new and updated handles for + * neighboring control points. + * * <pre> * handle_prev handle_next * x-----------------x diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index d36e6031557..3b9a3333208 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -417,7 +417,7 @@ void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int typ */ void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n); -bool CustomData_set_layer_name(const struct CustomData *data, int type, int n, const char *name); +bool CustomData_set_layer_name(struct CustomData *data, int type, int n, const char *name); const char *CustomData_get_layer_name(const struct CustomData *data, int type, int n); /** @@ -451,6 +451,12 @@ int CustomData_get_stencil_layer(const struct CustomData *data, int type); const char *CustomData_get_active_layer_name(const struct CustomData *data, int type); /** + * Returns name of the default layer of the given type or NULL + * if no such active layer is defined. + */ +const char *CustomData_get_render_layer_name(const struct CustomData *data, int type); + +/** * Copies the data from source to the data element at index in the first layer of type * no effect if there is no layer of type. */ @@ -686,7 +692,7 @@ typedef struct CustomDataTransferLayerMap { size_t data_size; /** Offset of actual data we transfer (in element contained in data_src/dst). */ size_t data_offset; - /** For bitflag transfer, flag(s) to affect in transferred data. */ + /** For bit-flag transfer, flag(s) to affect in transferred data. */ uint64_t data_flag; /** Opaque pointer, to be used by specific interp callback (e.g. transformspace for normals). */ @@ -717,7 +723,7 @@ void CustomData_data_transfer(const struct MeshPairRemap *me_remap, */ void CustomData_blend_write_prepare(CustomData &data, blender::Vector<CustomDataLayer, 16> &layers_to_write, - const blender::Set<blender::StringRef> &skip_names = {}); + const blender::Set<std::string> &skip_names = {}); /** * \param layers_to_write: Layers created by #CustomData_blend_write_prepare. diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index cdca740555a..6551e732300 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -24,8 +24,6 @@ enum { DL_SURF = 2, /** Triangles. */ DL_INDEX3 = 4, - /** Quads, with support for triangles (when values of the 3rd and 4th indices match). */ - DL_INDEX4 = 5, // DL_VERTCOL = 6, /* UNUSED */ /** Isolated points. */ DL_VERTS = 7, @@ -62,15 +60,12 @@ typedef struct DispList { } DispList; 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); void BKE_displist_free(struct ListBase *lb); void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *ob, bool for_render); -void BKE_displist_make_mball(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph, const struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h index b6b1bdab109..a1b97222019 100644 --- a/source/blender/blenkernel/BKE_fcurve_driver.h +++ b/source/blender/blenkernel/BKE_fcurve_driver.h @@ -85,7 +85,6 @@ void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dva void driver_change_variable_type(struct DriverVar *dvar, int type); /** * Validate driver variable name (after being renamed). - * */ void driver_variable_name_validate(struct DriverVar *dvar); /** diff --git a/source/blender/blenkernel/BKE_image_format.h b/source/blender/blenkernel/BKE_image_format.h index 6a03d1d8df5..8f71e1f4648 100644 --- a/source/blender/blenkernel/BKE_image_format.h +++ b/source/blender/blenkernel/BKE_image_format.h @@ -69,7 +69,7 @@ char BKE_imtype_valid_depths(char imtype); * String is from command line `--render-format` argument, * keep in sync with `creator_args.c` help info. */ -char BKE_imtype_from_arg(const char *arg); +char BKE_imtype_from_arg(const char *imtype_arg); /* Conversion between ImBuf settings. */ diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 9fa59c9e81b..aa4b1c69d24 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -27,7 +27,6 @@ void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object * struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); -bool object_deform_mball(struct Object *ob, struct ListBase *dispbase); void outside_lattice(struct Lattice *lt); float (*BKE_lattice_vert_coords_alloc(const struct Lattice *lt, int *r_vert_len))[3]; diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 9a6c3cf2b5f..3d064c7dea7 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -10,6 +10,7 @@ #include "DNA_layer_types.h" #include "DNA_listBase.h" +#include "DNA_object_enums.h" #ifdef __cplusplus extern "C" { @@ -353,13 +354,13 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); #define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance) \ { \ - struct ObjectsInModeIteratorData data_ = { \ - .object_mode = _object_mode, \ - .object_type = _object_type, \ - .view_layer = _view_layer, \ - .v3d = _v3d, \ - .base_active = _view_layer->basact, \ - }; \ + struct ObjectsInModeIteratorData data_; \ + memset(&data_, 0, sizeof(data_)); \ + data_.object_mode = _object_mode; \ + data_.object_type = _object_type; \ + data_.view_layer = _view_layer; \ + data_.v3d = _v3d; \ + data_.base_active = _view_layer->basact; \ ITER_BEGIN (BKE_view_layer_bases_in_mode_iterator_begin, \ BKE_view_layer_bases_in_mode_iterator_next, \ BKE_view_layer_bases_in_mode_iterator_end, \ @@ -520,46 +521,28 @@ struct Object **BKE_view_layer_array_from_objects_in_mode_params( uint *len, const struct ObjectsInModeParams *params); -#define BKE_view_layer_array_from_objects_in_mode(view_layer, v3d, r_len, ...) \ - BKE_view_layer_array_from_objects_in_mode_params( \ - view_layer, v3d, r_len, &(const struct ObjectsInModeParams)__VA_ARGS__) - -#define BKE_view_layer_array_from_bases_in_mode(view_layer, v3d, r_len, ...) \ - BKE_view_layer_array_from_bases_in_mode_params( \ - view_layer, v3d, r_len, &(const struct ObjectsInModeParams)__VA_ARGS__) - bool BKE_view_layer_filter_edit_mesh_has_uvs(const struct Object *ob, void *user_data); bool BKE_view_layer_filter_edit_mesh_has_edges(const struct Object *ob, void *user_data); -/* Utility macros that wrap common args (add more as needed). */ - -#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_objects_in_mode(view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT}) - -#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_bases_in_mode(view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT}) - -#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_objects_in_mode( \ - view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT, .no_dup_data = true}) - -#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_bases_in_mode( \ - view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT, .no_dup_data = true}) - -#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( \ - view_layer, v3d, r_len) \ - BKE_view_layer_array_from_objects_in_mode( \ - view_layer, \ - v3d, \ - r_len, \ - {.object_mode = OB_MODE_EDIT, \ - .no_dup_data = true, \ - .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs}) - -#define BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, v3d, r_len, mode) \ - BKE_view_layer_array_from_objects_in_mode( \ - view_layer, v3d, r_len, {.object_mode = mode, .no_dup_data = true}) +/* Utility functions that wrap common arguments (add more as needed). */ + +struct Object **BKE_view_layer_array_from_objects_in_edit_mode(struct ViewLayer *view_layer, + const struct View3D *v3d, + uint *r_len); +struct Base **BKE_view_layer_array_from_bases_in_edit_mode(struct ViewLayer *view_layer, + const struct View3D *v3d, + uint *r_len); +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + struct ViewLayer *view_layer, const struct View3D *v3d, uint *r_len); + +struct Base **BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + struct ViewLayer *view_layer, const struct View3D *v3d, uint *r_len); +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + struct ViewLayer *view_layer, const struct View3D *v3d, uint *r_len); +struct Object **BKE_view_layer_array_from_objects_in_mode_unique_data(struct ViewLayer *view_layer, + const struct View3D *v3d, + uint *r_len, + eObjectMode mode); struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer); void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index a23d010b51f..7d265ceb102 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -55,18 +55,9 @@ bool BKE_mball_is_basis(const struct Object *ob); struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob); /** - * Compute bounding box of all meta-elements / meta-ball. - * - * Bounding box is computed from polygonized surface. \a ob is - * basic meta-balls (with name `Meta` for example). All other meta-ball objects - * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box. - */ -void BKE_mball_texspace_calc(struct Object *ob); -/** * Return or compute bounding-box for given meta-ball object. */ struct BoundBox *BKE_mball_boundbox_get(struct Object *ob); -float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase); /** * Copy some properties from a meta-ball obdata to all other meta-ball obdata belonging to the same @@ -110,18 +101,7 @@ bool BKE_mball_select_swap_multi_ex(struct Base **bases, int bases_len); /* **** Depsgraph evaluation **** */ -struct Depsgraph; - -/* Draw Cache */ - -enum { - BKE_MBALL_BATCH_DIRTY_ALL = 0, -}; -void BKE_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode); -void BKE_mball_batch_cache_free(struct MetaBall *mb); - -extern void (*BKE_mball_batch_cache_dirty_tag_cb)(struct MetaBall *mb, int mode); -extern void (*BKE_mball_batch_cache_free_cb)(struct MetaBall *mb); +void BKE_mball_data_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h index 2dc16dc64d6..0840c51bb4d 100644 --- a/source/blender/blenkernel/BKE_mball_tessellate.h +++ b/source/blender/blenkernel/BKE_mball_tessellate.h @@ -12,11 +12,11 @@ extern "C" { struct Depsgraph; struct Object; struct Scene; +struct Mesh; -void BKE_mball_polygonize(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct ListBase *dispbase); +struct Mesh *BKE_mball_polygonize(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); void BKE_mball_cubeTable_free(void); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index b9f6b4b73f3..8cf973b785c 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -193,7 +193,6 @@ void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh); struct Mesh *BKE_mesh_from_object(struct Object *ob); void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me); -void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me); void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, int edge_users_test); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index b42b9df510d..509de0620c6 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1326,16 +1326,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define CMP_CHAN_RGB 1 #define CMP_CHAN_A 2 -/* filter types */ -#define CMP_FILT_SOFT 0 -#define CMP_FILT_SHARP_BOX 1 -#define CMP_FILT_LAPLACE 2 -#define CMP_FILT_SOBEL 3 -#define CMP_FILT_PREWITT 4 -#define CMP_FILT_KIRSCH 5 -#define CMP_FILT_SHADOW 6 -#define CMP_FILT_SHARP_DIAMOND 7 - /* scale node type, in custom1 */ #define CMP_SCALE_RELATIVE 0 #define CMP_SCALE_ABSOLUTE 1 diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 8f3b488c7db..e0fb6c5e834 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -474,8 +474,8 @@ void BKE_object_handle_data_update(struct Depsgraph *depsgraph, */ void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); /** - * The main object update call, for object matrix, constraints, keys and #DispList (modifiers) - * requires flags to be set! + * The main object update call, for object matrix, constraints, keys and modifiers. + * Requires flags to be set! * * Ideally we shouldn't have to pass the rigid body world, * but need bigger restructuring to avoid id. diff --git a/source/blender/blenkernel/BKE_outliner_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h deleted file mode 100644 index 6f4d126fcbf..00000000000 --- a/source/blender/blenkernel/BKE_outliner_treehash.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#pragma once - -/** \file - * \ingroup bke - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct BLI_mempool; -struct ID; -struct TreeStoreElem; - -/* create and fill hashtable with treestore elements */ -void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore); - -/* full rebuild for already allocated hashtable */ -void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore); - -/* clear element usage flags */ -void BKE_outliner_treehash_clear_used(void *treehash); - -/* Add/remove hashtable elements */ -void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem); -void BKE_outliner_treehash_remove_element(void *treehash, struct TreeStoreElem *elem); - -/* find first unused element with specific type, nr and id */ -struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, - short type, - short nr, - struct ID *id); - -/* find user or unused element with specific type, nr and id */ -struct TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, - short type, - short nr, - struct ID *id); - -/* free treehash structure */ -void BKE_outliner_treehash_free(void *treehash); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/blenkernel/BKE_outliner_treehash.hh b/source/blender/blenkernel/BKE_outliner_treehash.hh new file mode 100644 index 00000000000..7f1dad5fd68 --- /dev/null +++ b/source/blender/blenkernel/BKE_outliner_treehash.hh @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#pragma once + +/** \file + * \ingroup bke + * + * Hash table of tree-store elements (#TreeStoreElem) for fast lookups via a (id, type, index) + * tuple as key. + * + * The Outliner may have to perform many lookups for rebuilding complex trees, so this should be + * treated as performance sensitive. + */ + +#include <memory> + +#include "BLI_map.hh" + +struct BLI_mempool; +struct ID; +struct TreeStoreElem; + +namespace blender::bke::outliner::treehash { + +/* -------------------------------------------------------------------- */ + +class TreeStoreElemKey { + public: + ID *id = nullptr; + short type = 0; + short nr = 0; + + explicit TreeStoreElemKey(const TreeStoreElem &elem); + TreeStoreElemKey(ID *id, short type, short nr); + + uint64_t hash() const; + friend bool operator==(const TreeStoreElemKey &a, const TreeStoreElemKey &b); +}; + +/* -------------------------------------------------------------------- */ + +class TreeHash { + Map<TreeStoreElemKey, std::unique_ptr<class TseGroup>> elem_groups_; + + public: + ~TreeHash(); + + /** Create and fill hash-table with treestore elements */ + static std::unique_ptr<TreeHash> create_from_treestore(BLI_mempool &treestore); + + /** Full rebuild for already allocated hash-table. */ + void rebuild_from_treestore(BLI_mempool &treestore); + + /** Clear element usage flags. */ + void clear_used(); + + /** Add hash-table element. */ + void add_element(TreeStoreElem &elem); + /** Remove hash-table element. */ + void remove_element(TreeStoreElem &elem); + + /** Find first unused element with specific type, nr and id. */ + TreeStoreElem *lookup_unused(short type, short nr, ID *id) const; + + /** Find user or unused element with specific type, nr and id. */ + TreeStoreElem *lookup_any(short type, short nr, ID *id) const; + + private: + TreeHash() = default; + + TseGroup *lookup_group(const TreeStoreElemKey &key) const; + TseGroup *lookup_group(const TreeStoreElem &elem) const; + TseGroup *lookup_group(short type, short nr, ID *id) const; + void fill_treehash(BLI_mempool &treestore); +}; + +} // namespace blender::bke::outliner::treehash diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index fa67ff08383..92b1aacc300 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -60,10 +60,10 @@ struct bContext; struct bToolRef; struct tPaletteColorHSV; -extern const char PAINT_CURSOR_SCULPT[3]; -extern const char PAINT_CURSOR_VERTEX_PAINT[3]; -extern const char PAINT_CURSOR_WEIGHT_PAINT[3]; -extern const char PAINT_CURSOR_TEXTURE_PAINT[3]; +extern const uchar PAINT_CURSOR_SCULPT[3]; +extern const uchar PAINT_CURSOR_VERTEX_PAINT[3]; +extern const uchar PAINT_CURSOR_WEIGHT_PAINT[3]; +extern const uchar PAINT_CURSOR_TEXTURE_PAINT[3]; typedef enum ePaintMode { PAINT_MODE_SCULPT = 0, @@ -98,6 +98,7 @@ typedef enum ePaintOverlayControlFlags { PAINT_OVERLAY_OVERRIDE_PRIMARY = (1 << 5), PAINT_OVERLAY_OVERRIDE_SECONDARY = (1 << 6), } ePaintOverlayControlFlags; +ENUM_OPERATORS(ePaintOverlayControlFlags, PAINT_OVERLAY_OVERRIDE_SECONDARY); #define PAINT_OVERRIDE_MASK \ (PAINT_OVERLAY_OVERRIDE_SECONDARY | PAINT_OVERLAY_OVERRIDE_PRIMARY | \ @@ -157,7 +158,7 @@ struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); * Call when entering each respective paint mode. */ bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint); -void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]); +void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const uchar col[3]); void BKE_paint_free(struct Paint *p); /** * Called when copying scene settings, so even if 'src' and 'tar' are the same still do a diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 2be3f323d07..8c9488b0b46 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -350,10 +350,13 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, void *user_data, bool full_render); -void BKE_pbvh_draw_debug_cb( - PBVH *pbvh, - void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), - void *user_data); +void BKE_pbvh_draw_debug_cb(PBVH *pbvh, + void (*draw_fn)(PBVHNode *node, + void *user_data, + const float bmin[3], + const float bmax[3], + PBVHNodeFlags flag), + void *user_data); /* PBVH Access */ @@ -711,6 +714,7 @@ void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_col void BKE_pbvh_ensure_node_loops(PBVH *pbvh); bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh); +int BKE_pbvh_debug_draw_gen_get(PBVHNode *node); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh index e73950e6299..ad8eca2b36f 100644 --- a/source/blender/blenkernel/BKE_pbvh_pixels.hh +++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh @@ -186,8 +186,14 @@ struct NodeData { { UDIMTilePixels *tile = find_tile_data(image_tile); if (tile && tile->flags.dirty) { - BKE_image_partial_update_mark_region( - &image, image_tile.image_tile, &image_buffer, &tile->dirty_region); + if (image_buffer.planes == 8) { + image_buffer.planes = 32; + BKE_image_partial_update_mark_full_update(&image); + } + else { + BKE_image_partial_update_mark_region( + &image, image_tile.image_tile, &image_buffer, &tile->dirty_region); + } tile->clear_dirty(); } } diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 9965b6f1351..11c37a74a54 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -134,7 +134,7 @@ void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *s void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle); -void BKE_sound_mute_scene_sound(void *handle, char mute); +void BKE_sound_mute_scene_sound(void *handle, bool mute); void BKE_sound_move_scene_sound(const struct Scene *scene, void *handle, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index e3f00d03a3b..0d76bf994b7 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -25,7 +25,6 @@ set(INC ../simulation ../../../intern/eigen ../../../intern/ghost - ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/iksolver/extern ../../../intern/atomic @@ -238,9 +237,9 @@ set(SRC intern/object_update.c intern/ocean.c intern/ocean_spectrum.c - intern/outliner_treehash.c + intern/outliner_treehash.cc intern/packedFile.c - intern/paint.c + intern/paint.cc intern/paint_canvas.cc intern/paint_toolslots.c intern/particle.c @@ -280,7 +279,7 @@ set(SRC intern/subdiv_displacement_multires.c intern/subdiv_eval.c intern/subdiv_foreach.c - intern/subdiv_mesh.c + intern/subdiv_mesh.cc intern/subdiv_modifier.c intern/subdiv_stats.c intern/subdiv_topology.c @@ -445,7 +444,7 @@ set(SRC BKE_object_deform.h BKE_object_facemap.h BKE_ocean.h - BKE_outliner_treehash.h + BKE_outliner_treehash.hh BKE_packedFile.h BKE_paint.h BKE_particle.h diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 70c3dc2de39..d7f30c99397 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -453,7 +453,7 @@ static void handle_subversion_warning(Main *main, BlendFileReadReport *reports) (main->minversionfile == BLENDER_FILE_VERSION && main->minsubversionfile > BLENDER_FILE_SUBVERSION)) { BKE_reportf(reports->reports, - RPT_ERROR, + RPT_WARNING, "File written by newer Blender binary (%d.%d), expect loss of data!", main->minversionfile, main->minsubversionfile); diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index a86d6e25ee9..2e07b52c7bf 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -1567,7 +1567,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) cross_v3_v3v3(mat[1], mat[2], mat[0]); /* apply rotation */ - mat3_to_quat_is_ok(q, mat); + mat3_to_quat_legacy(q, mat); copy_qt_qt(pa->state.rot, q); } diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index f90cf48090c..6211f6b7be6 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -366,6 +366,8 @@ namespace blender::bke { Curves *curves_new_nomain(const int points_num, const int curves_num) { + BLI_assert(points_num >= 0); + BLI_assert(curves_num >= 0); Curves *curves_id = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr)); CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); curves.resize(points_num, curves_num); diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 6fdcb56fc91..e60523c23da 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -939,6 +939,12 @@ void CurvesGeometry::ensure_evaluated_lengths() const this->runtime->length_cache_dirty = false; } +void CurvesGeometry::ensure_can_interpolate_to_evaluated() const +{ + this->ensure_evaluated_offsets(); + this->ensure_nurbs_basis_cache(); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 6c6160ac0f1..bcecfc1b289 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2627,6 +2627,12 @@ const char *CustomData_get_active_layer_name(const CustomData *data, const int t return layer_index < 0 ? nullptr : data->layers[layer_index].name; } +const char *CustomData_get_render_layer_name(const CustomData *data, const int type) +{ + const int layer_index = CustomData_get_render_layer_index(data, type); + return layer_index < 0 ? nullptr : data->layers[layer_index].name; +} + void CustomData_set_layer_active(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { @@ -3537,10 +3543,7 @@ int CustomData_get_offset_named(const CustomData *data, int type, const char *na return data->layers[layer_index].offset; } -bool CustomData_set_layer_name(const CustomData *data, - const int type, - const int n, - const char *name) +bool CustomData_set_layer_name(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); @@ -4355,7 +4358,7 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str void CustomData_blend_write_prepare(CustomData &data, Vector<CustomDataLayer, 16> &layers_to_write, - const Set<StringRef> &skip_names) + const Set<std::string> &skip_names) { for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) { if (layer.flag & CD_FLAG_NOCOPY) { @@ -5133,7 +5136,7 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, else { const LayerTypeInfo *type_info = layerType_getInfo(data_type); - /* NOTE: we can use 'fake' CDLayers, like e.g. for crease :/. */ + /* NOTE: we can use 'fake' CDLayers for crease :/. */ data_size = (size_t)type_info->size; data_step = laymap->elem_size ? laymap->elem_size : data_size; data_offset = laymap->data_offset; diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc index 0b3ed584246..b87d675496c 100644 --- a/source/blender/blenkernel/intern/displist.cc +++ b/source/blender/blenkernel/intern/displist.cc @@ -34,10 +34,8 @@ #include "BKE_displist.h" #include "BKE_geometry_set.hh" #include "BKE_key.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_mball.h" -#include "BKE_mball_tessellate.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -86,120 +84,6 @@ DispList *BKE_displist_find(ListBase *lb, int type) return nullptr; } -void BKE_displist_normals_add(ListBase *lb) -{ - float *vdata, *ndata, nor[3]; - float *v1, *v2, *v3, *v4; - float *n1, *n2, *n3, *n4; - int a, b, p1, p2, p3, p4; - - LISTBASE_FOREACH (DispList *, dl, lb) { - if (dl->type == DL_INDEX3) { - if (dl->nors == nullptr) { - dl->nors = (float *)MEM_callocN(sizeof(float[3]), __func__); - - if (dl->flag & DL_BACK_CURVE) { - dl->nors[2] = -1.0f; - } - else { - dl->nors[2] = 1.0f; - } - } - } - else if (dl->type == DL_SURF) { - if (dl->nors == nullptr) { - dl->nors = (float *)MEM_callocN(sizeof(float[3]) * dl->nr * dl->parts, __func__); - - vdata = dl->verts; - ndata = dl->nors; - - for (a = 0; a < dl->parts; a++) { - - if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4) == 0) { - break; - } - - v1 = vdata + 3 * p1; - n1 = ndata + 3 * p1; - v2 = vdata + 3 * p2; - n2 = ndata + 3 * p2; - v3 = vdata + 3 * p3; - n3 = ndata + 3 * p3; - v4 = vdata + 3 * p4; - n4 = ndata + 3 * p4; - - for (; b < dl->nr; b++) { - normal_quad_v3(nor, v1, v3, v4, v2); - - add_v3_v3(n1, nor); - add_v3_v3(n2, nor); - add_v3_v3(n3, nor); - add_v3_v3(n4, nor); - - v2 = v1; - v1 += 3; - v4 = v3; - v3 += 3; - n2 = n1; - n1 += 3; - n4 = n3; - n3 += 3; - } - } - a = dl->parts * dl->nr; - v1 = ndata; - while (a--) { - normalize_v3(v1); - v1 += 3; - } - } - } - } -} - -void BKE_displist_count(const ListBase *lb, int *totvert, int *totface, int *tottri) -{ - LISTBASE_FOREACH (const DispList *, dl, lb) { - int vert_tot = 0; - int face_tot = 0; - int tri_tot = 0; - bool cyclic_u = dl->flag & DL_CYCL_U; - bool cyclic_v = dl->flag & DL_CYCL_V; - - switch (dl->type) { - case DL_SURF: { - int segments_u = dl->nr - (cyclic_u == false); - int segments_v = dl->parts - (cyclic_v == false); - vert_tot = dl->nr * dl->parts; - face_tot = segments_u * segments_v; - tri_tot = face_tot * 2; - break; - } - case DL_INDEX3: { - vert_tot = dl->nr; - face_tot = dl->parts; - tri_tot = face_tot; - break; - } - case DL_INDEX4: { - vert_tot = dl->nr; - face_tot = dl->parts; - tri_tot = face_tot * 2; - break; - } - case DL_POLY: - case DL_SEGM: { - vert_tot = dl->nr * dl->parts; - break; - } - } - - *totvert += vert_tot; - *totface += face_tot; - *tottri += tri_tot; - } -} - bool BKE_displist_surfindex_get( const DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4) { @@ -230,7 +114,6 @@ bool BKE_displist_surfindex_get( return true; } -/* ****************** Make #DispList ********************* */ #ifdef __INTEL_COMPILER /* ICC with the optimization -02 causes crashes. */ # pragma intel optimization_level 1 @@ -625,27 +508,6 @@ float BKE_displist_calc_taper( return displist_calc_taper(depsgraph, scene, taperobj, fac); } -void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - if (!ob || ob->type != OB_MBALL) { - return; - } - - if (ob == BKE_mball_basis_find(scene, ob)) { - if (ob->runtime.curve_cache) { - BKE_displist_free(&(ob->runtime.curve_cache->disp)); - } - else { - ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__); - } - - BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp); - BKE_mball_texspace_calc(ob); - - object_deform_mball(ob, &ob->runtime.curve_cache->disp); - } -} - static ModifierData *curve_get_tessellate_point(const Scene *scene, const Object *ob, const bool for_render, @@ -1501,20 +1363,19 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3]) { - bool doit = false; + bool empty = true; LISTBASE_FOREACH (const DispList *, dl, dispbase) { - const int tot = (ELEM(dl->type, DL_INDEX3, DL_INDEX4)) ? dl->nr : dl->nr * dl->parts; + const int tot = dl->type == DL_INDEX3 ? dl->nr : dl->nr * dl->parts; for (const int i : IndexRange(tot)) { minmax_v3v3_v3(min, max, &dl->verts[i * 3]); } if (tot != 0) { - doit = true; + empty = false; } } - if (!doit) { - /* there's no geometry in displist, use zero-sized boundbox */ + if (empty) { zero_v3(min); zero_v3(max); } diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index e4c7572b9e4..11c3dfc18dc 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -768,19 +768,19 @@ static void fcm_cycles_evaluate(FCurve *UNUSED(fcu), } static FModifierTypeInfo FMI_CYCLES = { - FMODIFIER_TYPE_CYCLES, /* type */ - sizeof(FMod_Cycles), /* size */ - FMI_TYPE_EXTRAPOLATION, /* action type */ - FMI_REQUIRES_ORIGINAL_DATA, /* requirements */ - N_("Cycles"), /* name */ - "FMod_Cycles", /* struct name */ - sizeof(tFCMED_Cycles), /* storage size */ - NULL, /* free data */ - NULL, /* copy data */ - fcm_cycles_new_data, /* new data */ - NULL /*fcm_cycles_verify*/, /* verify */ - fcm_cycles_time, /* evaluate time */ - fcm_cycles_evaluate, /* evaluate */ + FMODIFIER_TYPE_CYCLES, /* type */ + sizeof(FMod_Cycles), /* size */ + FMI_TYPE_EXTRAPOLATION, /* action type */ + FMI_REQUIRES_ORIGINAL_DATA, /* requirements */ + CTX_N_(BLT_I18NCONTEXT_ID_ACTION, "Cycles"), /* name */ + "FMod_Cycles", /* struct name */ + sizeof(tFCMED_Cycles), /* storage size */ + NULL, /* free data */ + NULL, /* copy data */ + fcm_cycles_new_data, /* new data */ + NULL /*fcm_cycles_verify*/, /* verify */ + fcm_cycles_time, /* evaluate time */ + fcm_cycles_evaluate, /* evaluate */ }; /* Noise F-Curve Modifier --------------------------- */ diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc index a2f58baebf7..24f59d5e49e 100644 --- a/source/blender/blenkernel/intern/idprop_create.cc +++ b/source/blender/blenkernel/intern/idprop_create.cc @@ -84,7 +84,7 @@ template< std::unique_ptr<IDProperty, IDPropertyDeleter> create_array(StringRefNull prop_name, Span<PrimitiveType> values) { - static_assert(std::is_same_v<PrimitiveType, int32_t> || std::is_same_v<PrimitiveType, float_t> || + static_assert(std::is_same_v<PrimitiveType, int32_t> || std::is_same_v<PrimitiveType, float> || std::is_same_v<PrimitiveType, double>, "Allowed values for PrimitiveType are int32_t, float and double."); static_assert(!std::is_same_v<PrimitiveType, int32_t> || id_property_subtype == IDP_INT, diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index d915a9db76c..d6caec86b5d 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -926,7 +926,7 @@ int BKE_image_find_nearest_tile_with_offset(const Image *image, zero_v2(r_uv_offset); int tile_number_best = -1; - if (image->source != IMA_SRC_TILED) { + if (!image || image->source != IMA_SRC_TILED) { return tile_number_best; } @@ -5519,7 +5519,7 @@ RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name) } else { int n = BLI_listbase_count(&ima->renderslots) + 1; - BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", n); + BLI_snprintf(slot->name, sizeof(slot->name), DATA_("Slot %d"), n); } BLI_addtail(&ima->renderslots, slot); return slot; diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index 6506b40b603..08fdd715512 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -138,6 +138,8 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) int arraywidth = 0, arrayheight = 0; ListBase boxes = {nullptr}; + int planes = 0; + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { ImageUser iuser; BKE_imageuser_default(&iuser); @@ -164,6 +166,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) BKE_image_release_ibuf(ima, ibuf, nullptr); BLI_addtail(&boxes, packtile); + planes = max_ii(planes, ibuf->planes); } } @@ -195,9 +198,15 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) } const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH); + const bool use_grayscale = planes <= 8; /* Create Texture without content. */ - GPUTexture *tex = IMB_touch_gpu_texture( - ima->id.name + 2, main_ibuf, arraywidth, arrayheight, arraylayers, use_high_bitdepth); + GPUTexture *tex = IMB_touch_gpu_texture(ima->id.name + 2, + main_ibuf, + arraywidth, + arrayheight, + arraylayers, + use_high_bitdepth, + use_grayscale); /* Upload each tile one by one. */ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { @@ -223,6 +232,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) tilelayer, UNPACK2(tilesize), use_high_bitdepth, + use_grayscale, store_premultiplied); } diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index d366e9362e8..5ee1258c512 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -821,7 +821,7 @@ bool BKE_image_render_write_exr(ReportList *reports, const bool pass_RGBA = (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A")); const bool pass_half_float = half_float && pass_RGBA; - /* Colorspace conversion only happens on RGBA passes. */ + /* Color-space conversion only happens on RGBA passes. */ float *output_rect = (save_as_render && pass_RGBA) ? image_exr_from_scene_linear_to_output( diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index b5c025a40b6..6fb67711ae9 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -398,21 +398,6 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name) return lt; } -bool object_deform_mball(Object *ob, ListBase *dispbase) -{ - if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) { - DispList *dl; - - for (dl = dispbase->first; dl; dl = dl->next) { - BKE_lattice_deform_coords(ob->parent, ob, (float(*)[3])dl->verts, dl->nr, 0, NULL, 1.0f); - } - - return true; - } - - return false; -} - static BPoint *latt_bp(Lattice *lt, int u, int v, int w) { return <->def[BKE_lattice_index_from_uvw(lt, u, v, w)]; diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 4257bccad93..53a9b6d469d 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -572,7 +572,7 @@ void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, con } /* Dependency graph uses view layer name based lookups. */ - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); } /* LayerCollection */ diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c index 0903c2a2cac..13e0a0bcf84 100644 --- a/source/blender/blenkernel/intern/layer_utils.c +++ b/source/blender/blenkernel/intern/layer_utils.c @@ -149,6 +149,65 @@ Object **BKE_view_layer_array_from_objects_in_mode_params(ViewLayer *view_layer, return (Object **)base_array; } +struct Object **BKE_view_layer_array_from_objects_in_edit_mode(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Base **BKE_view_layer_array_from_bases_in_edit_mode(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + return BKE_view_layer_array_from_bases_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + params.no_dup_data = true; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Base **BKE_view_layer_array_from_bases_in_edit_mode_unique_data(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + params.no_dup_data = true; + return BKE_view_layer_array_from_bases_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + ViewLayer *view_layer, const View3D *v3d, uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + params.no_dup_data = true; + params.filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Object **BKE_view_layer_array_from_objects_in_mode_unique_data(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len, + const eObjectMode mode) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = mode; + params.no_dup_data = true; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/lib_id_remapper_test.cc b/source/blender/blenkernel/intern/lib_id_remapper_test.cc index 73edc30d077..03f456d2d1e 100644 --- a/source/blender/blenkernel/intern/lib_id_remapper_test.cc +++ b/source/blender/blenkernel/intern/lib_id_remapper_test.cc @@ -55,6 +55,7 @@ TEST(lib_id_remapper, unassigned) { ID id1; ID *idp = &id1; + BLI_strncpy(id1.name, "OB2", sizeof(id1.name)); IDRemapper *remapper = BKE_id_remapper_create(); BKE_id_remapper_add(remapper, &id1, nullptr); diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index 05a00fb54fd..03ad4b1cd5f 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -366,6 +366,10 @@ static int foreachid_is_hierarchy_leaf_fn(LibraryIDLinkCallbackData *cb_data) ID *id = *cb_data->id_pointer; bool *is_leaf = static_cast<bool *>(cb_data->user_data); + if (cb_data->cb_flag & IDWALK_CB_LOOPBACK) { + return IDWALK_RET_NOP; + } + if (id != nullptr && ID_IS_OVERRIDE_LIBRARY_REAL(id) && id->override_library->hierarchy_root == id_owner->override_library->hierarchy_root) { *is_leaf = false; @@ -1208,6 +1212,7 @@ static void lib_override_library_create_post_process(Main *bmain, ID *id_root, ID *id_instance_hint, Collection *residual_storage, + const Object *old_active_object, const bool is_resync) { /* NOTE: We only care about local IDs here, if a linked object is not instantiated in any way we @@ -1280,6 +1285,14 @@ static void lib_override_library_create_post_process(Main *bmain, BLI_assert(ob_new->id.override_library != nullptr && ob_new->id.override_library->reference == &ob->id); + if (old_active_object == ob) { + Base *basact = BKE_view_layer_base_find(view_layer, ob_new); + if (basact != nullptr) { + view_layer->basact = basact; + } + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + } + if (BLI_gset_lookup(all_objects_in_scene, ob_new) == nullptr) { if (id_root != nullptr && default_instantiating_collection == nullptr) { ID *id_ref = id_root->newid != nullptr ? id_root->newid : id_root; @@ -1370,6 +1383,8 @@ bool BKE_lib_override_library_create(Main *bmain, id_hierarchy_root_reference = id_root_reference; } + const Object *old_active_object = OBACT(view_layer); + const bool success = lib_override_library_create_do(bmain, scene, owner_library, @@ -1392,6 +1407,7 @@ bool BKE_lib_override_library_create(Main *bmain, id_root_reference, id_instance_hint, nullptr, + old_active_object, false); /* Cleanup. */ @@ -1705,6 +1721,7 @@ static bool lib_override_library_resync(Main *bmain, ID *id_root_reference = id_root->override_library->reference; ID *id; + const Object *old_active_object = OBACT(view_layer); if (id_root_reference->tag & LIB_TAG_MISSING) { BKE_reportf(reports != nullptr ? reports->reports : nullptr, @@ -2129,6 +2146,7 @@ static bool lib_override_library_resync(Main *bmain, id_root_reference, id_root, override_resync_residual_storage, + old_active_object, true); } @@ -2649,6 +2667,8 @@ void BKE_lib_override_library_main_resync(Main *bmain, override_resync_residual_storage->flag |= COLLECTION_HIDE_VIEWPORT | COLLECTION_HIDE_RENDER; } + const Object *old_active_object = OBACT(view_layer); + /* Necessary to improve performances, and prevent layers matching override sub-collections to be * lost when re-syncing the parent override collection. * Ref. T73411. */ @@ -2669,8 +2689,15 @@ void BKE_lib_override_library_main_resync(Main *bmain, BKE_layer_collection_resync_allow(); /* Essentially ensures that potentially new overrides of new objects will be instantiated. */ - lib_override_library_create_post_process( - bmain, scene, view_layer, nullptr, nullptr, nullptr, override_resync_residual_storage, true); + lib_override_library_create_post_process(bmain, + scene, + view_layer, + nullptr, + nullptr, + nullptr, + override_resync_residual_storage, + old_active_object, + true); if (BKE_collection_is_empty(override_resync_residual_storage)) { BKE_collection_delete(bmain, override_resync_residual_storage, true); diff --git a/source/blender/blenkernel/intern/mball.cc b/source/blender/blenkernel/intern/mball.cc index 084fea6abbd..1a2b4b22080 100644 --- a/source/blender/blenkernel/intern/mball.cc +++ b/source/blender/blenkernel/intern/mball.cc @@ -4,11 +4,8 @@ /** \file * \ingroup bke * - * MetaBalls are created from a single Object (with a name without number in it), - * here the DispList and BoundBox also is located. + * MetaBalls are created from a single Object (with a name without number in it). * All objects with the same name (but with a number in it) are added to this. - * - * texture coordinates are patched within the displist */ #include <cctype> @@ -25,6 +22,7 @@ #include "DNA_defaults.h" #include "DNA_material_types.h" +#include "DNA_mesh_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -41,11 +39,15 @@ #include "BKE_anim_data.h" #include "BKE_curve.h" #include "BKE_displist.h" +#include "BKE_geometry_set.hh" #include "BKE_idtype.h" +#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_material.h" #include "BKE_mball.h" +#include "BKE_mball_tessellate.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -76,15 +78,12 @@ static void metaball_copy_data(Main *UNUSED(bmain), metaball_dst->editelems = nullptr; metaball_dst->lastelem = nullptr; - metaball_dst->batch_cache = nullptr; } static void metaball_free_data(ID *id) { MetaBall *metaball = (MetaBall *)id; - BKE_mball_batch_cache_free(metaball); - MEM_SAFE_FREE(metaball->mat); BLI_freelistN(&metaball->elems); @@ -111,7 +110,6 @@ static void metaball_blend_write(BlendWriter *writer, ID *id, const void *id_add /* Must always be cleared (meta's don't have their own edit-data). */ mb->needs_flush_to_id = 0; mb->lastelem = nullptr; - mb->batch_cache = nullptr; /* write LibData */ BLO_write_id_struct(writer, MetaBall, id_address, &mb->id); @@ -144,7 +142,6 @@ static void metaball_blend_read_data(BlendDataReader *reader, ID *id) mb->needs_flush_to_id = 0; // mb->edit_elems.first = mb->edit_elems.last = nullptr; mb->lastelem = nullptr; - mb->batch_cache = nullptr; } static void metaball_blend_read_lib(BlendLibReader *reader, ID *id) @@ -249,99 +246,37 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type) return ml; } -void BKE_mball_texspace_calc(Object *ob) -{ - DispList *dl; - BoundBox *bb; - float *data, min[3], max[3] /*, loc[3], size[3] */; - int tot; - bool do_it = false; - - if (ob->runtime.bb == nullptr) { - ob->runtime.bb = MEM_cnew<BoundBox>(__func__); - } - bb = ob->runtime.bb; - - /* Weird one, this. */ - // INIT_MINMAX(min, max); - (min)[0] = (min)[1] = (min)[2] = 1.0e30f; - (max)[0] = (max)[1] = (max)[2] = -1.0e30f; - - dl = static_cast<DispList *>(ob->runtime.curve_cache->disp.first); - while (dl) { - tot = dl->nr; - if (tot) { - do_it = true; - } - data = dl->verts; - while (tot--) { - /* Also weird... but longer. From utildefines. */ - minmax_v3v3_v3(min, max, data); - data += 3; - } - dl = dl->next; - } - - if (!do_it) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; - } - - BKE_boundbox_init_from_minmax(bb, min, max); - - bb->flag &= ~BOUNDBOX_DIRTY; -} BoundBox *BKE_mball_boundbox_get(Object *ob) { BLI_assert(ob->type == OB_MBALL); - - if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { + if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { return ob->runtime.bb; } - - /* This should always only be called with evaluated objects, - * but currently RNA is a problem here... */ - if (ob->runtime.curve_cache != nullptr) { - BKE_mball_texspace_calc(ob); + if (ob->runtime.bb == NULL) { + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); } - return ob->runtime.bb; -} - -float *BKE_mball_make_orco(Object *ob, ListBase *dispbase) -{ - BoundBox *bb; - DispList *dl; - float *data, *orco, *orcodata; - float loc[3], size[3]; - int a; - - /* restore size and loc */ - bb = ob->runtime.bb; - loc[0] = (bb->vec[0][0] + bb->vec[4][0]) / 2.0f; - size[0] = bb->vec[4][0] - loc[0]; - loc[1] = (bb->vec[0][1] + bb->vec[2][1]) / 2.0f; - size[1] = bb->vec[2][1] - loc[1]; - loc[2] = (bb->vec[0][2] + bb->vec[1][2]) / 2.0f; - size[2] = bb->vec[1][2] - loc[2]; - - dl = static_cast<DispList *>(dispbase->first); - orcodata = static_cast<float *>(MEM_mallocN(sizeof(float[3]) * dl->nr, __func__)); - - data = dl->verts; - orco = orcodata; - a = dl->nr; - while (a--) { - orco[0] = (data[0] - loc[0]) / size[0]; - orco[1] = (data[1] - loc[1]) / size[1]; - orco[2] = (data[2] - loc[2]) / size[2]; - - data += 3; - orco += 3; + /* Expect that this function is only called for evaluated objects. */ + const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + float min[3]; + float max[3]; + if (mesh_eval) { + INIT_MINMAX(min, max); + if (!BKE_mesh_minmax(mesh_eval, min, max)) { + copy_v3_fl(min, -1.0f); + copy_v3_fl(max, 1.0f); + } + } + else { + copy_v3_fl(min, 0.0f); + copy_v3_fl(max, 0.0f); } - return orcodata; + BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); + ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; + + return ob->runtime.bb; } bool BKE_mball_is_basis(const Object *ob) @@ -735,20 +670,44 @@ bool BKE_mball_select_swap_multi_ex(Base **bases, int bases_len) /* **** Depsgraph evaluation **** */ -/* Draw Engine */ +void BKE_mball_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + BLI_assert(ob->type == OB_MBALL); -void (*BKE_mball_batch_cache_dirty_tag_cb)(MetaBall *mb, int mode) = nullptr; -void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = nullptr; + BKE_object_free_derived_caches(ob); -void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode) -{ - if (mb->batch_cache) { - BKE_mball_batch_cache_dirty_tag_cb(mb, mode); + const Object *basis_object = BKE_mball_basis_find(scene, ob); + if (ob != basis_object) { + return; } -} -void BKE_mball_batch_cache_free(MetaBall *mb) -{ - if (mb->batch_cache) { - BKE_mball_batch_cache_free_cb(mb); + + Mesh *mesh = BKE_mball_polygonize(depsgraph, scene, ob); + if (mesh == NULL) { + return; } -} + + const MetaBall *mball = static_cast<MetaBall *>(ob->data); + mesh->mat = static_cast<Material **>(MEM_dupallocN(mball->mat)); + mesh->totcol = mball->totcol; + + if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) { + int verts_num; + float(*positions)[3] = BKE_mesh_vert_coords_alloc(mesh, &verts_num); + BKE_lattice_deform_coords(ob->parent, ob, positions, verts_num, 0, NULL, 1.0f); + BKE_mesh_vert_coords_apply(mesh, positions); + MEM_freeN(positions); + } + + ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::create_with_mesh(mesh)); + + if (ob->runtime.bb == NULL) { + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); + } + blender::float3 min(std::numeric_limits<float>::max()); + blender::float3 max(-std::numeric_limits<float>::max()); + if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) { + min = blender::float3(0); + max = blender::float3(0); + } + BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); +}; diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 54def0189b1..1ca4f120bc2 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -14,6 +14,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -24,10 +26,11 @@ #include "BLI_string_utils.h" #include "BLI_utildefines.h" -#include "BKE_global.h" - #include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_lib_id.h" #include "BKE_mball_tessellate.h" /* own include */ +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -427,8 +430,6 @@ static float metaball(PROCESS *process, float x, float y, float z) */ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4) { - int *cur; - #ifdef USE_ACCUM_NORMAL float n[3]; #endif @@ -438,10 +439,9 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4) process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex); } - cur = process->indices[process->curindex++]; - - /* #DispList supports array drawing, treat tri's as fake quad. */ + int *cur = process->indices[process->curindex++]; + /* Treat triangles as fake quads. */ cur[0] = i1; cur[1] = i2; cur[2] = i3; @@ -1371,7 +1371,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje } } -void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase) +Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) { PROCESS process = {0}; const bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER; @@ -1394,10 +1394,10 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa } if (!is_render && (mb->flag == MB_UPDATE_NEVER)) { - return; + return NULL; } if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) { - return; + return NULL; } if (is_render) { @@ -1418,7 +1418,7 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa init_meta(depsgraph, &process, scene, ob); if (process.totelem == 0) { freepolygonize(&process); - return; + return NULL; } build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); @@ -1430,40 +1430,62 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa ob->scale[1] < 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || ob->scale[2] < 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) { freepolygonize(&process); - return; + return NULL; } polygonize(&process); if (process.curindex == 0) { freepolygonize(&process); - return; + return NULL; } - /* add resulting surface to displist */ + freepolygonize(&process); + + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2); - /* Avoid over-allocation since this is stored in the displist. */ - if (process.curindex != process.totindex) { - process.indices = MEM_reallocN(process.indices, sizeof(int[4]) * process.curindex); + mesh->totvert = (int)process.curvertex; + MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_DEFAULT, NULL, mesh->totvert); + for (int i = 0; i < mesh->totvert; i++) { + copy_v3_v3(mvert[i].co, process.co[i]); + mvert->flag = 0; } - if (process.curvertex != process.totvertex) { - process.co = MEM_reallocN(process.co, process.curvertex * sizeof(float[3])); - process.no = MEM_reallocN(process.no, process.curvertex * sizeof(float[3])); + MEM_freeN(process.co); + + mesh->totpoly = (int)process.curindex; + MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_DEFAULT, NULL, mesh->totpoly); + MLoop *mloop = CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_DEFAULT, NULL, mesh->totpoly * 4); + + int loop_offset = 0; + for (int i = 0; i < mesh->totpoly; i++) { + const int *indices = process.indices[i]; + + const int count = indices[2] != indices[3] ? 4 : 3; + mpoly[i].loopstart = loop_offset; + mpoly[i].totloop = count; + mpoly[i].flag = ME_SMOOTH; + + mloop[loop_offset].v = (uint32_t)indices[0]; + mloop[loop_offset + 1].v = (uint32_t)indices[1]; + mloop[loop_offset + 2].v = (uint32_t)indices[2]; + if (count == 4) { + mloop[loop_offset + 3].v = (uint32_t)indices[3]; + } + + loop_offset += count; } + MEM_freeN(process.indices); - DispList *dl = MEM_callocN(sizeof(DispList), "mballdisp"); - BLI_addtail(dispbase, dl); - dl->type = DL_INDEX4; - dl->nr = (int)process.curvertex; - dl->parts = (int)process.curindex; + for (int i = 0; i < mesh->totvert; i++) { + normalize_v3(process.no[i]); + } + mesh->runtime.vert_normals = process.no; + BKE_mesh_vertex_normals_clear_dirty(mesh); - dl->index = (int *)process.indices; + mesh->totloop = loop_offset; - for (uint a = 0; a < process.curvertex; a++) { - normalize_v3(process.no[a]); - } + BKE_mesh_update_customdata_pointers(mesh, false); - dl->verts = (float *)process.co; - dl->nors = (float *)process.no; + BKE_mesh_calc_edges(mesh, false, false); - freepolygonize(&process); + return mesh; } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 3ec3c0ef3b4..cd076b370f1 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -113,7 +113,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int * * While this could be the callers responsibility, keep here since it's * highly unlikely we want to create a duplicate and not use it for drawing. */ - mesh_dst->runtime.is_original = false; + mesh_dst->runtime.is_original_bmesh = false; /* Only do tessface if we have no polys. */ const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0)); @@ -212,6 +212,7 @@ static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data) static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address) { + using namespace blender; Mesh *mesh = (Mesh *)id; const bool is_undo = BLO_write_is_undo(writer); @@ -245,15 +246,18 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address memset(&mesh->pdata, 0, sizeof(mesh->pdata)); } else { + Set<std::string> names_to_skip; if (!BLO_write_is_undo(writer)) { BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); BKE_mesh_legacy_bevel_weight_from_layers(mesh); + /* When converting to the old mesh format, don't save redundant attributes. */ + names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); } - CustomData_blend_write_prepare(mesh->vdata, vert_layers, {".hide_vert"}); - CustomData_blend_write_prepare(mesh->edata, edge_layers, {".hide_edge"}); - CustomData_blend_write_prepare(mesh->ldata, loop_layers); - CustomData_blend_write_prepare(mesh->pdata, poly_layers, {".hide_poly"}); + CustomData_blend_write_prepare(mesh->vdata, vert_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->edata, edge_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->ldata, loop_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->pdata, poly_layers, names_to_skip); } BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 000f356fd6a..db4fe8dc9d3 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -72,61 +72,6 @@ using blender::Span; static CLG_LogRef LOG = {"bke.mesh_convert"}; -void BKE_mesh_from_metaball(ListBase *lb, Mesh *me) -{ - DispList *dl; - MVert *mvert; - MLoop *mloop, *allloop; - MPoly *mpoly; - int a, *index; - - dl = (DispList *)lb->first; - if (dl == nullptr) { - return; - } - - if (dl->type == DL_INDEX4) { - mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, dl->nr); - allloop = mloop = (MLoop *)CustomData_add_layer( - &me->ldata, CD_MLOOP, CD_CALLOC, nullptr, dl->parts * 4); - mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, dl->parts); - me->mvert = mvert; - me->mloop = mloop; - me->mpoly = mpoly; - me->totvert = dl->nr; - me->totpoly = dl->parts; - - for (const int i : IndexRange(dl->nr)) { - copy_v3_v3(me->mvert[i].co, &dl->verts[3 * i]); - } - - a = dl->parts; - index = dl->index; - while (a--) { - int count = index[2] != index[3] ? 4 : 3; - - mloop[0].v = index[0]; - mloop[1].v = index[1]; - mloop[2].v = index[2]; - if (count == 4) { - mloop[3].v = index[3]; - } - - mpoly->totloop = count; - mpoly->loopstart = (int)(mloop - allloop); - mpoly->flag = ME_SMOOTH; - - mpoly++; - mloop += count; - me->totloop += count; - index += 4; - } - - BKE_mesh_update_customdata_pointers(me, true); - BKE_mesh_calc_edges(me, true, false); - } -} - /** * Specialized function to use when we _know_ existing edges don't overlap with poly edges. */ @@ -929,32 +874,21 @@ static Mesh *mesh_new_from_curve_type_object(const Object *object) static Mesh *mesh_new_from_mball_object(Object *object) { - MetaBall *mball = (MetaBall *)object->data; - /* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta * balls and all evaluated child meta balls (since polygonization is only stored in the mother * ball). * * Create empty mesh so script-authors don't run into None objects. */ - if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == nullptr || - BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) { + if (!DEG_is_evaluated_object(object)) { return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); } - Mesh *mesh_result = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); - BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result); - BKE_mesh_texspace_copy_from_object(mesh_result, object); - - /* Copy materials. */ - mesh_result->totcol = mball->totcol; - mesh_result->mat = (Material **)MEM_dupallocN(mball->mat); - if (mball->mat != nullptr) { - for (int i = mball->totcol; i-- > 0;) { - mesh_result->mat[i] = BKE_object_material_get(object, i + 1); - } + const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object); + if (mesh_eval == nullptr) { + return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); } - return mesh_result; + return BKE_mesh_copy_for_eval(mesh_eval, false); } static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc index 3a8a74050de..8a9ce901923 100644 --- a/source/blender/blenkernel/intern/mesh_debug.cc +++ b/source/blender/blenkernel/intern/mesh_debug.cc @@ -52,7 +52,8 @@ char *BKE_mesh_debug_info(const Mesh *me) BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly); BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only); - BLI_dynstr_appendf(dynstr, " 'runtime.is_original': %d,\n", me->runtime.is_original); + BLI_dynstr_appendf( + dynstr, " 'runtime.is_original_bmesh': %d,\n", me->runtime.is_original_bmesh); BLI_dynstr_append(dynstr, " 'vert_layers': (\n"); CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr); diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index f6c2a8066fb..19594282b3f 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -885,7 +885,8 @@ void BKE_mesh_legacy_bevel_weight_from_layers(Mesh *mesh) { using namespace blender; MutableSpan<MVert> vertices(mesh->mvert, mesh->totvert); - if (const float *weights = (const float *)CustomData_get_layer(&mesh->vdata, CD_BWEIGHT)) { + if (const float *weights = static_cast<const float *>( + CustomData_get_layer(&mesh->vdata, CD_BWEIGHT))) { mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; for (const int i : vertices.index_range()) { vertices[i].bweight = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f; @@ -898,7 +899,8 @@ void BKE_mesh_legacy_bevel_weight_from_layers(Mesh *mesh) } } MutableSpan<MEdge> edges(mesh->medge, mesh->totedge); - if (const float *weights = (const float *)CustomData_get_layer(&mesh->edata, CD_BWEIGHT)) { + if (const float *weights = static_cast<const float *>( + CustomData_get_layer(&mesh->edata, CD_BWEIGHT))) { mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; for (const int i : edges.index_range()) { edges[i].bweight = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f; @@ -917,8 +919,8 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh) using namespace blender; const Span<MVert> vertices(mesh->mvert, mesh->totvert); if (mesh->cd_flag & ME_CDFLAG_VERT_BWEIGHT) { - float *weights = (float *)CustomData_add_layer( - &mesh->vdata, CD_BWEIGHT, CD_DEFAULT, nullptr, vertices.size()); + float *weights = static_cast<float *>( + CustomData_add_layer(&mesh->vdata, CD_BWEIGHT, CD_DEFAULT, nullptr, vertices.size())); for (const int i : vertices.index_range()) { weights[i] = vertices[i].bweight / 255.0f; } @@ -926,8 +928,8 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh) const Span<MEdge> edges(mesh->medge, mesh->totedge); if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) { - float *weights = (float *)CustomData_add_layer( - &mesh->edata, CD_BWEIGHT, CD_DEFAULT, nullptr, edges.size()); + float *weights = static_cast<float *>( + CustomData_add_layer(&mesh->edata, CD_BWEIGHT, CD_DEFAULT, nullptr, edges.size())); for (const int i : edges.index_range()) { weights[i] = edges[i].bweight / 255.0f; } diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index 0b61b876abe..989cd5f1df1 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -61,7 +61,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, } /* Use edit-mesh directly where possible. */ - me->runtime.is_original = true; + me->runtime.is_original_bmesh = true; me->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(em)); me->edit_mesh->is_shallow_copy = true; @@ -133,7 +133,7 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me) EditMeshData *edit_data = me->runtime.edit_data; if (edit_data->vertexCos) { BKE_mesh_vert_coords_apply(me, edit_data->vertexCos); - me->runtime.is_original = false; + me->runtime.is_original_bmesh = false; } break; } diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 019ab114b83..58084226b00 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -94,6 +94,9 @@ static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, if (node.is_undefined()) { return InputSocketFieldType::None; } + if (node.bnode()->type == NODE_CUSTOM) { + return InputSocketFieldType::None; + } const NodeDeclaration *node_decl = node.declaration(); @@ -131,6 +134,9 @@ static OutputFieldDependency get_interface_output_field_dependency(const NodeRef if (node.is_undefined()) { return OutputFieldDependency::ForDataSource(); } + if (node.bnode()->type == NODE_CUSTOM) { + return OutputFieldDependency::ForDataSource(); + } const NodeDeclaration *node_decl = node.declaration(); @@ -1267,7 +1273,7 @@ class NodeTreeMainUpdater { } /* Check if a used node group has an animated image. */ - for (const NodeRef *group_node : tree_ref.nodes_by_type("NodeGroup")) { + for (const NodeRef *group_node : tree_ref.nodes_by_type("ShaderNodeGroup")) { const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id); if (group != nullptr) { ntree.runtime->runtime_flag |= group->runtime->runtime_flag; diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 62ebb45b0ed..2a85811e2e8 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -449,7 +449,7 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) if (object->soft->effector_weights) { BKE_LIB_FOREACHID_PROCESS_IDSUPER( - data, object->soft->effector_weights->group, IDWALK_CB_NOP); + data, object->soft->effector_weights->group, IDWALK_CB_USER); } } } diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index cc3a8b5bb0e..228bc682ddd 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -201,7 +201,7 @@ static DupliObject *make_dupli( /* Meta-balls never draw in duplis, they are instead merged into one by the basis * meta-ball outside of the group. this does mean that if that meta-ball is not in the * scene, they will not show up at all, limitation that should be solved once. */ - if (ob->type == OB_MBALL) { + if (object_data && GS(object_data->name) == ID_MB) { dob->no_draw = true; } @@ -1563,6 +1563,13 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) return nullptr; } + /* Metaball objects can't create instances, but the dupli system is used to "instance" their + * evaluated mesh to render engines. We need to exit early to avoid recursively instancing the + * evaluated metaball mesh on metaball instances that already contribute to the basis. */ + if (ctx->object->type == OB_MBALL && ctx->level > 0) { + return nullptr; + } + /* Should the dupli's be generated for this object? - Respect restrict flags. */ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (visibility_flag & OB_HIDE_RENDER) : (visibility_flag & OB_HIDE_VIEWPORT)) { diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 99c4d92d284..5656a9f6c92 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -110,7 +110,6 @@ void BKE_object_eval_constraints(Depsgraph *depsgraph, Scene *scene, Object *ob) * - post (i.e. BKE_constraints_clear_evalob) * * Not sure why, this is from Joshua - sergey - * */ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime); @@ -169,7 +168,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o break; case OB_MBALL: - BKE_displist_make_mball(depsgraph, scene, ob); + BKE_mball_data_update(depsgraph, scene, ob); break; case OB_CURVES_LEGACY: @@ -293,9 +292,15 @@ void BKE_object_batch_cache_dirty_tag(Object *ob) case OB_CURVES_LEGACY: BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL); break; - case OB_MBALL: - BKE_mball_batch_cache_dirty_tag((struct MetaBall *)ob->data, BKE_MBALL_BATCH_DIRTY_ALL); + case OB_MBALL: { + /* This function is currently called on original objects, so to properly + * clear the actual displayed geometry, we have to tag the evaluated mesh. */ + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(ob); + if (mesh) { + BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL); + } break; + } case OB_GPENCIL: BKE_gpencil_batch_cache_dirty_tag((struct bGPdata *)ob->data); break; diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c deleted file mode 100644 index 09e2baf2be1..00000000000 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - * - * Tree hash for the outliner space. - */ - -#include <stdlib.h> -#include <string.h> - -#include "BLI_ghash.h" -#include "BLI_mempool.h" -#include "BLI_utildefines.h" - -#include "DNA_outliner_types.h" - -#include "BKE_outliner_treehash.h" - -#include "MEM_guardedalloc.h" - -typedef struct TseGroup { - TreeStoreElem **elems; - /* Index of last used #TreeStoreElem item, to speed up search for another one. */ - int lastused; - /* Counter used to reduce the amount of 'rests' of `lastused` index, otherwise search for unused - * item is exponential and becomes critically slow when there are a lot of items in the group. */ - int lastused_reset_count; - /* Number of items currently in use. */ - int size; - /* Number of items currently allocated. */ - int allocated; -} TseGroup; - -/* Only allow reset of #TseGroup.lastused counter to 0 once every 1k search. */ -#define TSEGROUP_LASTUSED_RESET_VALUE 10000 - -/* Allocate structure for TreeStoreElements; - * Most of elements in treestore have no duplicates, - * so there is no need to preallocate memory for more than one pointer */ -static TseGroup *tse_group_create(void) -{ - TseGroup *tse_group = MEM_mallocN(sizeof(TseGroup), "TseGroup"); - tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems"); - tse_group->size = 0; - tse_group->allocated = 1; - tse_group->lastused = 0; - return tse_group; -} - -static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem) -{ - if (UNLIKELY(tse_group->size == tse_group->allocated)) { - tse_group->allocated *= 2; - tse_group->elems = MEM_reallocN(tse_group->elems, - sizeof(TreeStoreElem *) * tse_group->allocated); - } - tse_group->elems[tse_group->size] = elem; - tse_group->lastused = tse_group->size; - tse_group->size++; -} - -static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem) -{ - int min_allocated = MAX2(1, tse_group->allocated / 2); - BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0); - - tse_group->size--; - BLI_assert(tse_group->size >= 0); - for (int i = 0; i < tse_group->size; i++) { - if (tse_group->elems[i] == elem) { - memcpy(tse_group->elems[i], - tse_group->elems[i + 1], - (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *)); - break; - } - } - - if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) { - tse_group->allocated = min_allocated; - tse_group->elems = MEM_reallocN(tse_group->elems, - sizeof(TreeStoreElem *) * tse_group->allocated); - } -} - -static void tse_group_free(TseGroup *tse_group) -{ - MEM_freeN(tse_group->elems); - MEM_freeN(tse_group); -} - -static unsigned int tse_hash(const void *ptr) -{ - const TreeStoreElem *tse = ptr; - union { - short h_pair[2]; - unsigned int u_int; - } hash; - - BLI_assert((tse->type != TSE_SOME_ID) || !tse->nr); - - hash.h_pair[0] = tse->type; - hash.h_pair[1] = tse->nr; - - hash.u_int ^= BLI_ghashutil_ptrhash(tse->id); - - return hash.u_int; -} - -static bool tse_cmp(const void *a, const void *b) -{ - const TreeStoreElem *tse_a = a; - const TreeStoreElem *tse_b = b; - return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id; -} - -static void fill_treehash(void *treehash, BLI_mempool *treestore) -{ - TreeStoreElem *tselem; - BLI_mempool_iter iter; - BLI_mempool_iternew(treestore, &iter); - - BLI_assert(treehash); - - while ((tselem = BLI_mempool_iterstep(&iter))) { - BKE_outliner_treehash_add_element(treehash, tselem); - } -} - -void *BKE_outliner_treehash_create_from_treestore(BLI_mempool *treestore) -{ - GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_len(treestore)); - fill_treehash(treehash, treestore); - return treehash; -} - -static void free_treehash_group(void *key) -{ - tse_group_free(key); -} - -void BKE_outliner_treehash_clear_used(void *treehash) -{ - GHashIterator gh_iter; - - GHASH_ITER (gh_iter, treehash) { - TseGroup *group = BLI_ghashIterator_getValue(&gh_iter); - group->lastused = 0; - group->lastused_reset_count = 0; - } -} - -void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore) -{ - BLI_assert(treehash); - - BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_len(treestore)); - fill_treehash(treehash, treestore); - return treehash; -} - -void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem) -{ - TseGroup *group; - void **val_p; - - if (!BLI_ghash_ensure_p(treehash, elem, &val_p)) { - *val_p = tse_group_create(); - } - group = *val_p; - tse_group_add_element(group, elem); -} - -void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem) -{ - TseGroup *group = BLI_ghash_lookup(treehash, elem); - - BLI_assert(group != NULL); - if (group->size <= 1) { - /* one element -> remove group completely */ - BLI_ghash_remove(treehash, elem, NULL, free_treehash_group); - } - else { - tse_group_remove_element(group, elem); - } -} - -static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id) -{ - TreeStoreElem tse_template; - tse_template.type = type; - tse_template.nr = (type == TSE_SOME_ID) ? 0 : nr; /* we're picky! :) */ - tse_template.id = id; - - BLI_assert(th); - - return BLI_ghash_lookup(th, &tse_template); -} - -TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, - short type, - short nr, - struct ID *id) -{ - TseGroup *group; - - BLI_assert(treehash); - - group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); - if (group) { - /* Find unused element, with optimization to start from previously - * found element assuming we do repeated lookups. */ - int size = group->size; - int offset = group->lastused; - - for (int i = 0; i < size; i++, offset++) { - /* Once at the end of the array of items, in most cases it just means that all items are - * used, so only check the whole array once every TSEGROUP_LASTUSED_RESET_VALUE times. */ - if (offset >= size) { - if (LIKELY(group->lastused_reset_count <= TSEGROUP_LASTUSED_RESET_VALUE)) { - group->lastused_reset_count++; - group->lastused = group->size - 1; - break; - } - group->lastused_reset_count = 0; - offset = 0; - } - - if (!group->elems[offset]->used) { - group->lastused = offset; - return group->elems[offset]; - } - } - } - return NULL; -} - -TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, - short type, - short nr, - struct ID *id) -{ - TseGroup *group; - - BLI_assert(treehash); - - group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); - return group ? group->elems[0] : NULL; -} - -void BKE_outliner_treehash_free(void *treehash) -{ - BLI_assert(treehash); - - BLI_ghash_free(treehash, NULL, free_treehash_group); -} diff --git a/source/blender/blenkernel/intern/outliner_treehash.cc b/source/blender/blenkernel/intern/outliner_treehash.cc new file mode 100644 index 00000000000..3f66f6bb745 --- /dev/null +++ b/source/blender/blenkernel/intern/outliner_treehash.cc @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + * + * Tree hash for the outliner space. + */ + +#include <stdlib.h> +#include <string.h> + +#include "BLI_mempool.h" +#include "BLI_utildefines.h" +#include "BLI_vector.hh" + +#include "DNA_outliner_types.h" + +#include "BKE_outliner_treehash.hh" + +#include "MEM_guardedalloc.h" + +namespace blender::bke::outliner::treehash { + +/* -------------------------------------------------------------------- */ +/** \name #TseGroup + * \{ */ + +class TseGroup { + public: + blender::Vector<TreeStoreElem *> elems; + /* Index of last used #TreeStoreElem item, to speed up search for another one. */ + int lastused = 0; + /* Counter used to reduce the amount of 'rests' of `lastused` index, otherwise search for unused + * item is exponential and becomes critically slow when there are a lot of items in the group. */ + int lastused_reset_count = -1; + + public: + void add_element(TreeStoreElem &elem); + void remove_element(TreeStoreElem &elem); +}; + +/* Only allow reset of #TseGroup.lastused counter to 0 once every 1k search. */ +#define TSEGROUP_LASTUSED_RESET_VALUE 10000 + +void TseGroup::add_element(TreeStoreElem &elem) +{ + const int64_t idx = elems.append_and_get_index(&elem); + lastused = idx; +} + +void TseGroup::remove_element(TreeStoreElem &elem) +{ + const int64_t idx = elems.first_index_of(&elem); + elems.remove(idx); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #TreeStoreElemKey + * \{ */ + +TreeStoreElemKey::TreeStoreElemKey(const TreeStoreElem &elem) + : id(elem.id), type(elem.type), nr(elem.nr) +{ +} + +TreeStoreElemKey::TreeStoreElemKey(ID *id, short type, short nr) : id(id), type(type), nr(nr) +{ +} + +uint64_t TreeStoreElemKey::hash() const +{ + return get_default_hash_3(id, type, nr); +} + +bool operator==(const TreeStoreElemKey &a, const TreeStoreElemKey &b) +{ + return (a.id == b.id) && (a.type == b.type) && (a.nr == b.nr); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #TreeHash + * \{ */ + +TreeHash::~TreeHash() = default; + +std::unique_ptr<TreeHash> TreeHash::create_from_treestore(BLI_mempool &treestore) +{ + /* Can't use `make_unique()` here because of private constructor. */ + std::unique_ptr<TreeHash> tree_hash{new TreeHash()}; + tree_hash->fill_treehash(treestore); + + return tree_hash; +} + +void TreeHash::fill_treehash(BLI_mempool &treestore) +{ + TreeStoreElem *tselem; + BLI_mempool_iter iter; + BLI_mempool_iternew(&treestore, &iter); + + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + add_element(*tselem); + } +} + +void TreeHash::clear_used() +{ + for (auto &group : elem_groups_.values()) { + group->lastused = 0; + group->lastused_reset_count = 0; + } +} + +void TreeHash::rebuild_from_treestore(BLI_mempool &treestore) +{ + elem_groups_.clear(); + fill_treehash(treestore); +} + +void TreeHash::add_element(TreeStoreElem &elem) +{ + std::unique_ptr<TseGroup> &group = elem_groups_.lookup_or_add_cb( + TreeStoreElemKey(elem), []() { return std::make_unique<TseGroup>(); }); + group->add_element(elem); +} + +void TreeHash::remove_element(TreeStoreElem &elem) +{ + TseGroup *group = lookup_group(elem); + BLI_assert(group != nullptr); + + if (group->elems.size() <= 1) { + /* One element -> remove group completely. */ + elem_groups_.remove(TreeStoreElemKey(elem)); + } + else { + group->remove_element(elem); + } +} + +TseGroup *TreeHash::lookup_group(const TreeStoreElemKey &key) const +{ + auto *group = elem_groups_.lookup_ptr(key); + if (group) { + return group->get(); + } + return nullptr; +} + +TseGroup *TreeHash::lookup_group(const TreeStoreElem &key_elem) const +{ + return lookup_group(TreeStoreElemKey(key_elem)); +} + +TseGroup *TreeHash::lookup_group(const short type, const short nr, ID *id) const +{ + TreeStoreElemKey key(id, type, nr); + if (type == TSE_SOME_ID) { + key.nr = 0; /* we're picky! :) */ + } + return lookup_group(key); +} + +TreeStoreElem *TreeHash::lookup_unused(const short type, const short nr, ID *id) const +{ + TseGroup *group = lookup_group(type, nr, id); + if (!group) { + return nullptr; + } + + /* Find unused element, with optimization to start from previously + * found element assuming we do repeated lookups. */ + const int size = group->elems.size(); + int offset = group->lastused; + + for (int i = 0; i < size; i++, offset++) { + /* Once at the end of the array of items, in most cases it just means that all items are + * used, so only check the whole array once every TSEGROUP_LASTUSED_RESET_VALUE times. */ + if (offset >= size) { + if (LIKELY(group->lastused_reset_count <= TSEGROUP_LASTUSED_RESET_VALUE)) { + group->lastused_reset_count++; + group->lastused = group->elems.size() - 1; + break; + } + group->lastused_reset_count = 0; + offset = 0; + } + + if (!group->elems[offset]->used) { + group->lastused = offset; + return group->elems[offset]; + } + } + return nullptr; +} + +TreeStoreElem *TreeHash::lookup_any(const short type, const short nr, ID *id) const +{ + const TseGroup *group = lookup_group(type, nr, id); + return group ? group->elems[0] : nullptr; +} + +/** \} */ + +} // namespace blender::bke::outliner::treehash diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.cc index 922ea45703d..8c3f3d7bedc 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.cc @@ -5,8 +5,8 @@ * \ingroup bke */ -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -30,6 +30,7 @@ #include "BLT_translation.h" #include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_brush.h" #include "BKE_ccg.h" #include "BKE_colortools.h" @@ -95,13 +96,10 @@ static void palette_blend_write(BlendWriter *writer, ID *id, const void *id_addr { Palette *palette = (Palette *)id; - PaletteColor *color; BLO_write_id_struct(writer, Palette, id_address, &palette->id); BKE_id_blend_write(writer, &palette->id); - for (color = palette->colors.first; color; color = color->next) { - BLO_write_struct(writer, PaletteColor, color); - } + BLO_write_struct_list(writer, PaletteColor, &palette->colors); } static void palette_blend_read_data(BlendDataReader *reader, ID *id) @@ -116,38 +114,38 @@ static void palette_undo_preserve(BlendLibReader *UNUSED(reader), ID *id_new, ID /* NOTE: We do not care about potential internal references to self here, Palette has none. */ /* NOTE: We do not swap IDProperties, as dealing with potential ID pointers in those would be * fairly delicate. */ - BKE_lib_id_swap(NULL, id_new, id_old); + BKE_lib_id_swap(nullptr, id_new, id_old); SWAP(IDProperty *, id_new->properties, id_old->properties); } IDTypeInfo IDType_ID_PAL = { - .id_code = ID_PAL, - .id_filter = FILTER_ID_PAL, - .main_listbase_index = INDEX_ID_PAL, - .struct_size = sizeof(Palette), - .name = "Palette", - .name_plural = "palettes", - .translation_context = BLT_I18NCONTEXT_ID_PALETTE, - .flags = IDTYPE_FLAGS_NO_ANIMDATA, - .asset_type_info = NULL, - - .init_data = palette_init_data, - .copy_data = palette_copy_data, - .free_data = palette_free_data, - .make_local = NULL, - .foreach_id = NULL, - .foreach_cache = NULL, - .foreach_path = NULL, - .owner_get = NULL, - - .blend_write = palette_blend_write, - .blend_read_data = palette_blend_read_data, - .blend_read_lib = NULL, - .blend_read_expand = NULL, - - .blend_read_undo_preserve = palette_undo_preserve, - - .lib_override_apply_post = NULL, + /* id_code */ ID_PAL, + /* id_filter */ FILTER_ID_PAL, + /* main_listbase_index */ INDEX_ID_PAL, + /* struct_size */ sizeof(Palette), + /* name */ "Palette", + /* name_plural */ "palettes", + /* translation_context */ BLT_I18NCONTEXT_ID_PALETTE, + /* flags */ IDTYPE_FLAGS_NO_ANIMDATA, + /* asset_type_info */ nullptr, + + /* init_data */ palette_init_data, + /* copy_data */ palette_copy_data, + /* free_data */ palette_free_data, + /* make_local */ nullptr, + /* foreach_id */ nullptr, + /* foreach_cache */ nullptr, + /* foreach_path */ nullptr, + /* owner_get */ nullptr, + + /* blend_write */ palette_blend_write, + /* blend_read_data */ palette_blend_read_data, + /* blend_read_lib */ nullptr, + /* blend_read_expand */ nullptr, + + /* blend_read_undo_preserve */ palette_undo_preserve, + + /* lib_override_apply_post */ nullptr, }; static void paint_curve_copy_data(Main *UNUSED(bmain), @@ -159,7 +157,8 @@ static void paint_curve_copy_data(Main *UNUSED(bmain), const PaintCurve *paint_curve_src = (const PaintCurve *)id_src; if (paint_curve_src->tot_points != 0) { - paint_curve_dst->points = MEM_dupallocN(paint_curve_src->points); + paint_curve_dst->points = static_cast<PaintCurvePoint *>( + MEM_dupallocN(paint_curve_src->points)); } } @@ -188,41 +187,41 @@ static void paint_curve_blend_read_data(BlendDataReader *reader, ID *id) } IDTypeInfo IDType_ID_PC = { - .id_code = ID_PC, - .id_filter = FILTER_ID_PC, - .main_listbase_index = INDEX_ID_PC, - .struct_size = sizeof(PaintCurve), - .name = "PaintCurve", - .name_plural = "paint_curves", - .translation_context = BLT_I18NCONTEXT_ID_PAINTCURVE, - .flags = IDTYPE_FLAGS_NO_ANIMDATA, - .asset_type_info = NULL, - - .init_data = NULL, - .copy_data = paint_curve_copy_data, - .free_data = paint_curve_free_data, - .make_local = NULL, - .foreach_id = NULL, - .foreach_cache = NULL, - .foreach_path = NULL, - .owner_get = NULL, - - .blend_write = paint_curve_blend_write, - .blend_read_data = paint_curve_blend_read_data, - .blend_read_lib = NULL, - .blend_read_expand = NULL, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, + /* id_code */ ID_PC, + /* id_filter */ FILTER_ID_PC, + /* main_listbase_index */ INDEX_ID_PC, + /* struct_size */ sizeof(PaintCurve), + /* name */ "PaintCurve", + /* name_plural */ "paint_curves", + /* translation_context */ BLT_I18NCONTEXT_ID_PAINTCURVE, + /* flags */ IDTYPE_FLAGS_NO_ANIMDATA, + /* asset_type_info */ nullptr, + + /* init_data */ nullptr, + /* copy_data */ paint_curve_copy_data, + /* free_data */ paint_curve_free_data, + /* make_local */ nullptr, + /* foreach_id */ nullptr, + /* foreach_cache */ nullptr, + /* foreach_path */ nullptr, + /* owner_get */ nullptr, + + /* blend_write */ paint_curve_blend_write, + /* blend_read_data */ paint_curve_blend_read_data, + /* blend_read_lib */ nullptr, + /* blend_read_expand */ nullptr, + + /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; -const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; -const char PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255}; -const char PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255}; -const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; +const uchar PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; +const uchar PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255}; +const uchar PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255}; +const uchar PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; -static ePaintOverlayControlFlags overlay_flags = 0; +static ePaintOverlayControlFlags overlay_flags = (ePaintOverlayControlFlags)0; void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex) { @@ -247,7 +246,7 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve) { Paint *p = BKE_paint_get_active(scene, view_layer); - if (p == NULL) { + if (p == nullptr) { return; } @@ -294,10 +293,10 @@ void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag) bool BKE_paint_ensure_from_paintmode(Scene *sce, ePaintMode mode) { ToolSettings *ts = sce->toolsettings; - Paint **paint_ptr = NULL; + Paint **paint_ptr = nullptr; /* Some paint modes don't store paint settings as pointer, for these this can be set and * referenced by paint_ptr. */ - Paint *paint_tmp = NULL; + Paint *paint_tmp = nullptr; switch (mode) { case PAINT_MODE_SCULPT: @@ -370,13 +369,13 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode) case PAINT_MODE_SCULPT_CURVES: return &ts->curves_sculpt->paint; case PAINT_MODE_INVALID: - return NULL; + return nullptr; default: return &ts->imapaint.paint; } } - return NULL; + return nullptr; } const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) @@ -406,7 +405,7 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) case PAINT_MODE_INVALID: break; } - return NULL; + return nullptr; } const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode) @@ -438,7 +437,7 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode) } /* Invalid paint mode. */ - return NULL; + return nullptr; } Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) @@ -467,7 +466,7 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) case OB_MODE_SCULPT_CURVES: return &ts->curves_sculpt->paint; case OB_MODE_EDIT: - return ts->uvsculpt ? &ts->uvsculpt->paint : NULL; + return ts->uvsculpt ? &ts->uvsculpt->paint : nullptr; default: break; } @@ -477,7 +476,7 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) return &ts->imapaint.paint; } - return NULL; + return nullptr; } Paint *BKE_paint_get_active_from_context(const bContext *C) @@ -488,13 +487,13 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) if (sce && view_layer) { ToolSettings *ts = sce->toolsettings; - Object *obact = NULL; + Object *obact = nullptr; if (view_layer->basact && view_layer->basact->object) { obact = view_layer->basact->object; } - if ((sima = CTX_wm_space_image(C)) != NULL) { + if ((sima = CTX_wm_space_image(C)) != nullptr) { if (obact && obact->mode == OB_MODE_EDIT) { if (sima->mode == SI_MODE_PAINT) { return &ts->imapaint.paint; @@ -512,7 +511,7 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) } } - return NULL; + return nullptr; } ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) @@ -522,13 +521,13 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) SpaceImage *sima; if (sce && view_layer) { - Object *obact = NULL; + Object *obact = nullptr; if (view_layer->basact && view_layer->basact->object) { obact = view_layer->basact->object; } - if ((sima = CTX_wm_space_image(C)) != NULL) { + if ((sima = CTX_wm_space_image(C)) != nullptr) { if (obact && obact->mode == OB_MODE_EDIT) { if (sima->mode == SI_MODE_PAINT) { return PAINT_MODE_TEXTURE_2D; @@ -568,7 +567,7 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) return PAINT_MODE_INVALID; } -ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref) +ePaintMode BKE_paintmode_get_from_tool(const bToolRef *tref) { if (tref->space_type == SPACE_VIEW3D) { switch (tref->mode) { @@ -611,7 +610,7 @@ Brush *BKE_paint_brush(Paint *p) const Brush *BKE_paint_brush_for_read(const Paint *p) { - return p ? p->brush : NULL; + return p ? p->brush : nullptr; } void BKE_paint_brush_set(Paint *p, Brush *br) @@ -704,16 +703,13 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode) PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) { - PaintCurve *pc; - - pc = BKE_id_new(bmain, ID_PC, name); - + PaintCurve *pc = static_cast<PaintCurve *>(BKE_id_new(bmain, ID_PC, name)); return pc; } Palette *BKE_paint_palette(Paint *p) { - return p ? p->palette : NULL; + return p ? p->palette : nullptr; } void BKE_paint_palette_set(Paint *p, Palette *palette) @@ -763,18 +759,18 @@ void BKE_palette_clear(Palette *palette) Palette *BKE_palette_add(Main *bmain, const char *name) { - Palette *palette = BKE_id_new(bmain, ID_PAL, name); + Palette *palette = static_cast<Palette *>(BKE_id_new(bmain, ID_PAL, name)); return palette; } PaletteColor *BKE_palette_color_add(Palette *palette) { - PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color"); + PaletteColor *color = MEM_cnew<PaletteColor>(__func__); BLI_addtail(&palette->colors, color); return color; } -bool BKE_palette_is_empty(const struct Palette *palette) +bool BKE_palette_is_empty(const Palette *palette) { return BLI_listbase_is_empty(&palette->colors); } @@ -782,7 +778,8 @@ bool BKE_palette_is_empty(const struct Palette *palette) /* helper function to sort using qsort */ static int palettecolor_compare_hsv(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); /* Hue */ if (ps1->h > ps2->h) { @@ -814,7 +811,8 @@ static int palettecolor_compare_hsv(const void *a1, const void *a2) /* helper function to sort using qsort */ static int palettecolor_compare_svh(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); /* Saturation. */ if (ps1->s > ps2->s) { @@ -845,7 +843,8 @@ static int palettecolor_compare_svh(const void *a1, const void *a2) static int palettecolor_compare_vhs(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); /* Value. */ if (1.0f - ps1->v > 1.0f - ps2->v) { @@ -876,7 +875,8 @@ static int palettecolor_compare_vhs(const void *a1, const void *a2) static int palettecolor_compare_luminance(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); float lumi1 = (ps1->rgb[0] + ps1->rgb[1] + ps1->rgb[2]) / 3.0f; float lumi2 = (ps2->rgb[0] + ps2->rgb[1] + ps2->rgb[2]) / 3.0f; @@ -917,14 +917,15 @@ void BKE_palette_sort_luminance(tPaletteColorHSV *color_array, const int totcol) bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, const bool linear) { - tPaletteColorHSV *color_array = NULL; - tPaletteColorHSV *col_elm = NULL; + tPaletteColorHSV *color_array = nullptr; + tPaletteColorHSV *col_elm = nullptr; bool done = false; const int totpal = BLI_ghash_len(color_table); if (totpal > 0) { - color_array = MEM_calloc_arrayN(totpal, sizeof(tPaletteColorHSV), __func__); + color_array = static_cast<tPaletteColorHSV *>( + MEM_calloc_arrayN(totpal, sizeof(tPaletteColorHSV), __func__)); /* Put all colors in an array. */ GHashIterator gh_iter; int t = 0; @@ -979,14 +980,14 @@ bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, co bool BKE_paint_select_face_test(Object *ob) { - return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) && + return ((ob != nullptr) && (ob->type == OB_MESH) && (ob->data != nullptr) && (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))); } bool BKE_paint_select_vert_test(Object *ob) { - return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) && + return ((ob != nullptr) && (ob->type == OB_MESH) && (ob->data != nullptr) && (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_VERT_SEL) && (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT)); } @@ -998,14 +999,14 @@ bool BKE_paint_select_elem_test(Object *ob) bool BKE_paint_always_hide_test(Object *ob) { - return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) && + return ((ob != nullptr) && (ob->type == OB_MESH) && (ob->data != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT)); } void BKE_paint_cavity_curve_preset(Paint *p, int preset) { - CurveMapping *cumap = NULL; - CurveMap *cuma = NULL; + CurveMapping *cumap = nullptr; + CurveMap *cuma = nullptr; if (!p->cavity_curve) { p->cavity_curve = BKE_curvemapping_add(1, 0, 0, 1, 1); @@ -1035,13 +1036,13 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode) return OB_MODE_EDIT; case PAINT_MODE_INVALID: default: - return 0; + return OB_MODE_OBJECT; } } -bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) +bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint) { - Paint *paint = NULL; + Paint *paint = nullptr; if (*r_paint) { /* Tool offset should never be 0 for initialized paint settings, so it's a reliable way to * check if already initialized. */ @@ -1053,7 +1054,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) } else { BLI_assert(ELEM(*r_paint, - /* Cast is annoying, but prevent NULL-pointer access. */ + /* Cast is annoying, but prevent nullptr-pointer access. */ (Paint *)ts->gp_paint, (Paint *)ts->gp_vertexpaint, (Paint *)ts->gp_sculptpaint, @@ -1065,7 +1066,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) (Paint *)ts->curves_sculpt, (Paint *)&ts->imapaint)); #ifdef DEBUG - struct Paint paint_test = **r_paint; + Paint paint_test = **r_paint; BKE_paint_runtime_init(ts, *r_paint); /* Swap so debug doesn't hide errors when release fails. */ SWAP(Paint, **r_paint, paint_test); @@ -1077,11 +1078,11 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) } if (((VPaint **)r_paint == &ts->vpaint) || ((VPaint **)r_paint == &ts->wpaint)) { - VPaint *data = MEM_callocN(sizeof(*data), __func__); + VPaint *data = MEM_cnew<VPaint>(__func__); paint = &data->paint; } else if ((Sculpt **)r_paint == &ts->sculpt) { - Sculpt *data = MEM_callocN(sizeof(*data), __func__); + Sculpt *data = MEM_cnew<Sculpt>(__func__); paint = &data->paint; /* Turn on X plane mirror symmetry by default */ @@ -1091,27 +1092,27 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; } else if ((GpPaint **)r_paint == &ts->gp_paint) { - GpPaint *data = MEM_callocN(sizeof(*data), __func__); + GpPaint *data = MEM_cnew<GpPaint>(__func__); paint = &data->paint; } else if ((GpVertexPaint **)r_paint == &ts->gp_vertexpaint) { - GpVertexPaint *data = MEM_callocN(sizeof(*data), __func__); + GpVertexPaint *data = MEM_cnew<GpVertexPaint>(__func__); paint = &data->paint; } else if ((GpSculptPaint **)r_paint == &ts->gp_sculptpaint) { - GpSculptPaint *data = MEM_callocN(sizeof(*data), __func__); + GpSculptPaint *data = MEM_cnew<GpSculptPaint>(__func__); paint = &data->paint; } else if ((GpWeightPaint **)r_paint == &ts->gp_weightpaint) { - GpWeightPaint *data = MEM_callocN(sizeof(*data), __func__); + GpWeightPaint *data = MEM_cnew<GpWeightPaint>(__func__); paint = &data->paint; } else if ((UvSculpt **)r_paint == &ts->uvsculpt) { - UvSculpt *data = MEM_callocN(sizeof(*data), __func__); + UvSculpt *data = MEM_cnew<UvSculpt>(__func__); paint = &data->paint; } else if ((CurvesSculpt **)r_paint == &ts->curves_sculpt) { - CurvesSculpt *data = MEM_callocN(sizeof(*data), __func__); + CurvesSculpt *data = MEM_cnew<CurvesSculpt>(__func__); paint = &data->paint; } else if (*r_paint == &ts->imapaint.paint) { @@ -1127,7 +1128,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) return false; } -void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) +void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const uchar col[3]) { UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings; Paint *paint = BKE_paint_get_active_from_paintmode(sce, mode); @@ -1137,7 +1138,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) /* If there's no brush, create one */ if (PAINT_MODE_HAS_BRUSH(mode)) { Brush *brush = BKE_paint_brush(paint); - if (brush == NULL) { + if (brush == nullptr) { eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode); brush = BKE_brush_first_search(bmain, ob_mode); if (!brush) { @@ -1148,7 +1149,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) } } - memcpy(paint->paint_cursor_col, col, 3); + copy_v3_v3_uchar(paint->paint_cursor_col, col); paint->paint_cursor_col[3] = 128; ups->last_stroke_valid = false; zero_v3(ups->average_stroke_accum); @@ -1168,12 +1169,12 @@ void BKE_paint_copy(Paint *src, Paint *tar, const int flag) { tar->brush = src->brush; tar->cavity_curve = BKE_curvemapping_copy(src->cavity_curve); - tar->tool_slots = MEM_dupallocN(src->tool_slots); + tar->tool_slots = static_cast<PaintToolSlot *>(MEM_dupallocN(src->tool_slots)); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)tar->brush); id_us_plus((ID *)tar->palette); - if (src->tool_slots != NULL) { + if (src->tool_slots != nullptr) { for (int i = 0; i < tar->tool_slots_len; i++) { id_us_plus((ID *)tar->tool_slots[i].brush); } @@ -1221,7 +1222,7 @@ void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Pain const size_t expected_size = sizeof(PaintToolSlot) * p->tool_slots_len; if (p->tool_slots && MEM_allocN_len(p->tool_slots) < expected_size) { MEM_freeN(p->tool_slots); - p->tool_slots = MEM_callocN(expected_size, "PaintToolSlot"); + p->tool_slots = static_cast<PaintToolSlot *>(MEM_callocN(expected_size, "PaintToolSlot")); } BKE_paint_runtime_init(scene->toolsettings, p); @@ -1232,12 +1233,12 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p) if (p) { BLO_read_id_address(reader, sce->id.lib, &p->brush); for (int i = 0; i < p->tool_slots_len; i++) { - if (p->tool_slots[i].brush != NULL) { + if (p->tool_slots[i].brush != nullptr) { BLO_read_id_address(reader, sce->id.lib, &p->tool_slots[i].brush); } } BLO_read_id_address(reader, sce->id.lib, &p->palette); - p->paint_cursor = NULL; + p->paint_cursor = nullptr; BKE_paint_runtime_init(sce->toolsettings, p); } @@ -1348,9 +1349,9 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss) MEM_SAFE_FREE(ss->deform_imats); } -void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) +void BKE_sculptsession_free_vwpaint_data(SculptSession *ss) { - struct SculptVertexPaintGeomMap *gmap = NULL; + SculptVertexPaintGeomMap *gmap = nullptr; if (ss->mode_type == OB_MODE_VERTEX_PAINT) { gmap = &ss->mode.vpaint.gmap; } @@ -1361,7 +1362,7 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) if (ss->mode.wpaint.dvert_prev) { BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert); MEM_freeN(ss->mode.wpaint.dvert_prev); - ss->mode.wpaint.dvert_prev = NULL; + ss->mode.wpaint.dvert_prev = nullptr; } } else { @@ -1390,12 +1391,9 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder) if (reorder) { BM_log_mesh_elems_reorder(ss->bm, ss->bm_log); } - BM_mesh_bm_to_me(NULL, - ss->bm, - ob->data, - (&(struct BMeshToMeshParams){ - .calc_object_remap = false, - })); + BMeshToMeshParams params{}; + params.calc_object_remap = false; + BM_mesh_bm_to_me(nullptr, ss->bm, static_cast<Mesh *>(ob->data), ¶ms); } } } @@ -1421,7 +1419,7 @@ static void sculptsession_free_pbvh(Object *object) if (ss->pbvh) { BKE_pbvh_free(ss->pbvh); - ss->pbvh = NULL; + ss->pbvh = nullptr; } MEM_SAFE_FREE(ss->pmap); @@ -1523,7 +1521,7 @@ void BKE_sculptsession_free(Object *ob) MEM_freeN(ss); - ob->sculpt = NULL; + ob->sculpt = nullptr; } } @@ -1535,18 +1533,18 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) if (ob->sculpt && ob->sculpt->bm) { /* can't combine multires and dynamic topology */ - return NULL; + return nullptr; } if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) { /* multires can't work without displacement layer */ - return NULL; + return nullptr; } /* Weight paint operates on original vertices, and needs to treat multires as regular modifier * to make it so that PBVH vertices are at the multires surface. */ if ((ob->mode & OB_MODE_SCULPT) == 0) { - return NULL; + return nullptr; } for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); md; md = md->next) { @@ -1561,11 +1559,11 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) return mmd; } - return NULL; + return nullptr; } } - return NULL; + return nullptr; } /* Checks if there are any supported deformation modifiers active */ @@ -1588,7 +1586,7 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) /* exception for shape keys because we can edit those */ for (; md; md = md->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type)); if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } @@ -1641,7 +1639,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->scene = scene; if (need_mask) { - if (mmd == NULL) { + if (mmd == nullptr) { BLI_assert(CustomData_has_layer(&me->vdata, CD_PAINT_MASK)); } else { @@ -1649,7 +1647,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, } } - ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; + ss->shapekey_active = (mmd == nullptr) ? BKE_keyblock_from_object(ob) : nullptr; /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path, * so no extra checks is needed here. */ @@ -1675,40 +1673,40 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->mpoly = me->mpoly; ss->mloop = me->mloop; ss->multires.active = false; - ss->multires.modifier = NULL; + ss->multires.modifier = nullptr; ss->multires.level = 0; - ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); + ss->vmask = static_cast<float *>(CustomData_get_layer(&me->vdata, CD_PAINT_MASK)); CustomDataLayer *layer; eAttrDomain domain; if (BKE_pbvh_get_color_layer(me, &layer, &domain)) { if (layer->type == CD_PROP_COLOR) { - ss->vcol = layer->data; + ss->vcol = static_cast<MPropCol *>(layer->data); } else { - ss->mcol = layer->data; + ss->mcol = static_cast<MLoopCol *>(layer->data); } ss->vcol_domain = domain; - ss->vcol_type = layer->type; + ss->vcol_type = static_cast<eCustomDataType>(layer->type); } else { - ss->vcol = NULL; - ss->mcol = NULL; + ss->vcol = nullptr; + ss->mcol = nullptr; - ss->vcol_type = -1; - ss->vcol_domain = ATTR_DOMAIN_NUM; + ss->vcol_type = (eCustomDataType)-1; + ss->vcol_domain = ATTR_DOMAIN_POINT; } } /* Sculpt Face Sets. */ if (use_face_sets) { BLI_assert(CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)); - ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); + ss->face_sets = static_cast<int *>(CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS)); } else { - ss->face_sets = NULL; + ss->face_sets = nullptr; } ss->subdiv_ccg = me_eval->runtime.subdiv_ccg; @@ -1742,7 +1740,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->orig_cos = (ss->shapekey_active) ? BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active) : - BKE_mesh_vert_coords_alloc(me, NULL); + BKE_mesh_vert_coords_alloc(me, nullptr); BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos); BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert); @@ -1756,14 +1754,14 @@ static void sculpt_update_object(Depsgraph *depsgraph, BKE_sculptsession_free_deformMats(ss); } - if (ss->shapekey_active != NULL && ss->deform_cos == NULL) { + if (ss->shapekey_active != nullptr && ss->deform_cos == nullptr) { ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); } /* if pbvh is deformed, key block is already applied to it */ if (ss->shapekey_active) { bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh); - if (!pbvh_deformed || ss->deform_cos == NULL) { + if (!pbvh_deformed || ss->deform_cos == nullptr) { float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); if (vertCos) { @@ -1771,7 +1769,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, /* apply shape keys coordinates to PBVH */ BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, me->totvert); } - if (ss->deform_cos == NULL) { + if (ss->deform_cos == nullptr) { ss->deform_cos = vertCos; } if (vertCos != ss->deform_cos) { @@ -1790,7 +1788,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, */ if (U.experimental.use_sculpt_texture_paint && ss->pbvh) { char *paint_canvas_key = BKE_paint_canvas_key_get(&scene->toolsettings->paint_mode, ob); - if (ss->last_paint_canvas_key == NULL || + if (ss->last_paint_canvas_key == nullptr || !STREQ(paint_canvas_key, ss->last_paint_canvas_key)) { MEM_SAFE_FREE(ss->last_paint_canvas_key); ss->last_paint_canvas_key = paint_canvas_key; @@ -1815,8 +1813,8 @@ static void sculpt_face_sets_ensure(Mesh *mesh) return; } - int *new_face_sets = CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, mesh->totpoly); + int *new_face_sets = static_cast<int *>( + CustomData_add_layer(&mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ @@ -1847,7 +1845,7 @@ void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval) PBVHNode **nodes; int n, totnode; - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode); for (n = 0; n < totnode; n++) { BKE_pbvh_node_mark_update(nodes[n]); @@ -1875,11 +1873,11 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval) Object *ob_orig = DEG_get_original_object(ob_eval); Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); - BLI_assert(me_eval != NULL); + BLI_assert(me_eval != nullptr); sculpt_update_object(depsgraph, ob_orig, me_eval, false, false, false); } -void BKE_sculpt_color_layer_create_if_needed(struct Object *object) +void BKE_sculpt_color_layer_create_if_needed(Object *object) { Mesh *orig_me = BKE_object_get_original_mesh(object); @@ -1899,7 +1897,7 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object) return; } - CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert); + CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, orig_me->totvert); CustomDataLayer *layer = orig_me->vdata.layers + CustomData_get_layer_index(&orig_me->vdata, CD_PROP_COLOR); @@ -1920,18 +1918,18 @@ void BKE_sculpt_update_object_for_edit( Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig); Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); - BLI_assert(me_eval != NULL); + BLI_assert(me_eval != nullptr); sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, is_paint_tool); } int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) { - const float *paint_mask; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); int ret = 0; - paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); + const float *paint_mask = static_cast<const float *>( + CustomData_get_layer(&me->vdata, CD_PAINT_MASK)); /* if multires is active, create a grid paint mask layer if there * isn't one already */ @@ -1942,13 +1940,15 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) int gridarea = gridsize * gridsize; int i, j; - gmask = CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK, CD_CALLOC, NULL, me->totloop); + gmask = static_cast<GridPaintMask *>( + CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK, CD_CALLOC, nullptr, me->totloop)); for (i = 0; i < me->totloop; i++) { GridPaintMask *gpm = &gmask[i]; gpm->level = level; - gpm->data = MEM_callocN(sizeof(float) * gridarea, "GridPaintMask.data"); + gpm->data = static_cast<float *>( + MEM_callocN(sizeof(float) * gridarea, "GridPaintMask.data")); } /* if vertices already have mask, copy into multires data */ @@ -1984,14 +1984,14 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) /* create vertex paint mask layer if there isn't one already */ if (!paint_mask) { - CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, me->totvert); + CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, me->totvert); ret |= SCULPT_MASK_LAYER_CALC_VERT; } return ret; } -void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene) +void BKE_sculpt_toolsettings_data_ensure(Scene *scene) { BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->sculpt); @@ -2029,7 +2029,7 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc deformed |= object->sculpt->deform_modifiers_active; if (for_construction) { - deformed |= object->sculpt->shapekey_active != NULL; + deformed |= object->sculpt->shapekey_active != nullptr; } else { /* As in case with modifiers, we can't synchronize deformation made against @@ -2051,15 +2051,16 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { /* Make everything visible. */ - int *current_face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + int *current_face_sets = static_cast<int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); for (int i = 0; i < mesh->totpoly; i++) { current_face_sets[i] = abs(current_face_sets[i]); } } else { initialize_new_face_sets = true; - int *new_face_sets = CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, mesh->totpoly); + int *new_face_sets = static_cast<int *>(CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ @@ -2069,7 +2070,7 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) mesh->face_sets_color_default = face_sets_default_visible_id; } - int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + int *face_sets = static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); const bool *hide_poly = (const bool *)CustomData_get_layer_named( &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); @@ -2094,26 +2095,31 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) { - const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + using namespace blender::bke; + const int *face_sets = static_cast<const int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); if (!face_sets) { return; } - bool *hide_poly = (bool *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly"); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh); + SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_poly", ATTR_DOMAIN_FACE); if (!hide_poly) { return; } - - for (int i = 0; i < mesh->totpoly; i++) { - hide_poly[i] = face_sets[i] < 0; + for (const int i : hide_poly.span.index_range()) { + hide_poly.span[i] = face_sets[i] < 0; } + hide_poly.finish(); BKE_mesh_flush_hidden_from_polys(mesh); } void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) { - const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + const int *face_sets = static_cast<const int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); if (!face_sets) { return; } @@ -2142,7 +2148,7 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv } } -void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg) +void BKE_sculpt_sync_face_set_visibility(Mesh *mesh, SubdivCCG *subdiv_ccg) { BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh); @@ -2158,9 +2164,10 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object) /* Copy the current mesh visibility to the Face Sets. */ BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); - if (object->sculpt != NULL) { + if (object->sculpt != nullptr) { /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */ - object->sculpt->face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + object->sculpt->face_sets = static_cast<int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); /* NOTE: In theory we could add that on the fly when required by sculpt code. * But this then requires proper update of depsgraph etc. For now we play safe, optimization is @@ -2209,11 +2216,12 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool PBVH *pbvh = BKE_pbvh_new(); BKE_pbvh_respect_hide_set(pbvh, respect_hide); - MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__); + MLoopTri *looptri = static_cast<MLoopTri *>( + MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__)); BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); - BKE_sculpt_sync_face_set_visibility(me, NULL); + BKE_sculpt_sync_face_set_visibility(me, nullptr); BKE_pbvh_build_mesh(pbvh, me, @@ -2231,7 +2239,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); const bool is_deformed = check_sculpt_object_deformed(ob, true); - if (is_deformed && me_eval_deform != NULL) { + if (is_deformed && me_eval_deform != nullptr) { int totvert; float(*v_cos)[3] = BKE_mesh_vert_coords_alloc(me_eval_deform, &totvert); BKE_pbvh_vert_coords_apply(pbvh, v_cos, totvert); @@ -2265,21 +2273,21 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) { - if (ob == NULL || ob->sculpt == NULL) { - return NULL; + if (ob == nullptr || ob->sculpt == nullptr) { + return nullptr; } const bool respect_hide = true; PBVH *pbvh = ob->sculpt->pbvh; - if (pbvh != NULL) { + if (pbvh != nullptr) { /* NOTE: It is possible that grids were re-allocated due to modifier * stack. Need to update those pointers. */ if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - Mesh *mesh_eval = object_eval->data; + Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; - if (subdiv_ccg != NULL) { + if (subdiv_ccg != nullptr) { BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg); } } @@ -2290,14 +2298,14 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) return pbvh; } - if (ob->sculpt->bm != NULL) { + if (ob->sculpt->bm != nullptr) { /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */ pbvh = build_pbvh_for_dynamic_topology(ob); } else { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - Mesh *mesh_eval = object_eval->data; - if (mesh_eval->runtime.subdiv_ccg != NULL) { + Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); + if (mesh_eval->runtime.subdiv_ccg != nullptr) { pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide); } else if (ob->type == OB_MESH) { @@ -2324,7 +2332,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg) bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d)) { SculptSession *ss = ob->sculpt; - if (ss == NULL || ss->pbvh == NULL || ss->mode_type != OB_MODE_SCULPT) { + if (ss == nullptr || ss->pbvh == nullptr || ss->mode_type != OB_MODE_SCULPT) { return false; } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 85a8d6c817f..9ccd6562649 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -171,7 +171,7 @@ static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data) } if (psett->effector_weights) { - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->effector_weights->group, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->effector_weights->group, IDWALK_CB_USER); } if (psett->pd) { @@ -3494,7 +3494,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re * initial tangent, but taking that in to account will allow * the possibility of flipping again. -jahka */ - mat3_to_quat_is_ok(cache[p]->rot, rotmat); + mat3_to_quat_legacy(cache[p]->rot, rotmat); } psys->totcached = totpart; @@ -3684,7 +3684,7 @@ static void psys_cache_edit_paths_iter(void *__restrict iter_data_v, * initial tangent, but taking that in to account will allow * the possibility of flipping again. -jahka */ - mat3_to_quat_is_ok(cache[iter]->rot, rotmat); + mat3_to_quat_legacy(cache[iter]->rot, rotmat); } } diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index 524ee31229b..a890812cfc4 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -158,10 +158,8 @@ static void do_kink_spiral(ParticleThreadContext *ctx, int start_index = 0, end_index = 0; float kink_base[3]; - if (ptex) { - kink_amp *= ptex->kink_amp; - kink_freq *= ptex->kink_freq; - } + kink_amp *= ptex->kink_amp; + kink_freq *= ptex->kink_freq; cut_time = (totkeys - 1) * ptex->length; zero_v3(spiral_start); @@ -405,7 +403,7 @@ void do_kink(ParticleKey *state, float obmat[4][4], int smooth_start) { - float kink[3] = {1.0f, 0.0f, 0.0f}, par_vec[3], q1[4] = {1.0f, 0.0f, 0.0f, 0.0f}; + float kink[3] = {1.0f, 0.0f, 0.0f}, par_vec[3]; float t, dt = 1.0f, result[3]; if (ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL)) { @@ -455,6 +453,7 @@ void do_kink(ParticleKey *state, switch (type) { case PART_KINK_CURL: { float curl_offset[3]; + float q1[4] = {1.0f, 0.0f, 0.0f, 0.0f}; /* rotate kink vector around strand tangent */ mul_v3_v3fl(curl_offset, kink, amplitude); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index e9bbcea241e..abecb9f8d9d 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -837,7 +837,7 @@ void psys_get_birth_coords( cross_v3_v3v3(mat[1], mat[2], mat[0]); /* apply rotation */ - mat3_to_quat_is_ok(q, mat); + mat3_to_quat_legacy(q, mat); copy_qt_qt(state->rot, q); } else { diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 4e6418942be..726c022ba2c 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1275,7 +1275,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDo if (!layer || !ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) { *r_layer = NULL; - *r_attr = ATTR_DOMAIN_NUM; + *r_attr = ATTR_DOMAIN_POINT; return false; } @@ -1283,7 +1283,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDo if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { *r_layer = NULL; - *r_attr = ATTR_DOMAIN_NUM; + *r_attr = ATTR_DOMAIN_POINT; return false; } @@ -1330,6 +1330,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, } if (node->flag & PBVH_UpdateDrawBuffers) { + node->debug_draw_gen++; + const int update_flags = pbvh_get_buffers_update_flags(pbvh); switch (pbvh->header.type) { case PBVH_GRIDS: @@ -2897,15 +2899,18 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, MEM_SAFE_FREE(nodes); } -void BKE_pbvh_draw_debug_cb( - PBVH *pbvh, - void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), - void *user_data) +void BKE_pbvh_draw_debug_cb(PBVH *pbvh, + void (*draw_fn)(PBVHNode *node, + void *user_data, + const float bmin[3], + const float bmax[3], + PBVHNodeFlags flag), + void *user_data) { for (int a = 0; a < pbvh->totnode; a++) { PBVHNode *node = &pbvh->nodes[a]; - draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag); + draw_fn(node, user_data, node->vb.bmin, node->vb.bmax, node->flag); } } @@ -3330,3 +3335,8 @@ void BKE_pbvh_ensure_node_loops(PBVH *pbvh) MEM_SAFE_FREE(visit); } + +int BKE_pbvh_debug_draw_gen_get(PBVHNode *node) +{ + return node->debug_draw_gen; +} diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 5babfd3acbe..3d67ab9ba6b 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -123,6 +123,11 @@ struct PBVHNode { /* Used to store the brush color during a stroke and composite it over the original color */ PBVHColorBufferNode color_buffer; PBVHPixelsNode pixels; + + /* Used to flash colors of updated node bounding boxes in + * debug draw mode (when G.debug_value / bpy.app.debug_value is 889). + */ + int debug_draw_gen; }; typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags; diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 821976f8e0e..e5fb61bfa2f 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1176,6 +1176,9 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) if (rbw->effector_weights) { rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)rbw->effector_weights->group); + } } if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)rbw_copy->group); @@ -1205,9 +1208,9 @@ void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw) void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) { - func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP); - func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP); - func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP); + func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_USER); + func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_USER); + func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_USER); if (rbw->objects) { int i; @@ -1424,7 +1427,7 @@ static bool rigidbody_add_object_to_scene(Main *bmain, Scene *scene, Object *ob) if (rbw->group == NULL) { rbw->group = BKE_collection_add(bmain, NULL, "RigidBodyWorld"); - id_fake_user_set(&rbw->group->id); + id_us_plus(&rbw->group->id); } /* Add object to rigid body group. */ @@ -1453,7 +1456,7 @@ static bool rigidbody_add_constraint_to_scene(Main *bmain, Scene *scene, Object if (rbw->constraints == NULL) { rbw->constraints = BKE_collection_add(bmain, NULL, "RigidBodyConstraints"); - id_fake_user_set(&rbw->constraints->id); + id_us_plus(&rbw->constraints->id); } /* Add object to rigid body group. */ diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 4d41471e1fb..0445db5aed0 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -2591,7 +2591,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on // DEG_debug_graph_relations_validate(depsgraph, bmain, scene); /* Flush editing data if needed. */ prepare_mesh_for_viewport_render(bmain, view_layer); - /* Update all objects: drivers, matrices, #DispList, etc. flags set + /* Update all objects: drivers, matrices, etc. flags set * by depsgraph or manual, no layer check here, gets correct flushed. */ DEG_evaluate_on_refresh(depsgraph); /* Update sound system. */ @@ -2666,7 +2666,7 @@ void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool cle BKE_image_editors_update_frame(bmain, scene->r.cfra); BKE_sound_set_cfra(scene->r.cfra); DEG_graph_relations_update(depsgraph); - /* Update all objects: drivers, matrices, #DispList, etc. flags set + /* Update all objects: drivers, matrices, etc. flags set * by depsgraph or manual, no layer check here, gets correct flushed. * * NOTE: Only update for new frame on first iteration. Second iteration is for ensuring user diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index c16e5ce5655..f1eba64e401 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -148,7 +148,6 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP); if (space_outliner->treestore != NULL) { TreeStoreElem *tselem; BLI_mempool_iter iter; @@ -1124,40 +1123,50 @@ static void write_uilist(BlendWriter *writer, uiList *ui_list) } } -static void write_space_outliner(BlendWriter *writer, SpaceOutliner *space_outliner) +static void write_space_outliner(BlendWriter *writer, const SpaceOutliner *space_outliner) { BLI_mempool *ts = space_outliner->treestore; if (ts) { - SpaceOutliner space_outliner_flat = *space_outliner; - - int elems = BLI_mempool_len(ts); + const int elems = BLI_mempool_len(ts); /* linearize mempool to array */ TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL; if (data) { - /* In this block we use the memory location of the treestore - * but _not_ its data, the addresses in this case are UUID's, - * since we can't rely on malloc giving us different values each time. + BLO_write_struct(writer, SpaceOutliner, space_outliner); + + /* To store #TreeStore (instead of the mempool), two unique memory addresses are needed, + * which can be used to identify the data on read: + * 1) One for the #TreeStore data itself. + * 2) One for the array of #TreeStoreElem's inside #TreeStore (#TreeStore.data). + * + * For 1) we just use the mempool's address (#SpaceOutliner::treestore). + * For 2) we don't have such a direct choice. We can't just use the array's address from + * above, since that may not be unique over all Outliners. So instead use an address relative + * to 1). */ - TreeStore ts_flat = {0}; + /* TODO the mempool could be moved to #SpaceOutliner_Runtime so that #SpaceOutliner could + * hold the #TreeStore directly. */ - /* we know the treestore is at least as big as a pointer, - * so offsetting works to give us a UUID. */ + /* Address relative to the tree-store, as noted above. */ void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *)); + /* There should be plenty of memory addresses within the mempool data that we can point into, + * just double-check we don't potentially end up with a memory address that another DNA + * struct might use. Assumes BLI_mempool uses the guarded allocator. */ + BLI_assert(MEM_allocN_len(ts) >= sizeof(void *) * 2); + TreeStore ts_flat = {0}; ts_flat.usedelem = elems; ts_flat.totelem = elems; ts_flat.data = data_addr; - BLO_write_struct(writer, SpaceOutliner, space_outliner); - BLO_write_struct_at_address(writer, TreeStore, ts, &ts_flat); BLO_write_struct_array_at_address(writer, TreeStoreElem, elems, data_addr, data); MEM_freeN(data); } else { + SpaceOutliner space_outliner_flat = *space_outliner; space_outliner_flat.treestore = NULL; BLO_write_struct_at_address(writer, SpaceOutliner, space_outliner, &space_outliner_flat); } @@ -1873,7 +1882,6 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - BLO_read_id_address(reader, NULL, &space_outliner->search_tse.id); if (space_outliner->treestore) { TreeStoreElem *tselem; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index f459b5a82ac..bb0e7a4dd6b 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -756,7 +756,7 @@ void BKE_sound_remove_scene_sound(Scene *scene, void *handle) AUD_Sequence_remove(scene->sound_scene, handle); } -void BKE_sound_mute_scene_sound(void *handle, char mute) +void BKE_sound_mute_scene_sound(void *handle, bool mute) { AUD_SequenceEntry_setMuted(handle, mute); } @@ -1346,7 +1346,7 @@ void *BKE_sound_add_scene_sound_defaults(Scene *UNUSED(scene), Sequence *UNUSED( void BKE_sound_remove_scene_sound(Scene *UNUSED(scene), void *UNUSED(handle)) { } -void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) +void BKE_sound_mute_scene_sound(void *UNUSED(handle), bool UNUSED(mute)) { } void BKE_sound_move_scene_sound(const Scene *UNUSED(scene), diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.cc index 22479f70433..fe6fd5f6052 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -11,7 +11,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_bitmap.h" #include "BLI_math_vector.h" @@ -29,7 +29,7 @@ /** \name Subdivision Context * \{ */ -typedef struct SubdivMeshContext { +struct SubdivMeshContext { const SubdivToMeshSettings *settings; const Mesh *coarse_mesh; Subdiv *subdiv; @@ -48,15 +48,15 @@ typedef struct SubdivMeshContext { /* Per-subdivided vertex counter of averaged values. */ int *accumulated_counters; bool have_displacement; -} SubdivMeshContext; +}; static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx) { Mesh *subdiv_mesh = ctx->subdiv_mesh; ctx->num_uv_layers = CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV); for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) { - ctx->uv_layers[layer_index] = CustomData_get_layer_n( - &subdiv_mesh->ldata, CD_MLOOPUV, layer_index); + ctx->uv_layers[layer_index] = static_cast<MLoopUV *>( + CustomData_get_layer_n(&subdiv_mesh->ldata, CD_MLOOPUV, layer_index)); } } @@ -64,15 +64,20 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx) { Mesh *subdiv_mesh = ctx->subdiv_mesh; /* Pointers to original indices layers. */ - ctx->vert_origindex = CustomData_get_layer(&subdiv_mesh->vdata, CD_ORIGINDEX); - ctx->edge_origindex = CustomData_get_layer(&subdiv_mesh->edata, CD_ORIGINDEX); - ctx->loop_origindex = CustomData_get_layer(&subdiv_mesh->ldata, CD_ORIGINDEX); - ctx->poly_origindex = CustomData_get_layer(&subdiv_mesh->pdata, CD_ORIGINDEX); + ctx->vert_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->vdata, CD_ORIGINDEX)); + ctx->edge_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->edata, CD_ORIGINDEX)); + ctx->loop_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->ldata, CD_ORIGINDEX)); + ctx->poly_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->pdata, CD_ORIGINDEX)); /* UV layers interpolation. */ subdiv_mesh_ctx_cache_uv_layers(ctx); /* Orco interpolation. */ - ctx->orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_ORCO); - ctx->cloth_orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_CLOTH_ORCO); + ctx->orco = static_cast<float(*)[3]>(CustomData_get_layer(&subdiv_mesh->vdata, CD_ORCO)); + ctx->cloth_orco = static_cast<float(*)[3]>( + CustomData_get_layer(&subdiv_mesh->vdata, CD_CLOTH_ORCO)); } static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices) @@ -80,8 +85,8 @@ static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vert if (!ctx->have_displacement) { return; } - ctx->accumulated_counters = MEM_calloc_arrayN( - num_vertices, sizeof(*ctx->accumulated_counters), "subdiv accumulated counters"); + ctx->accumulated_counters = static_cast<int *>( + MEM_calloc_arrayN(num_vertices, sizeof(*ctx->accumulated_counters), __func__)); } static void subdiv_mesh_context_free(SubdivMeshContext *ctx) @@ -95,7 +100,7 @@ static void subdiv_mesh_context_free(SubdivMeshContext *ctx) /** \name Loop custom data copy helpers * \{ */ -typedef struct LoopsOfPtex { +struct LoopsOfPtex { /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */ const MLoop *first_loop; /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */ @@ -103,7 +108,7 @@ typedef struct LoopsOfPtex { /* For quad coarse faces only. */ const MLoop *second_loop; const MLoop *third_loop; -} LoopsOfPtex; +}; static void loops_of_ptex_get(const SubdivMeshContext *ctx, LoopsOfPtex *loops_of_ptex, @@ -126,8 +131,8 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx, loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2; } else { - loops_of_ptex->second_loop = NULL; - loops_of_ptex->third_loop = NULL; + loops_of_ptex->second_loop = nullptr; + loops_of_ptex->third_loop = nullptr; } } @@ -140,7 +145,7 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx, /* TODO(sergey): Somehow de-duplicate with loops storage, without too much * exception cases all over the code. */ -typedef struct VerticesForInterpolation { +struct VerticesForInterpolation { /* This field points to a vertex data which is to be used for interpolation. * The idea is to avoid unnecessary allocations for regular faces, where * we can simply use corner vertices. */ @@ -159,7 +164,7 @@ typedef struct VerticesForInterpolation { /* Indices within vertex_data to interpolate for. The indices are aligned * with uv coordinates in a similar way as indices in loop_data_storage. */ int vertex_indices[4]; -} VerticesForInterpolation; +}; static void vertex_interpolation_init(const SubdivMeshContext *ctx, VerticesForInterpolation *vertex_interpolation, @@ -192,17 +197,17 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, /* Interpolate center of poly right away, it stays unchanged for all * ptex faces. */ const float weight = 1.0f / (float)coarse_poly->totloop; - float *weights = BLI_array_alloca(weights, coarse_poly->totloop); - int *indices = BLI_array_alloca(indices, coarse_poly->totloop); + blender::Array<float, 32> weights(coarse_poly->totloop); + blender::Array<int, 32> indices(coarse_poly->totloop); for (int i = 0; i < coarse_poly->totloop; i++) { weights[i] = weight; indices[i] = coarse_mloop[coarse_poly->loopstart + i].v; } CustomData_interp(&coarse_mesh->vdata, &vertex_interpolation->vertex_data_storage, - indices, - weights, - NULL, + indices.data(), + weights.data(), + nullptr, coarse_poly->totloop, 2); } @@ -237,26 +242,27 @@ static void vertex_interpolation_from_corner(const SubdivMeshContext *ctx, const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop; const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop; const int first_indices[2] = { - coarse_mloop[first_loop_index].v, - coarse_mloop[coarse_poly->loopstart + - (first_loop_index - coarse_poly->loopstart + 1) % coarse_poly->totloop] - .v}; + static_cast<int>(coarse_mloop[first_loop_index].v), + static_cast<int>( + coarse_mloop[coarse_poly->loopstart + + (first_loop_index - coarse_poly->loopstart + 1) % coarse_poly->totloop] + .v)}; const int last_indices[2] = { - coarse_mloop[first_loop_index].v, - coarse_mloop[last_loop_index].v, + static_cast<int>(coarse_mloop[first_loop_index].v), + static_cast<int>(coarse_mloop[last_loop_index].v), }; CustomData_interp(vertex_data, &vertex_interpolation->vertex_data_storage, first_indices, weights, - NULL, + nullptr, 2, 1); CustomData_interp(vertex_data, &vertex_interpolation->vertex_data_storage, last_indices, weights, - NULL, + nullptr, 2, 3); } @@ -275,7 +281,7 @@ static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolat /** \name Loop custom data interpolation helpers * \{ */ -typedef struct LoopsForInterpolation { +struct LoopsForInterpolation { /* This field points to a loop data which is to be used for interpolation. * The idea is to avoid unnecessary allocations for regular faces, where * we can simply interpolate corner vertices. */ @@ -291,10 +297,10 @@ typedef struct LoopsForInterpolation { * Is allocated for non-regular faces (triangles and n-gons). */ CustomData loop_data_storage; bool loop_data_storage_allocated; - /* Infices within loop_data to interpolate for. The indices are aligned with + /* Indices within loop_data to interpolate for. The indices are aligned with * uv coordinates in a similar way as indices in loop_data_storage. */ int loop_indices[4]; -} LoopsForInterpolation; +}; static void loop_interpolation_init(const SubdivMeshContext *ctx, LoopsForInterpolation *loop_interpolation, @@ -326,17 +332,17 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, /* Interpolate center of poly right away, it stays unchanged for all * ptex faces. */ const float weight = 1.0f / (float)coarse_poly->totloop; - float *weights = BLI_array_alloca(weights, coarse_poly->totloop); - int *indices = BLI_array_alloca(indices, coarse_poly->totloop); + blender::Array<float, 32> weights(coarse_poly->totloop); + blender::Array<int, 32> indices(coarse_poly->totloop); for (int i = 0; i < coarse_poly->totloop; i++) { weights[i] = weight; indices[i] = coarse_poly->loopstart + i; } CustomData_interp(&coarse_mesh->ldata, &loop_interpolation->loop_data_storage, - indices, - weights, - NULL, + indices.data(), + weights.data(), + nullptr, coarse_poly->totloop, 2); } @@ -372,13 +378,13 @@ static void loop_interpolation_from_corner(const SubdivMeshContext *ctx, (first_loop_index - base_loop_index + 1) % coarse_poly->totloop; const int first_indices[2] = {first_loop_index, second_loop_index}; const int last_indices[2] = { - loops_of_ptex.last_loop - coarse_mloop, - loops_of_ptex.first_loop - coarse_mloop, + static_cast<int>(loops_of_ptex.last_loop - coarse_mloop), + static_cast<int>(loops_of_ptex.first_loop - coarse_mloop), }; CustomData_interp( - loop_data, &loop_interpolation->loop_data_storage, first_indices, weights, NULL, 2, 1); + loop_data, &loop_interpolation->loop_data_storage, first_indices, weights, nullptr, 2, 1); CustomData_interp( - loop_data, &loop_interpolation->loop_data_storage, last_indices, weights, NULL, 2, 3); + loop_data, &loop_interpolation->loop_data_storage, last_indices, weights, nullptr, 2, 3); } } @@ -395,7 +401,7 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) /** \name TLS * \{ */ -typedef struct SubdivMeshTLS { +struct SubdivMeshTLS { bool vertex_interpolation_initialized; VerticesForInterpolation vertex_interpolation; const MPoly *vertex_interpolation_coarse_poly; @@ -405,11 +411,11 @@ typedef struct SubdivMeshTLS { LoopsForInterpolation loop_interpolation; const MPoly *loop_interpolation_coarse_poly; int loop_interpolation_coarse_corner; -} SubdivMeshTLS; +}; static void subdiv_mesh_tls_free(void *tls_v) { - SubdivMeshTLS *tls = tls_v; + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); if (tls->vertex_interpolation_initialized) { vertex_interpolation_end(&tls->vertex_interpolation); } @@ -492,7 +498,7 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex CustomData_MeshMasks mask = CD_MASK_EVERYTHING; mask.lmask &= ~CD_MASK_MULTIRES_GRIDS; - SubdivMeshContext *subdiv_context = foreach_context->user_data; + SubdivMeshContext *subdiv_context = static_cast<SubdivMeshContext *>(foreach_context->user_data); subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex( subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask); subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context); @@ -533,10 +539,10 @@ static void subdiv_vertex_data_interpolate(const SubdivMeshContext *ctx, &ctx->subdiv_mesh->vdata, vertex_interpolation->vertex_indices, weights, - NULL, + nullptr, 4, subdiv_vertex_index); - if (ctx->vert_origindex != NULL) { + if (ctx->vert_origindex != nullptr) { ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; } } @@ -564,7 +570,7 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext add_v3_v3(subdiv_vert->co, D); /* Evaluate undeformed texture coordinate. */ subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index); - /* Remove facedot flag. This can happen if there is more than one subsurf modifier. */ + /* Remove face-dot flag. This can happen if there is more than one subsurf modifier. */ BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index); } @@ -602,7 +608,7 @@ static void subdiv_mesh_vertex_displacement_every_corner_or_edge( const float v, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); Mesh *subdiv_mesh = ctx->subdiv_mesh; MVert *subdiv_mvert = subdiv_mesh->mvert; MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index]; @@ -649,7 +655,7 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex const int subdiv_vertex_index) { BLI_assert(coarse_vertex_index != ORIGINDEX_NONE); - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MVert *coarse_mvert = coarse_mesh->mvert; Mesh *subdiv_mesh = ctx->subdiv_mesh; @@ -698,8 +704,8 @@ static void subdiv_mesh_vertex_edge(const SubdivForeachContext *foreach_context, const int coarse_corner, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; - SubdivMeshTLS *tls = tls_v; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; @@ -746,8 +752,8 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context const int coarse_corner, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; - SubdivMeshTLS *tls = tls_v; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); Subdiv *subdiv = ctx->subdiv; const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; @@ -773,13 +779,13 @@ static void subdiv_copy_edge_data(SubdivMeshContext *ctx, const MEdge *coarse_edge) { const int subdiv_edge_index = subdiv_edge - ctx->subdiv_mesh->medge; - if (coarse_edge == NULL) { + if (coarse_edge == nullptr) { subdiv_edge->crease = 0; subdiv_edge->flag = 0; if (!ctx->settings->use_optimal_display) { subdiv_edge->flag |= ME_EDGERENDER; } - if (ctx->edge_origindex != NULL) { + if (ctx->edge_origindex != nullptr) { ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE; } return; @@ -798,11 +804,11 @@ static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context, const int subdiv_v1, const int subdiv_v2) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); Mesh *subdiv_mesh = ctx->subdiv_mesh; MEdge *subdiv_medge = subdiv_mesh->medge; MEdge *subdiv_edge = &subdiv_medge[subdiv_edge_index]; - const MEdge *coarse_edge = NULL; + const MEdge *coarse_edge = nullptr; if (coarse_edge_index != ORIGINDEX_NONE) { const Mesh *coarse_mesh = ctx->coarse_mesh; const MEdge *coarse_medge = coarse_mesh->medge; @@ -831,7 +837,7 @@ static void subdiv_interpolate_loop_data(const SubdivMeshContext *ctx, &ctx->subdiv_mesh->ldata, loop_interpolation->loop_indices, weights, - NULL, + nullptr, 4, subdiv_loop_index); /* TODO(sergey): Set ORIGINDEX. */ @@ -894,8 +900,8 @@ static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context, const int subdiv_vertex_index, const int subdiv_edge_index) { - SubdivMeshContext *ctx = foreach_context->user_data; - SubdivMeshTLS *tls = tls_v; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; @@ -933,7 +939,7 @@ static void subdiv_mesh_poly(const SubdivForeachContext *foreach_context, const int num_loops) { BLI_assert(coarse_poly_index != ORIGINDEX_NONE); - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; @@ -956,7 +962,7 @@ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context const int coarse_vertex_index, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MVert *coarse_mvert = coarse_mesh->mvert; const MVert *coarse_vertex = &coarse_mvert[coarse_vertex_index]; @@ -974,8 +980,8 @@ static void find_edge_neighbors(const Mesh *coarse_mesh, const MEdge *neighbors[2]) { const MEdge *coarse_medge = coarse_mesh->medge; - neighbors[0] = NULL; - neighbors[1] = NULL; + neighbors[0] = nullptr; + neighbors[1] = nullptr; int neighbor_counters[2] = {0, 0}; for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) { const MEdge *current_edge = &coarse_medge[edge_index]; @@ -995,10 +1001,10 @@ static void find_edge_neighbors(const Mesh *coarse_mesh, * sharp. This is also how topology factory treats vertices of a surface * which are adjacent to a loose edge. */ if (neighbor_counters[0] > 1) { - neighbors[0] = NULL; + neighbors[0] = nullptr; } if (neighbor_counters[1] > 1) { - neighbors[1] = NULL; + neighbors[1] = nullptr; } } @@ -1012,7 +1018,7 @@ static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh, copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co); copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co); /* Start point, duplicate from edge start if no neighbor. */ - if (neighbors[0] != NULL) { + if (neighbors[0] != nullptr) { if (neighbors[0]->v1 == coarse_edge->v1) { copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v2].co); } @@ -1025,7 +1031,7 @@ static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh, add_v3_v3(points_r[0], points_r[1]); } /* End point, duplicate from edge end if no neighbor. */ - if (neighbors[1] != NULL) { + if (neighbors[1] != nullptr) { if (neighbors[1]->v1 == coarse_edge->v2) { copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v2].co); } @@ -1074,26 +1080,27 @@ static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx, BLI_assert(u > 0.0f); BLI_assert(u < 1.0f); const float interpolation_weights[2] = {1.0f - u, u}; - const int coarse_vertex_indices[2] = {coarse_edge->v1, coarse_edge->v2}; + const int coarse_vertex_indices[2] = {static_cast<int>(coarse_edge->v1), + static_cast<int>(coarse_edge->v2)}; CustomData_interp(&coarse_mesh->vdata, &subdiv_mesh->vdata, coarse_vertex_indices, interpolation_weights, - NULL, + nullptr, 2, subdiv_vertex_index); - if (ctx->vert_origindex != NULL) { + if (ctx->vert_origindex != nullptr) { ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; } } -static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *foreach_context, +static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach_context, void *UNUSED(tls), const int coarse_edge_index, const float u, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index]; Mesh *subdiv_mesh = ctx->subdiv_mesh; @@ -1154,7 +1161,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, /* Make sure evaluator is up to date with possible new topology, and that * it is refined for the new positions of coarse vertices. */ if (!BKE_subdiv_eval_begin_from_mesh( - subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) { + subdiv, coarse_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) { /* This could happen in two situations: * - OpenSubdiv is disabled. * - Something totally bad happened, and OpenSubdiv rejected our @@ -1162,7 +1169,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, * In either way, we can't safely continue. */ if (coarse_mesh->totpoly) { BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); - return NULL; + return nullptr; } } /* Initialize subdivision mesh creation context. */ @@ -1170,7 +1177,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, subdiv_context.settings = settings; subdiv_context.coarse_mesh = coarse_mesh; subdiv_context.subdiv = subdiv; - subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL); + subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr); /* Multi-threaded traversal/evaluation. */ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); SubdivForeachContext foreach_context; diff --git a/source/blender/blenkernel/intern/tracking_detect.c b/source/blender/blenkernel/intern/tracking_detect.c index 51ffce4a3e3..540f880905d 100644 --- a/source/blender/blenkernel/intern/tracking_detect.c +++ b/source/blender/blenkernel/intern/tracking_detect.c @@ -81,7 +81,6 @@ static void detect_retrieve_libmv_features(MovieTracking *tracking, a = libmv_countFeatures(features); while (a--) { - MovieTrackingTrack *track; double x, y, size, score; bool ok = true; float xu, yu; @@ -99,7 +98,8 @@ static void detect_retrieve_libmv_features(MovieTracking *tracking, } if (ok) { - track = BKE_tracking_track_add(tracking, tracksbase, xu, yu, framenr, width, height); + MovieTrackingTrack *track = BKE_tracking_track_add( + tracking, tracksbase, xu, yu, framenr, width, height); track->flag |= SELECT; track->pat_flag |= SELECT; track->search_flag |= SELECT; diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index e2e0b4227e3..b03d226964c 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -1342,7 +1342,7 @@ ImBuf *BKE_tracking_stabilize_frame( return ibuf; } - /* Allocate frame for stabilization result, copy alpha mode and colorspace. */ + /* Allocate frame for stabilization result, copy alpha mode and color-space. */ ibuf_flags = 0; if (ibuf->rect) { ibuf_flags |= IB_rect; diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index b31632f0234..f7ea4c81fbf 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -845,8 +845,8 @@ static bool unit_distribute_negatives(char *str, const int len_max) bool changed = false; char *remaining_str = str; - int remaining_str_len = len_max; while ((remaining_str = find_next_negative(str, remaining_str)) != NULL) { + int remaining_str_len; /* Exit early in the unlikely situation that we've run out of length to add the parentheses. */ remaining_str_len = len_max - (int)(remaining_str - str); if (remaining_str_len <= 2) { @@ -1025,6 +1025,16 @@ static bool unit_find(const char *str, const bUnitDef *unit) return false; } +static const bUnitDef *unit_find_in_collection(const bUnitCollection *usys, const char *str) +{ + for (const bUnitDef *unit = usys->units; unit->name; unit++) { + if (unit_find(str, unit)) { + return unit; + } + } + return NULL; +} + /** * Try to find a default unit from current or previous string. * This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m! @@ -1035,25 +1045,15 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const char *str, const char *str_prev) { - const bUnitDef *unit = NULL; - /* See which units the new value has. */ - for (unit = usys->units; unit->name; unit++) { - if (unit_find(str, unit)) { - break; - } - } + const bUnitDef *unit = unit_find_in_collection(usys, str); /* Else, try to infer the default unit from the previous string. */ - if (str_prev && (unit == NULL || unit->name == NULL)) { + if (str_prev && (unit == NULL)) { /* See which units the original value had. */ - for (unit = usys->units; unit->name; unit++) { - if (unit_find(str_prev, unit)) { - break; - } - } + unit = unit_find_in_collection(usys, str_prev); } /* Else, fall back to default unit. */ - if (unit == NULL || unit->name == NULL) { + if (unit == NULL) { unit = unit_default(usys); } @@ -1067,11 +1067,8 @@ bool BKE_unit_string_contains_unit(const char *str, int type) if (!is_valid_unit_collection(usys)) { continue; } - - for (int i = 0; i < usys->length; i++) { - if (unit_find(str, usys->units + i)) { - return true; - } + if (unit_find_in_collection(usys, str)) { + return true; } } return false; @@ -1155,13 +1152,12 @@ bool BKE_unit_replace_string( */ { char *str_found = str; - const char *ch = str; while ((str_found = strchr(str_found, SEP_CHR))) { bool op_found = false; /* Any operators after this? */ - for (ch = str_found + 1; *ch != '\0'; ch++) { + for (const char *ch = str_found + 1; *ch != '\0'; ch++) { if (ELEM(*ch, ' ', '\t')) { continue; } diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h index 41d1eef733c..c6fbdcc542c 100644 --- a/source/blender/blenkernel/nla_private.h +++ b/source/blender/blenkernel/nla_private.h @@ -128,7 +128,7 @@ typedef struct NlaEvalData { int num_channels; NlaEvalSnapshot base_snapshot; - /* Evaluation result shapshot. */ + /* Evaluation result snapshot. */ NlaEvalSnapshot eval_snapshot; } NlaEvalData; diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh index a20239f214f..f9b53436763 100644 --- a/source/blender/blenlib/BLI_any.hh +++ b/source/blender/blenlib/BLI_any.hh @@ -39,7 +39,7 @@ template<typename ExtraInfo> struct AnyTypeInfo { * Used when #T is stored directly in the inline buffer of the #Any. */ template<typename ExtraInfo, typename T> -static constexpr AnyTypeInfo<ExtraInfo> info_for_inline = { +inline constexpr AnyTypeInfo<ExtraInfo> info_for_inline = { is_trivially_copy_constructible_extended_v<T> ? nullptr : +[](void *dst, const void *src) { new (dst) T(*(const T *)src); }, @@ -57,7 +57,7 @@ static constexpr AnyTypeInfo<ExtraInfo> info_for_inline = { */ template<typename T> using Ptr = std::unique_ptr<T>; template<typename ExtraInfo, typename T> -static constexpr AnyTypeInfo<ExtraInfo> info_for_unique_ptr = { +inline constexpr AnyTypeInfo<ExtraInfo> info_for_unique_ptr = { [](void *dst, const void *src) { new (dst) Ptr<T>(new T(**(const Ptr<T> *)src)); }, [](void *dst, void *src) { new (dst) Ptr<T>(new T(std::move(**(Ptr<T> *)src))); }, [](void *src) { std::destroy_at((Ptr<T> *)src); }, diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h index 8a91825da6f..c04c392627d 100644 --- a/source/blender/blenlib/BLI_array_store.h +++ b/source/blender/blenlib/BLI_array_store.h @@ -57,7 +57,6 @@ size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs); size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs); /** - * * \param data: Data used to create * \param state_reference: The state to use as a reference when adding the new state, * typically this is the previous state, diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh index 64e6e68432f..ca0d9ea0028 100644 --- a/source/blender/blenlib/BLI_float4x4.hh +++ b/source/blender/blenlib/BLI_float4x4.hh @@ -266,7 +266,7 @@ struct float4x4 { for (int j = 0; j < 4; j++) { snprintf(fchar, sizeof(fchar), "%11.6f", mat[j][i]); stream << fchar; - if (i != 3) { + if (j != 3) { stream << ", "; } } diff --git a/source/blender/blenlib/BLI_function_ref.hh b/source/blender/blenlib/BLI_function_ref.hh index 5f18e994991..9a38176c988 100644 --- a/source/blender/blenlib/BLI_function_ref.hh +++ b/source/blender/blenlib/BLI_function_ref.hh @@ -63,7 +63,6 @@ * * void some_function(FunctionRef<int()> f); * some_function([]() { return 0; }); - * */ #include "BLI_memory_utils.hh" diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index 6386a7f76f8..3aa2e35476d 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -164,7 +164,9 @@ void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]); MINLINE float rgb_to_grayscale(const float rgb[3]); MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]); -MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], int limit); +MINLINE int compare_rgb_uchar(const unsigned char col_a[3], + const unsigned char col_b[3], + int limit); /** * Return triangle noise in [-0.5..1.5] range. diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 93b413ab755..d056c42e019 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -1270,8 +1270,8 @@ MINLINE void mul_sh_fl(float r[9], float f); MINLINE void add_sh_shsh(float r[9], const float a[9], const float b[9]); MINLINE float dot_shsh(const float a[9], const float b[9]); -MINLINE float eval_shv3(float r[9], const float v[3]); -MINLINE float diffuse_shv3(const float r[9], const float v[3]); +MINLINE float eval_shv3(float sh[9], const float v[3]); +MINLINE float diffuse_shv3(const float sh[9], const float v[3]); MINLINE void vec_fac_to_sh(float r[9], const float v[3], float f); MINLINE void madd_sh_shfl(float r[9], const float sh[9], float f); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index c2dafbe3a1a..467e6db4805 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -98,110 +98,110 @@ void mul_m4_m4_post(float R[4][4], const float B[4][4]); /* Implement #mul_m3_series macro. */ -void _va_mul_m3_series_3(float R[3][3], const float M1[3][3], const float M2[3][3]) ATTR_NONNULL(); -void _va_mul_m3_series_4(float R[3][3], - const float M1[3][3], - const float M2[3][3], - const float M3[3][3]) ATTR_NONNULL(); -void _va_mul_m3_series_5(float R[3][3], - const float M1[3][3], - const float M2[3][3], - const float M3[3][3], - const float M4[3][3]) ATTR_NONNULL(); -void _va_mul_m3_series_6(float R[3][3], - const float M1[3][3], - const float M2[3][3], - const float M3[3][3], - const float M4[3][3], - const float M5[3][3]) ATTR_NONNULL(); -void _va_mul_m3_series_7(float R[3][3], - const float M1[3][3], - const float M2[3][3], - const float M3[3][3], - const float M4[3][3], - const float M5[3][3], - const float M6[3][3]) ATTR_NONNULL(); -void _va_mul_m3_series_8(float R[3][3], - const float M1[3][3], - const float M2[3][3], - const float M3[3][3], - const float M4[3][3], - const float M5[3][3], - const float M6[3][3], - const float M7[3][3]) ATTR_NONNULL(); -void _va_mul_m3_series_9(float R[3][3], - const float M1[3][3], - const float M2[3][3], - const float M3[3][3], - const float M4[3][3], - const float M5[3][3], - const float M6[3][3], - const float M7[3][3], - const float M8[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_3(float r[3][3], const float m1[3][3], const float m2[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_4(float r[3][3], + const float m1[3][3], + const float m2[3][3], + const float m3[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_5(float r[3][3], + const float m1[3][3], + const float m2[3][3], + const float m3[3][3], + const float m4[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_6(float r[3][3], + const float m1[3][3], + const float m2[3][3], + const float m3[3][3], + const float m4[3][3], + const float m5[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_7(float r[3][3], + const float m1[3][3], + const float m2[3][3], + const float m3[3][3], + const float m4[3][3], + const float m5[3][3], + const float m6[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_8(float r[3][3], + const float m1[3][3], + const float m2[3][3], + const float m3[3][3], + const float m4[3][3], + const float m5[3][3], + const float m6[3][3], + const float m7[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_9(float r[3][3], + const float m1[3][3], + const float m2[3][3], + const float m3[3][3], + const float m4[3][3], + const float m5[3][3], + const float m6[3][3], + const float m7[3][3], + const float m8[3][3]) ATTR_NONNULL(); /* Implement #mul_m4_series macro. */ -void _va_mul_m4_series_3(float R[4][4], const float M1[4][4], const float M2[4][4]) ATTR_NONNULL(); -void _va_mul_m4_series_4(float R[4][4], - const float M1[4][4], - const float M2[4][4], - const float M3[4][4]) ATTR_NONNULL(); -void _va_mul_m4_series_5(float R[4][4], - const float M1[4][4], - const float M2[4][4], - const float M3[4][4], - const float M4[4][4]) ATTR_NONNULL(); -void _va_mul_m4_series_6(float R[4][4], - const float M1[4][4], - const float M2[4][4], - const float M3[4][4], - const float M4[4][4], - const float M5[4][4]) ATTR_NONNULL(); -void _va_mul_m4_series_7(float R[4][4], - const float M1[4][4], - const float M2[4][4], - const float M3[4][4], - const float M4[4][4], - const float M5[4][4], - const float M6[4][4]) ATTR_NONNULL(); -void _va_mul_m4_series_8(float R[4][4], - const float M1[4][4], - const float M2[4][4], - const float M3[4][4], - const float M4[4][4], - const float M5[4][4], - const float M6[4][4], - const float M7[4][4]) ATTR_NONNULL(); -void _va_mul_m4_series_9(float R[4][4], - const float M1[4][4], - const float M2[4][4], - const float M3[4][4], - const float M4[4][4], - const float M5[4][4], - const float M6[4][4], - const float M7[4][4], - const float M8[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_3(float r[4][4], const float m1[4][4], const float m2[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_4(float r[4][4], + const float m1[4][4], + const float m2[4][4], + const float m3[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_5(float r[4][4], + const float m1[4][4], + const float m2[4][4], + const float m3[4][4], + const float m4[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_6(float r[4][4], + const float m1[4][4], + const float m2[4][4], + const float m3[4][4], + const float m4[4][4], + const float m5[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_7(float r[4][4], + const float m1[4][4], + const float m2[4][4], + const float m3[4][4], + const float m4[4][4], + const float m5[4][4], + const float m6[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_8(float r[4][4], + const float m1[4][4], + const float m2[4][4], + const float m3[4][4], + const float m4[4][4], + const float m5[4][4], + const float m6[4][4], + const float m7[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_9(float r[4][4], + const float m1[4][4], + const float m2[4][4], + const float m3[4][4], + const float m4[4][4], + const float m5[4][4], + const float m6[4][4], + const float m7[4][4], + const float m8[4][4]) ATTR_NONNULL(); #define mul_m3_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m3_series_, __VA_ARGS__) #define mul_m4_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m4_series_, __VA_ARGS__) void mul_m4_v3(const float M[4][4], float r[3]); -void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3]); +void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3]); void mul_v3_m4v3_db(double r[3], const double mat[4][4], const double vec[3]); void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3]); -void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]); -void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]); -void mul_m2_v2(const float M[2][2], float v[2]); +void mul_v2_m4v3(float r[2], const float mat[4][4], const float vec[3]); +void mul_v2_m2v2(float r[2], const float mat[2][2], const float vec[2]); +void mul_m2_v2(const float mat[2][2], float vec[2]); /** Same as #mul_m4_v3() but doesn't apply translation component. */ -void mul_mat3_m4_v3(const float M[4][4], float r[3]); -void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]); -void mul_v3_mat3_m4v3_db(double r[3], const double M[4][4], const double v[3]); -void mul_m4_v4(const float M[4][4], float r[4]); -void mul_v4_m4v4(float r[4], const float M[4][4], const float v[4]); +void mul_mat3_m4_v3(const float mat[4][4], float r[3]); +void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3]); +void mul_v3_mat3_m4v3_db(double r[3], const double mat[4][4], const double vec[3]); +void mul_m4_v4(const float mat[4][4], float r[4]); +void mul_v4_m4v4(float r[4], const float mat[4][4], const float v[4]); void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3]); /* v has implicit w = 1.0f */ -void mul_project_m4_v3(const float M[4][4], float vec[3]); +void mul_project_m4_v3(const float mat[4][4], float vec[3]); void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3]); -void mul_v2_project_m4_v3(float r[2], const float M[4][4], const float vec[3]); +void mul_v2_project_m4_v3(float r[2], const float mat[4][4], const float vec[3]); void mul_m3_v2(const float m[3][3], float r[2]); void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2]); @@ -234,14 +234,14 @@ void negate_m3(float R[3][3]); void negate_mat3_m4(float R[4][4]); void negate_m4(float R[4][4]); -bool invert_m3_ex(float m[3][3], float epsilon); -bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], float epsilon); +bool invert_m3_ex(float mat[3][3], float epsilon); +bool invert_m3_m3_ex(float inverse[3][3], const float mat[3][3], float epsilon); -bool invert_m3(float R[3][3]); -bool invert_m2_m2(float R[2][2], const float A[2][2]); -bool invert_m3_m3(float R[3][3], const float A[3][3]); -bool invert_m4(float R[4][4]); -bool invert_m4_m4(float R[4][4], const float A[4][4]); +bool invert_m3(float mat[3][3]); +bool invert_m2_m2(float inverse[2][2], const float mat[2][2]); +bool invert_m3_m3(float inverse[3][3], const float mat[3][3]); +bool invert_m4(float mat[4][4]); +bool invert_m4_m4(float inverse[4][4], const float mat[4][4]); /** * Computes the inverse of mat and puts it in inverse. * Uses Gaussian Elimination with partial (maximal column) pivoting. @@ -252,12 +252,12 @@ bool invert_m4_m4(float R[4][4], const float A[4][4]); * for non-invertible scale matrices, finding a partial solution can * be useful to have a valid local transform center, see T57767. */ -bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]); +bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4]); /* Double arithmetic (mixed float/double). */ -void mul_m4_v4d(const float M[4][4], double r[4]); -void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]); +void mul_m4_v4d(const float mat[4][4], double r[4]); +void mul_v4d_m4v4d(double r[4], const float mat[4][4], const double v[4]); /* Double matrix functions (no mixing types). */ @@ -291,8 +291,8 @@ void normalize_m3_m3_ex(float R[3][3], const float M[3][3], float r_scale[3]) AT void normalize_m3_m3(float R[3][3], const float M[3][3]) ATTR_NONNULL(); void normalize_m4_ex(float R[4][4], float r_scale[3]) ATTR_NONNULL(); void normalize_m4(float R[4][4]) ATTR_NONNULL(); -void normalize_m4_m4_ex(float R[4][4], const float M[4][4], float r_scale[3]) ATTR_NONNULL(); -void normalize_m4_m4(float R[4][4], const float M[4][4]) ATTR_NONNULL(); +void normalize_m4_m4_ex(float rmat[4][4], const float mat[4][4], float r_scale[3]) ATTR_NONNULL(); +void normalize_m4_m4(float rmat[4][4], const float mat[4][4]) ATTR_NONNULL(); /** * Make an orthonormal matrix around the selected axis of the given matrix. @@ -326,15 +326,15 @@ void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize); */ void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize); -bool orthogonalize_m3_zero_axes(float R[3][3], float unit_length); -bool orthogonalize_m4_zero_axes(float R[4][4], float unit_length); +bool orthogonalize_m3_zero_axes(float m[3][3], float unit_length); +bool orthogonalize_m4_zero_axes(float m[4][4], float unit_length); -bool is_orthogonal_m3(const float mat[3][3]); -bool is_orthogonal_m4(const float mat[4][4]); -bool is_orthonormal_m3(const float mat[3][3]); -bool is_orthonormal_m4(const float mat[4][4]); +bool is_orthogonal_m3(const float m[3][3]); +bool is_orthogonal_m4(const float m[4][4]); +bool is_orthonormal_m3(const float m[3][3]); +bool is_orthonormal_m4(const float m[4][4]); -bool is_uniform_scaled_m3(const float mat[3][3]); +bool is_uniform_scaled_m3(const float m[3][3]); bool is_uniform_scaled_m4(const float m[4][4]); /* NOTE: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix! @@ -362,22 +362,22 @@ float determinant_m4(const float m[4][4]); * From this decomposition it is trivial to compute the (pseudo-inverse) * of `A` as `Ainv = V.Winv.transpose(U)`. */ -void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]); -void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon); -void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon); +void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4]); +void pseudoinverse_m4_m4(float inverse[4][4], const float mat[4][4], float epsilon); +void pseudoinverse_m3_m3(float inverse[3][3], const float mat[3][3], float epsilon); bool has_zero_axis_m4(const float matrix[4][4]); -void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]); +void invert_m4_m4_safe(float inverse[4][4], const float mat[4][4]); -void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]); +void invert_m3_m3_safe_ortho(float inverse[3][3], const float mat[3][3]); /** * A safe version of invert that uses valid axes, calculating the zero'd axis * based on the non-zero ones. * * This works well for transformation matrices, when a single axis is zeroed. */ -void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]); +void invert_m4_m4_safe_ortho(float inverse[4][4], const float mat[4][4]); /** \} */ @@ -394,18 +394,18 @@ void scale_m4_v2(float R[4][4], const float scale[2]); * For an orthogonal matrix, it is the product of all three scale values. * Returns a negative value if the transform is flipped by negative scale. */ -float mat3_to_volume_scale(const float M[3][3]); -float mat4_to_volume_scale(const float M[4][4]); +float mat3_to_volume_scale(const float mat[3][3]); +float mat4_to_volume_scale(const float mat[4][4]); /** * This gets the average scale of a matrix, only use when your scaling * data that has no idea of scale axis, examples are bone-envelope-radius * and curve radius. */ -float mat3_to_scale(const float M[3][3]); -float mat4_to_scale(const float M[4][4]); +float mat3_to_scale(const float mat[3][3]); +float mat4_to_scale(const float mat[4][4]); /** Return 2D scale (in XY plane) of given mat4. */ -float mat4_to_xy_scale(const float M[4][4]); +float mat4_to_xy_scale(const float mat[4][4]); void size_to_mat3(float R[3][3], const float size[3]); void size_to_mat4(float R[4][4], const float size[3]); @@ -433,7 +433,7 @@ float mat4_to_size_max_axis(const float M[4][4]); */ void mat4_to_size_fix_shear(float size[3], const float M[4][4]); -void translate_m4(float mat[4][4], float tx, float ty, float tz); +void translate_m4(float mat[4][4], float Tx, float Ty, float Tz); /** * Rotate a matrix in-place. * @@ -454,8 +454,20 @@ void rescale_m4(float mat[4][4], const float scale[3]); */ void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); +/** + * \param rot: A 3x3 rotation matrix, normalized never negative. + */ void mat4_to_rot(float rot[3][3], const float wmat[4][4]); + +/** + * \param rot: A 3x3 rotation matrix, normalized never negative. + * \param size: The scale, negative if `mat3` is negative. + */ void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]); +/** + * \param rot: A 3x3 rotation matrix, normalized never negative. + * \param size: The scale, negative if `mat3` is negative. + */ void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]); void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]); void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4]); @@ -528,7 +540,18 @@ void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], flo */ void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], float t); +/** + * Return true when the matrices determinant is less than zero. + * + * \note This is often used to check if a matrix flips content in 3D space, + * where transforming geometry (for example) would flip the direction of polygon normals + * from pointing outside a closed volume, to pointing inside (or the reverse). + * + * When the matrix is constructed from location, rotation & scale + * as matrix will be negative when it has an odd number of negative scales. + */ bool is_negative_m3(const float mat[3][3]); +/** A version of #is_negative_m3 that takes a 4x4 matrix. */ bool is_negative_m4(const float mat[4][4]); bool is_zero_m3(const float mat[3][3]); @@ -605,8 +628,8 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float /** \name Other * \{ */ -void print_m3(const char *str, const float M[3][3]); -void print_m4(const char *str, const float M[4][4]); +void print_m3(const char *str, const float m[3][3]); +void print_m4(const char *str, const float m[4][4]); #define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M) diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index b8ab74d95ff..7fb7085360b 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -71,7 +71,7 @@ void mul_qt_fl(float q[4], float f); /** * Raise a unit quaternion to the specified power. */ -void pow_qt_fl_normalized(float q[4], float f); +void pow_qt_fl_normalized(float q[4], float fac); void sub_qt_qtqt(float q[4], const float a[4], const float b[4]); @@ -109,8 +109,8 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], float t); /* Conversion. */ -void quat_to_mat3(float mat[3][3], const float q[4]); -void quat_to_mat4(float mat[4][4], const float q[4]); +void quat_to_mat3(float m[3][3], const float q[4]); +void quat_to_mat4(float m[4][4], const float q[4]); /** * Apply the rotation of \a a to \a q keeping the values compatible with \a old. @@ -118,6 +118,11 @@ void quat_to_mat4(float mat[4][4], const float q[4]); */ void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]); +/** + * A version of #mat3_normalized_to_quat that skips error checking. + */ +void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3]); + void mat3_normalized_to_quat(float q[4], const float mat[3][3]); void mat4_normalized_to_quat(float q[4], const float mat[4][4]); void mat3_to_quat(float q[4], const float mat[3][3]); @@ -157,7 +162,10 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q * \param r_twist: if not NULL, receives the twist quaternion. * \returns twist angle. */ -float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]); +float quat_split_swing_and_twist(const float q_in[4], + int axis, + float r_swing[4], + float r_twist[4]); float angle_normalized_qt(const float q[4]); float angle_normalized_qtqt(const float q1[4], const float q2[4]); @@ -170,9 +178,10 @@ float angle_signed_qt(const float q[4]); float angle_signed_qtqt(const float q1[4], const float q2[4]); /** - * TODO: don't what this is, but it's not the same as #mat3_to_quat. + * Legacy matrix to quaternion conversion, keep to prevent changes to existing + * boids & particle-system behavior. Use #mat3_to_quat for new code. */ -void mat3_to_quat_is_ok(float q[4], const float mat[3][3]); +void mat3_to_quat_legacy(float q[4], const float wmat[3][3]); /* Other. */ @@ -235,16 +244,16 @@ void axis_angle_to_mat4(float R[4][4], const float axis[3], float angle); /** * 3x3 matrix to axis angle. */ -void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float M[3][3]); +void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float mat[3][3]); /** * 4x4 matrix to axis angle. */ -void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float M[4][4]); -void mat3_to_axis_angle(float axis[3], float *angle, const float M[3][3]); +void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float mat[4][4]); +void mat3_to_axis_angle(float axis[3], float *angle, const float mat[3][3]); /** * 4x4 matrix to axis angle. */ -void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]); +void mat4_to_axis_angle(float axis[3], float *angle, const float mat[4][4]); /** * Quaternions to Axis Angle. */ @@ -283,19 +292,19 @@ void eul_to_mat3(float mat[3][3], const float eul[3]); void eul_to_mat4(float mat[4][4], const float eul[3]); void mat3_normalized_to_eul(float eul[3], const float mat[3][3]); -void mat4_normalized_to_eul(float eul[3], const float mat[4][4]); +void mat4_normalized_to_eul(float eul[3], const float m[4][4]); void mat3_to_eul(float eul[3], const float mat[3][3]); void mat4_to_eul(float eul[3], const float mat[4][4]); void quat_to_eul(float eul[3], const float quat[4]); -void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]); -void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]); +void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3]); +void mat3_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3]); void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]); -void rotate_eul(float eul[3], char axis, float angle); +void rotate_eul(float beul[3], char axis, float angle); /* Order independent. */ -void compatible_eul(float eul[3], const float old[3]); +void compatible_eul(float eul[3], const float oldrot[3]); void add_eul_euleul(float r_eul[3], float a[3], float b[3], short order); void sub_eul_euleul(float r_eul[3], float a[3], float b[3], short order); @@ -323,15 +332,15 @@ typedef enum eEulerRotationOrders { /** * Construct quaternion from Euler angles (in radians). */ -void eulO_to_quat(float quat[4], const float eul[3], short order); +void eulO_to_quat(float q[4], const float e[3], short order); /** * Construct 3x3 matrix from Euler angles (in radians). */ -void eulO_to_mat3(float mat[3][3], const float eul[3], short order); +void eulO_to_mat3(float M[3][3], const float e[3], short order); /** * Construct 4x4 matrix from Euler angles (in radians). */ -void eulO_to_mat4(float mat[4][4], const float eul[3], short order); +void eulO_to_mat4(float mat[4][4], const float e[3], short order); /** * Euler Rotation to Axis Angle. */ @@ -344,17 +353,17 @@ void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], short order); /** * Convert 3x3 matrix to Euler angles (in radians). */ -void mat3_normalized_to_eulO(float eul[3], short order, const float mat[3][3]); +void mat3_normalized_to_eulO(float eul[3], short order, const float m[3][3]); /** * Convert 4x4 matrix to Euler angles (in radians). */ -void mat4_normalized_to_eulO(float eul[3], short order, const float mat[4][4]); -void mat3_to_eulO(float eul[3], short order, const float mat[3][3]); -void mat4_to_eulO(float eul[3], short order, const float mat[4][4]); +void mat4_normalized_to_eulO(float eul[3], short order, const float m[4][4]); +void mat3_to_eulO(float eul[3], short order, const float m[3][3]); +void mat4_to_eulO(float eul[3], short order, const float m[4][4]); /** * Convert quaternion to Euler angles (in radians). */ -void quat_to_eulO(float eul[3], short order, const float quat[4]); +void quat_to_eulO(float e[3], short order, const float q[4]); /** * Axis Angle to Euler Rotation. */ @@ -363,18 +372,27 @@ void axis_angle_to_eulO(float eul[3], short order, const float axis[3], float an /* Uses 2 methods to retrieve eulers, and picks the closest. */ void mat3_normalized_to_compatible_eulO(float eul[3], - const float old[3], + const float oldrot[3], short order, const float mat[3][3]); void mat4_normalized_to_compatible_eulO(float eul[3], - const float old[3], + const float oldrot[3], short order, const float mat[4][4]); -void mat3_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[3][3]); -void mat4_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[4][4]); -void quat_to_compatible_eulO(float eul[3], const float old[3], short order, const float quat[4]); - -void rotate_eulO(float eul[3], short order, char axis, float angle); +void mat3_to_compatible_eulO(float eul[3], + const float oldrot[3], + short order, + const float mat[3][3]); +void mat4_to_compatible_eulO(float eul[3], + const float oldrot[3], + short order, + const float mat[4][4]); +void quat_to_compatible_eulO(float eul[3], + const float oldrot[3], + short order, + const float quat[4]); + +void rotate_eulO(float beul[3], short order, char axis, float angle); /** \} */ @@ -383,7 +401,7 @@ void rotate_eulO(float eul[3], short order, char axis, float angle); * \{ */ void copy_dq_dq(DualQuat *r, const DualQuat *dq); -void normalize_dq(DualQuat *dq, float totw); +void normalize_dq(DualQuat *dq, float totweight); void add_weighted_dq_dq(DualQuat *dq_sum, const DualQuat *dq, float weight); void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq); @@ -400,7 +418,7 @@ void vec_apply_track(float vec[3], short axis); * Lens/angle conversion (radians). */ float focallength_to_fov(float focal_length, float sensor); -float fov_to_focallength(float fov, float sensor); +float fov_to_focallength(float hfov, float sensor); float angle_wrap_rad(float angle); float angle_wrap_deg(float angle); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 0b178064a4c..17fe25ec67b 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -155,7 +155,7 @@ MINLINE void mul_v3_v3db_db(double r[3], const double a[3], double f); MINLINE void mul_v2_v2(float r[2], const float a[2]); MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2]); MINLINE void mul_v3_v3(float r[3], const float a[3]); -MINLINE void mul_v3_v3v3(float r[3], const float a[3], const float b[3]); +MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3]); MINLINE void mul_v4_fl(float r[4], float f); MINLINE void mul_v4_v4(float r[4], const float a[4]); MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f); @@ -271,10 +271,10 @@ MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_manhattan_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; MINLINE int len_manhattan_v2_int(const int v[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_manhattan_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; MINLINE double len_v2_db(const double v[2]) ATTR_WARN_UNUSED_RESULT; -MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; -MINLINE double len_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE double len_v2v2_db(const double v1[2], const double v2[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_v2v2_int(const int v1[2], const int v2[2]); MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE double len_squared_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT; @@ -288,22 +288,22 @@ MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESU MINLINE double len_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE double len_squared_v3_db(const double v[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float normalize_v2_length(float r[2], float unit_scale); +MINLINE float normalize_v2_length(float n[2], float unit_length); /** * \note any vectors containing `nan` will be zeroed out. */ -MINLINE float normalize_v2_v2_length(float r[2], const float a[2], float unit_scale); -MINLINE float normalize_v3_length(float r[3], float unit_scale); +MINLINE float normalize_v2_v2_length(float r[2], const float a[2], float unit_length); +MINLINE float normalize_v3_length(float n[3], float unit_length); /** * \note any vectors containing `nan` will be zeroed out. */ -MINLINE float normalize_v3_v3_length(float r[3], const float a[3], float unit_scale); -MINLINE double normalize_v3_length_db(double n[3], double unit_scale); -MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], double unit_scale); +MINLINE float normalize_v3_v3_length(float r[3], const float a[3], float unit_length); +MINLINE double normalize_v3_length_db(double n[3], double unit_length); +MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], double unit_length); -MINLINE float normalize_v2(float r[2]); +MINLINE float normalize_v2(float n[2]); MINLINE float normalize_v2_v2(float r[2], const float a[2]); -MINLINE float normalize_v3(float r[3]); +MINLINE float normalize_v3(float n[3]); MINLINE float normalize_v3_v3(float r[3], const float a[3]); MINLINE double normalize_v3_v3_db(double r[3], const double a[3]); MINLINE double normalize_v3_db(double n[3]); @@ -424,45 +424,51 @@ void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]); /** \name Comparison * \{ */ -MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool is_zero_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v4(const float v[4]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool is_zero_v2_db(const double a[2]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool is_zero_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool is_zero_v4_db(const double a[4]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v2_db(const double v[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v3_db(const double v[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v4_db(const double v[4]) ATTR_WARN_UNUSED_RESULT; -bool is_finite_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT; -bool is_finite_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; -bool is_finite_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT; +bool is_finite_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; +bool is_finite_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; +bool is_finite_v4(const float v[4]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool is_one_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_one_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool equals_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool equals_v4v4(const float v1[4], const float v2[4]) ATTR_WARN_UNUSED_RESULT; MINLINE bool equals_v2v2_int(const int v1[2], const int v2[2]) ATTR_WARN_UNUSED_RESULT; MINLINE bool equals_v3v3_int(const int v1[3], const int v2[3]) ATTR_WARN_UNUSED_RESULT; MINLINE bool equals_v4v4_int(const int v1[4], const int v2[4]) ATTR_WARN_UNUSED_RESULT; -MINLINE bool compare_v2v2(const float a[2], const float b[2], float limit) ATTR_WARN_UNUSED_RESULT; -MINLINE bool compare_v3v3(const float a[3], const float b[3], float limit) ATTR_WARN_UNUSED_RESULT; -MINLINE bool compare_v4v4(const float a[4], const float b[4], float limit) ATTR_WARN_UNUSED_RESULT; - -MINLINE bool compare_v2v2_relative(const float a[2], const float b[2], float limit, int max_ulps) +MINLINE bool compare_v2v2(const float v1[2], + const float v2[2], + float limit) ATTR_WARN_UNUSED_RESULT; +MINLINE bool compare_v3v3(const float v1[3], + const float v2[3], + float limit) ATTR_WARN_UNUSED_RESULT; +MINLINE bool compare_v4v4(const float v1[4], + const float v2[4], + float limit) ATTR_WARN_UNUSED_RESULT; + +MINLINE bool compare_v2v2_relative(const float v1[2], const float v2[2], float limit, int max_ulps) ATTR_WARN_UNUSED_RESULT; -MINLINE bool compare_v3v3_relative(const float a[3], const float b[3], float limit, int max_ulps) +MINLINE bool compare_v3v3_relative(const float v1[3], const float v2[3], float limit, int max_ulps) ATTR_WARN_UNUSED_RESULT; -MINLINE bool compare_v4v4_relative(const float a[4], const float b[4], float limit, int max_ulps) +MINLINE bool compare_v4v4_relative(const float v1[4], const float v2[4], float limit, int max_ulps) ATTR_WARN_UNUSED_RESULT; -MINLINE bool compare_len_v3v3(const float a[3], - const float b[3], +MINLINE bool compare_len_v3v3(const float v1[3], + const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT; -MINLINE bool compare_size_v3v3(const float a[3], - const float b[3], +MINLINE bool compare_size_v3v3(const float v1[3], + const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT; /** @@ -606,8 +612,8 @@ void project_v3_plane(float out[3], const float plane_no[3], const float plane_c * out: result (negate for a 'bounce'). * </pre> */ -void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]); -void reflect_v3_v3v3_db(double out[3], const double vec[3], const double normal[3]); +void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3]); +void reflect_v3_v3v3_db(double out[3], const double v[3], const double normal[3]); /** * Takes a vector and computes 2 orthogonal directions. * @@ -655,10 +661,10 @@ void print_vn(const char *str, const float v[], int n); #define print_v4_id(v) print_v4(STRINGIFY(v), v) #define print_vn_id(v, n) print_vn(STRINGIFY(v), v, n) -MINLINE void normal_float_to_short_v2(short r[2], const float n[2]); -MINLINE void normal_short_to_float_v3(float r[3], const short n[3]); -MINLINE void normal_float_to_short_v3(short r[3], const float n[3]); -MINLINE void normal_float_to_short_v4(short r[4], const float n[4]); +MINLINE void normal_float_to_short_v2(short out[2], const float in[2]); +MINLINE void normal_short_to_float_v3(float out[3], const short in[3]); +MINLINE void normal_float_to_short_v3(short out[3], const float in[3]); +MINLINE void normal_float_to_short_v4(short out[4], const float in[4]); void minmax_v4v4_v4(float min[4], float max[4], const float vec[4]); void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]); diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh index bd91c522d06..e23d7d20d0b 100644 --- a/source/blender/blenlib/BLI_serialize.hh +++ b/source/blender/blenlib/BLI_serialize.hh @@ -55,7 +55,6 @@ * * To add a new formatter a new sub-class of `Formatter` must be created and the * `serialize`/`deserialize` methods should be implemented. - * */ #include <ostream> @@ -110,7 +109,6 @@ using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Ar * - `DoubleValue`: contains a double precision floating point number. * - `DictionaryValue`: represents an object (key value pairs where keys are strings and values can * be of different types. - * */ class Value { private: diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index 4c5cc3fd9c5..61a21fd8bbf 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -157,8 +157,8 @@ size_t BLI_strnlen_utf8(const char *strc, size_t maxlen) ATTR_NONNULL(1) ATTR_WA size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, size_t maxncpy) ATTR_NONNULL(1, 2); -size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst, - const char *__restrict src, +size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w, + const char *__restrict src_c, size_t maxncpy) ATTR_NONNULL(1, 2); /** @@ -174,17 +174,17 @@ int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NON size_t BLI_str_partition_utf8(const char *str, const unsigned int delim[], - const char **sep, - const char **suf) ATTR_NONNULL(1, 2, 3, 4); + const char **r_sep, + const char **r_suf) ATTR_NONNULL(1, 2, 3, 4); size_t BLI_str_rpartition_utf8(const char *str, const unsigned int delim[], - const char **sep, - const char **suf) ATTR_NONNULL(1, 2, 3, 4); + const char **r_sep, + const char **r_suf) ATTR_NONNULL(1, 2, 3, 4); size_t BLI_str_partition_ex_utf8(const char *str, const char *end, const unsigned int delim[], - const char **sep, - const char **suf, + const char **r_sep, + const char **r_suf, bool from_right) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3, 4, 5); int BLI_str_utf8_offset_to_index(const char *str, int offset) ATTR_WARN_UNUSED_RESULT diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index d39a586206f..78455c44fe1 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -1,6 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright 2006 Blender Foundation. All rights reserved. +if(HAVE_EXECINFO_H) + add_definitions(-DHAVE_EXECINFO_H) +endif() + set(INC . # ../blenkernel # don't add this back! diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c index f780d520301..b03efd2b8a2 100644 --- a/source/blender/blenlib/intern/BLI_memblock.c +++ b/source/blender/blenlib/intern/BLI_memblock.c @@ -5,7 +5,6 @@ * \ingroup bli * * Dead simple, fast memory allocator for allocating many elements of the same size. - * */ #include <stdlib.h> diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c index 78f5088e8b1..d55a4a8c9ff 100644 --- a/source/blender/blenlib/intern/boxpack_2d.c +++ b/source/blender/blenlib/intern/boxpack_2d.c @@ -712,7 +712,6 @@ void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase * # Box * Small # # Box * # * # * # # * # * ################### ################### - * */ int area_hsplit_large = space->w * (space->h - box->h); int area_vsplit_large = (space->w - box->w) * space->h; diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index fcd017b3082..e96b12033a9 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -113,7 +113,6 @@ void copy_m4_m3(float m1[4][4], const float m2[3][3]) /* no clear */ m1[2][1] = m2[2][1]; m1[2][2] = m2[2][2]; - /* Reevan's Bugfix */ m1[0][3] = 0.0f; m1[1][3] = 0.0f; m1[2][3] = 0.0f; @@ -787,14 +786,14 @@ void mul_m2_v2(const float mat[2][2], float vec[2]) mul_v2_m2v2(vec, mat, vec); } -void mul_mat3_m4_v3(const float M[4][4], float r[3]) +void mul_mat3_m4_v3(const float mat[4][4], float r[3]) { const float x = r[0]; const float y = r[1]; - r[0] = x * M[0][0] + y * M[1][0] + M[2][0] * r[2]; - r[1] = x * M[0][1] + y * M[1][1] + M[2][1] * r[2]; - r[2] = x * M[0][2] + y * M[1][2] + M[2][2] * r[2]; + r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * r[2]; + r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * r[2]; + r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * r[2]; } void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3]) @@ -1116,32 +1115,32 @@ double determinant_m3_array_db(const double m[3][3]) m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); } -bool invert_m2_m2(float m1[2][2], const float m2[2][2]) +bool invert_m2_m2(float inverse[2][2], const float mat[2][2]) { - adjoint_m2_m2(m1, m2); - float det = determinant_m2(m2[0][0], m2[1][0], m2[0][1], m2[1][1]); + adjoint_m2_m2(inverse, mat); + float det = determinant_m2(mat[0][0], mat[1][0], mat[0][1], mat[1][1]); bool success = (det != 0.0f); if (success) { - m1[0][0] /= det; - m1[1][0] /= det; - m1[0][1] /= det; - m1[1][1] /= det; + inverse[0][0] /= det; + inverse[1][0] /= det; + inverse[0][1] /= det; + inverse[1][1] /= det; } return success; } -bool invert_m3_ex(float m[3][3], const float epsilon) +bool invert_m3_ex(float mat[3][3], const float epsilon) { - float tmp[3][3]; - const bool success = invert_m3_m3_ex(tmp, m, epsilon); + float mat_tmp[3][3]; + const bool success = invert_m3_m3_ex(mat_tmp, mat, epsilon); - copy_m3_m3(m, tmp); + copy_m3_m3(mat, mat_tmp); return success; } -bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon) +bool invert_m3_m3_ex(float inverse[3][3], const float mat[3][3], const float epsilon) { float det; int a, b; @@ -1150,10 +1149,10 @@ bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon) BLI_assert(epsilon >= 0.0f); /* calc adjoint */ - adjoint_m3_m3(m1, m2); + adjoint_m3_m3(inverse, mat); /* then determinant old matrix! */ - det = determinant_m3_array(m2); + det = determinant_m3_array(mat); success = (fabsf(det) > epsilon); @@ -1161,33 +1160,33 @@ bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon) det = 1.0f / det; for (a = 0; a < 3; a++) { for (b = 0; b < 3; b++) { - m1[a][b] *= det; + inverse[a][b] *= det; } } } return success; } -bool invert_m3(float m[3][3]) +bool invert_m3(float mat[3][3]) { - float tmp[3][3]; - const bool success = invert_m3_m3(tmp, m); + float mat_tmp[3][3]; + const bool success = invert_m3_m3(mat_tmp, mat); - copy_m3_m3(m, tmp); + copy_m3_m3(mat, mat_tmp); return success; } -bool invert_m3_m3(float m1[3][3], const float m2[3][3]) +bool invert_m3_m3(float inverse[3][3], const float mat[3][3]) { float det; int a, b; bool success; /* calc adjoint */ - adjoint_m3_m3(m1, m2); + adjoint_m3_m3(inverse, mat); /* then determinant old matrix! */ - det = determinant_m3_array(m2); + det = determinant_m3_array(mat); success = (det != 0.0f); @@ -1195,7 +1194,7 @@ bool invert_m3_m3(float m1[3][3], const float m2[3][3]) det = 1.0f / det; for (a = 0; a < 3; a++) { for (b = 0; b < 3; b++) { - m1[a][b] *= det; + inverse[a][b] *= det; } } } @@ -1203,12 +1202,12 @@ bool invert_m3_m3(float m1[3][3], const float m2[3][3]) return success; } -bool invert_m4(float m[4][4]) +bool invert_m4(float mat[4][4]) { - float tmp[4][4]; - const bool success = invert_m4_m4(tmp, m); + float mat_tmp[4][4]; + const bool success = invert_m4_m4(mat_tmp, mat); - copy_m4_m4(m, tmp); + copy_m4_m4(mat, mat_tmp); return success; } @@ -2191,11 +2190,11 @@ float mat4_to_scale(const float mat[4][4]) return len_v3(unit_vec); } -float mat4_to_xy_scale(const float M[4][4]) +float mat4_to_xy_scale(const float mat[4][4]) { /* unit length vector in xy plane */ float unit_vec[3] = {(float)M_SQRT1_2, (float)M_SQRT1_2, 0.0f}; - mul_mat3_m4_v3(M, unit_vec); + mul_mat3_m4_v3(mat, unit_vec); return len_v3(unit_vec); } @@ -2240,12 +2239,6 @@ void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]) copy_m3_m4(mat3, wmat); normalize_m3_m3(mat3_n, mat3); - /* So scale doesn't interfere with rotation T24291. */ - /* FIXME: this is a workaround for negative matrix not working for rotation conversion. */ - if (is_negative_m3(mat3)) { - negate_m3(mat3_n); - } - mat3_normalized_to_quat(quat, mat3_n); copy_v3_v3(loc, wmat[3]); } @@ -2254,7 +2247,7 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat { float rot[3][3]; mat4_to_loc_rot_size(loc, rot, size, wmat); - mat3_normalized_to_quat(quat, rot); + mat3_normalized_to_quat_fast(quat, rot); } /** @@ -2393,8 +2386,8 @@ void blend_m3_m3m3(float out[3][3], mat3_to_rot_size(drot, dscale, dst); mat3_to_rot_size(srot, sscale, src); - mat3_normalized_to_quat(dquat, drot); - mat3_normalized_to_quat(squat, srot); + mat3_normalized_to_quat_fast(dquat, drot); + mat3_normalized_to_quat_fast(squat, srot); /* do blending */ interp_qt_qtqt(fquat, dquat, squat, srcweight); @@ -2419,8 +2412,8 @@ void blend_m4_m4m4(float out[4][4], mat4_to_loc_rot_size(dloc, drot, dscale, dst); mat4_to_loc_rot_size(sloc, srot, sscale, src); - mat3_normalized_to_quat(dquat, drot); - mat3_normalized_to_quat(squat, srot); + mat3_normalized_to_quat_fast(dquat, drot); + mat3_normalized_to_quat_fast(squat, srot); /* do blending */ interp_v3_v3v3(floc, dloc, sloc, srcweight); @@ -2456,11 +2449,11 @@ void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], con * Note that a flip of two axes is just a rotation of 180 degrees around the third axis, and * three flipped axes are just an 180 degree rotation + a single axis flip. It is thus sufficient * to solve this problem for single axis flips. */ - if (determinant_m3_array(U_A) < 0) { + if (is_negative_m3(U_A)) { mul_m3_fl(U_A, -1.0f); mul_m3_fl(P_A, -1.0f); } - if (determinant_m3_array(U_B) < 0) { + if (is_negative_m3(U_B)) { mul_m3_fl(U_B, -1.0f); mul_m3_fl(P_B, -1.0f); } @@ -2501,16 +2494,14 @@ void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], con bool is_negative_m3(const float mat[3][3]) { - float vec[3]; - cross_v3_v3v3(vec, mat[0], mat[1]); - return (dot_v3v3(vec, mat[2]) < 0.0f); + return determinant_m3_array(mat) < 0.0f; } bool is_negative_m4(const float mat[4][4]) { - float vec[3]; - cross_v3_v3v3(vec, mat[0], mat[1]); - return (dot_v3v3(vec, mat[2]) < 0.0f); + /* Don't use #determinant_m4 as only the 3x3 components are needed + * when the matrix is used as a transformation to represent location/scale/rotation. */ + return determinant_m4_mat3_array(mat) < 0.0f; } bool is_zero_m3(const float mat[3][3]) @@ -2568,11 +2559,8 @@ void loc_eul_size_to_mat4(float R[4][4], R[3][2] = loc[2]; } -void loc_eulO_size_to_mat4(float R[4][4], - const float loc[3], - const float eul[3], - const float size[3], - const short rotOrder) +void loc_eulO_size_to_mat4( + float R[4][4], const float loc[3], const float eul[3], const float size[3], const short order) { float rmat[3][3], smat[3][3], tmat[3][3]; @@ -2580,7 +2568,7 @@ void loc_eulO_size_to_mat4(float R[4][4], unit_m4(R); /* Make rotation + scaling part. */ - eulO_to_mat3(rmat, eul, rotOrder); + eulO_to_mat3(rmat, eul, order); size_to_mat3(smat, size); mul_m3_m3m3(tmat, rmat, smat); @@ -3082,14 +3070,14 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4]) } } -void pseudoinverse_m4_m4(float Ainv[4][4], const float A_[4][4], float epsilon) +void pseudoinverse_m4_m4(float inverse[4][4], const float mat[4][4], float epsilon) { /* compute Moore-Penrose pseudo inverse of matrix, singular values * below epsilon are ignored for stability (truncated SVD) */ float A[4][4], V[4][4], W[4], Wm[4][4], U[4][4]; int i; - transpose_m4_m4(A, A_); + transpose_m4_m4(A, mat); svd_m4(V, W, U, A); transpose_m4(U); transpose_m4(V); @@ -3101,18 +3089,18 @@ void pseudoinverse_m4_m4(float Ainv[4][4], const float A_[4][4], float epsilon) transpose_m4(V); - mul_m4_series(Ainv, U, Wm, V); + mul_m4_series(inverse, U, Wm, V); } -void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon) +void pseudoinverse_m3_m3(float inverse[3][3], const float mat[3][3], float epsilon) { /* try regular inverse when possible, otherwise fall back to slow svd */ - if (!invert_m3_m3(Ainv, A)) { - float tmp[4][4], tmpinv[4][4]; + if (!invert_m3_m3(inverse, mat)) { + float mat_tmp[4][4], tmpinv[4][4]; - copy_m4_m3(tmp, A); - pseudoinverse_m4_m4(tmpinv, tmp, epsilon); - copy_m3_m4(Ainv, tmpinv); + copy_m4_m3(mat_tmp, mat); + pseudoinverse_m4_m4(tmpinv, mat_tmp, epsilon); + copy_m3_m4(inverse, tmpinv); } } @@ -3122,22 +3110,22 @@ bool has_zero_axis_m4(const float matrix[4][4]) len_squared_v3(matrix[2]) < FLT_EPSILON; } -void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]) +void invert_m4_m4_safe(float inverse[4][4], const float mat[4][4]) { - if (!invert_m4_m4(Ainv, A)) { - float Atemp[4][4]; + if (!invert_m4_m4(inverse, mat)) { + float mat_tmp[4][4]; - copy_m4_m4(Atemp, A); + copy_m4_m4(mat_tmp, mat); /* Matrix is degenerate (e.g. 0 scale on some axis), ideally we should * never be in this situation, but try to invert it anyway with tweak. */ - Atemp[0][0] += 1e-8f; - Atemp[1][1] += 1e-8f; - Atemp[2][2] += 1e-8f; + mat_tmp[0][0] += 1e-8f; + mat_tmp[1][1] += 1e-8f; + mat_tmp[2][2] += 1e-8f; - if (!invert_m4_m4(Ainv, Atemp)) { - unit_m4(Ainv); + if (!invert_m4_m4(inverse, mat_tmp)) { + unit_m4(inverse); } } } @@ -3157,24 +3145,24 @@ void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]) * where we want to specify the length of the degenerate axes. * \{ */ -void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]) +void invert_m4_m4_safe_ortho(float inverse[4][4], const float mat[4][4]) { - if (UNLIKELY(!invert_m4_m4(Ainv, A))) { - float Atemp[4][4]; - copy_m4_m4(Atemp, A); - if (UNLIKELY(!(orthogonalize_m4_zero_axes(Atemp, 1.0f) && invert_m4_m4(Ainv, Atemp)))) { - unit_m4(Ainv); + if (UNLIKELY(!invert_m4_m4(inverse, mat))) { + float mat_tmp[4][4]; + copy_m4_m4(mat_tmp, mat); + if (UNLIKELY(!(orthogonalize_m4_zero_axes(mat_tmp, 1.0f) && invert_m4_m4(inverse, mat_tmp)))) { + unit_m4(inverse); } } } -void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]) +void invert_m3_m3_safe_ortho(float inverse[3][3], const float mat[3][3]) { - if (UNLIKELY(!invert_m3_m3(Ainv, A))) { - float Atemp[3][3]; - copy_m3_m3(Atemp, A); - if (UNLIKELY(!(orthogonalize_m3_zero_axes(Atemp, 1.0f) && invert_m3_m3(Ainv, Atemp)))) { - unit_m3(Ainv); + if (UNLIKELY(!invert_m3_m3(inverse, mat))) { + float mat_tmp[3][3]; + copy_m3_m3(mat_tmp, mat); + if (UNLIKELY(!(orthogonalize_m3_zero_axes(mat_tmp, 1.0f) && invert_m3_m3(inverse, mat_tmp)))) { + unit_m3(inverse); } } } diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index 03275ce19b4..ae068e3fb19 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -176,7 +176,7 @@ void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]) } } -/* skip error check, currently only needed by mat3_to_quat_is_ok */ +/* Skip error check, currently only needed by #mat3_to_quat_legacy. */ static void quat_to_mat3_no_error(float m[3][3], const float q[4]) { double q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc; @@ -269,9 +269,11 @@ void quat_to_mat4(float m[4][4], const float q[4]) m[3][3] = 1.0f; } -void mat3_normalized_to_quat(float q[4], const float mat[3][3]) +void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3]) { BLI_ASSERT_UNIT_M3(mat); + /* Caller must ensure matrices aren't negative for valid results, see: T24291, T94231. */ + BLI_assert(!is_negative_m3(mat)); /* Check the trace of the matrix - bad precision if close to -1. */ const float trace = mat[0][0] + mat[1][1] + mat[2][2]; @@ -332,34 +334,54 @@ void mat3_normalized_to_quat(float q[4], const float mat[3][3]) normalize_qt(q); } -void mat3_to_quat(float q[4], const float m[3][3]) -{ - float unit_mat[3][3]; - /* work on a copy */ - /* this is needed AND a 'normalize_qt' in the end */ - normalize_m3_m3(unit_mat, m); - mat3_normalized_to_quat(q, unit_mat); +static void mat3_normalized_to_quat_with_checks(float q[4], float mat[3][3]) +{ + const float det = determinant_m3_array(mat); + if (UNLIKELY(!isfinite(det))) { + unit_m3(mat); + } + else if (UNLIKELY(det < 0.0f)) { + negate_m3(mat); + } + mat3_normalized_to_quat_fast(q, mat); } -void mat4_normalized_to_quat(float q[4], const float m[4][4]) +void mat3_normalized_to_quat(float q[4], const float mat[3][3]) { - float mat3[3][3]; + float unit_mat_abs[3][3]; + copy_m3_m3(unit_mat_abs, mat); + mat3_normalized_to_quat_with_checks(q, unit_mat_abs); +} - copy_m3_m4(mat3, m); - mat3_normalized_to_quat(q, mat3); +void mat3_to_quat(float q[4], const float mat[3][3]) +{ + float unit_mat_abs[3][3]; + normalize_m3_m3(unit_mat_abs, mat); + mat3_normalized_to_quat_with_checks(q, unit_mat_abs); } -void mat4_to_quat(float q[4], const float m[4][4]) +void mat4_normalized_to_quat(float q[4], const float mat[4][4]) { - float mat3[3][3]; + float unit_mat_abs[3][3]; + copy_m3_m4(unit_mat_abs, mat); + mat3_normalized_to_quat_with_checks(q, unit_mat_abs); +} - copy_m3_m4(mat3, m); - mat3_to_quat(q, mat3); +void mat4_to_quat(float q[4], const float mat[4][4]) +{ + float unit_mat_abs[3][3]; + copy_m3_m4(unit_mat_abs, mat); + normalize_m3(unit_mat_abs); + mat3_normalized_to_quat_with_checks(q, unit_mat_abs); } -void mat3_to_quat_is_ok(float q[4], const float wmat[3][3]) +void mat3_to_quat_legacy(float q[4], const float wmat[3][3]) { + /* Legacy version of #mat3_to_quat which has slightly different behavior. + * Keep for particle-system & boids since replacing this will make subtle changes + * that impact hair in existing files. See: D15772. */ + float mat[3][3], matr[3][3], matn[3][3], q1[4], q2[4], angle, si, co, nor[3]; /* work on a copy */ @@ -498,7 +520,10 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q mul_qt_qtqt(q, tquat, q2); } -float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4]) +float quat_split_swing_and_twist(const float q_in[4], + const int axis, + float r_swing[4], + float r_twist[4]) { BLI_assert(axis >= 0 && axis <= 2); @@ -915,107 +940,63 @@ float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[ return len; } -void sin_cos_from_fraction(int numerator, const int denominator, float *r_sin, float *r_cos) +void sin_cos_from_fraction(int numerator, int denominator, float *r_sin, float *r_cos) { - /* By default, creating an circle from an integer: calling #sinf & #cosf on the fraction doesn't - * create symmetrical values (because of float imprecision). + /* By default, creating a circle from an integer: calling #sinf & #cosf on the fraction doesn't + * create symmetrical values (because floats can't represent Pi exactly). * Resolve this when the rotation is calculated from a fraction by mapping the `numerator` * to lower values so X/Y values for points around a circle are exactly symmetrical, see T87779. * - * - Numbers divisible by 4 are mapped to the lower 8th (8 axis symmetry). - * - Even numbers are mapped to the lower quarter (4 axis symmetry). - * - Odd numbers are mapped to the lower half (1 axis symmetry). + * Multiply both the `numerator` and `denominator` by eight to ensure we can divide the circle + * into 8 octants. For each octant, we then use symmetry and negation to bring the `numerator` + * closer to the origin where precision is highest. * - * Once the values are calculated, the are mapped back to their position in the circle - * using negation & swapping values. */ - - BLI_assert((numerator <= denominator) && (denominator > 0)); - enum { NEGATE_SIN_BIT = 0, NEGATE_COS_BIT = 1, SWAP_SIN_COS_BIT = 2 }; - enum { - NEGATE_SIN = (1 << NEGATE_SIN_BIT), - NEGATE_COS = (1 << NEGATE_COS_BIT), - SWAP_SIN_COS = (1 << SWAP_SIN_COS_BIT), - } xform = 0; - if ((denominator & 3) == 0) { - /* The denominator divides by 4, determine the quadrant then further refine the upper 8th. */ - const int denominator_4 = denominator / 4; - if (numerator < denominator_4) { - /* Fall through. */ - } - else { - if (numerator < denominator_4 * 2) { - numerator -= denominator_4; - xform = NEGATE_SIN | SWAP_SIN_COS; - } - else if (numerator == denominator_4 * 2) { - numerator = 0; - xform = NEGATE_COS; - } - else if (numerator < denominator_4 * 3) { - numerator -= denominator_4 * 2; - xform = NEGATE_SIN | NEGATE_COS; - } - else if (numerator == denominator_4 * 3) { - numerator = 0; - xform = NEGATE_COS | SWAP_SIN_COS; - } - else { - numerator -= denominator_4 * 3; - xform = NEGATE_COS | SWAP_SIN_COS; - } - } - /* Further increase accuracy by using the range of the upper 8th. */ - const int numerator_test = denominator_4 - numerator; - if (numerator_test < numerator) { - numerator = numerator_test; - xform ^= SWAP_SIN_COS; - /* Swap #NEGATE_SIN, #NEGATE_COS flags. */ - xform = (xform & (uint)(~(NEGATE_SIN | NEGATE_COS))) | - (((xform & NEGATE_SIN) >> NEGATE_SIN_BIT) << NEGATE_COS_BIT) | - (((xform & NEGATE_COS) >> NEGATE_COS_BIT) << NEGATE_SIN_BIT); - } - } - else if ((denominator & 1) == 0) { - /* The denominator divides by 2, determine the quadrant then further refine the upper 4th. */ - const int denominator_2 = denominator / 2; - if (numerator < denominator_2) { - /* Fall through. */ - } - else if (numerator == denominator_2) { - numerator = 0; - xform = NEGATE_COS; - } - else { - numerator -= denominator_2; - xform = NEGATE_SIN | NEGATE_COS; - } - /* Further increase accuracy by using the range of the upper 4th. */ - const int numerator_test = denominator_2 - numerator; - if (numerator_test < numerator) { - numerator = numerator_test; - xform ^= NEGATE_COS; - } - } - else { - /* The denominator is an odd number, only refine the upper half. */ - const int numerator_test = denominator - numerator; - if (numerator_test < numerator) { - numerator = numerator_test; - xform ^= NEGATE_SIN; - } + * Cases 2, 4, 5 and 7, use the trigonometric identity sin(-x) == -sin(x). + * Cases 1, 2, 5 and 6, swap the pointers `r_sin` and `r_cos`. + */ + BLI_assert(0 <= numerator); + BLI_assert(numerator <= denominator); + BLI_assert(denominator > 0); + + numerator *= 8; /* Multiply numerator the same as denominator. */ + const int octant = numerator / denominator; /* Determine the octant. */ + denominator *= 8; /* Ensure denominator is a multiple of eight. */ + float cos_sign = 1.0f; /* Either 1.0f or -1.0f. */ + + switch (octant) { + case 0: + /* Primary octant, nothing to do. */ + break; + case 1: + case 2: + numerator = (denominator / 4) - numerator; + SWAP(float *, r_sin, r_cos); + break; + case 3: + case 4: + numerator = (denominator / 2) - numerator; + cos_sign = -1.0f; + break; + case 5: + case 6: + numerator = numerator - (denominator * 3 / 4); + SWAP(float *, r_sin, r_cos); + cos_sign = -1.0f; + break; + case 7: + numerator = numerator - denominator; + break; + default: + BLI_assert_unreachable(); } - const float phi = (float)(2.0 * M_PI) * ((float)numerator / (float)denominator); - const float sin_phi = sinf(phi) * ((xform & NEGATE_SIN) ? -1.0f : 1.0f); - const float cos_phi = cosf(phi) * ((xform & NEGATE_COS) ? -1.0f : 1.0f); - if ((xform & SWAP_SIN_COS) == 0) { - *r_sin = sin_phi; - *r_cos = cos_phi; - } - else { - *r_sin = cos_phi; - *r_cos = sin_phi; - } + BLI_assert(-denominator / 4 <= numerator); /* Numerator may be negative. */ + BLI_assert(numerator <= denominator / 4); + BLI_assert(cos_sign == -1.0f || cos_sign == 1.0f); + + const float angle = (float)(2.0 * M_PI) * ((float)numerator / (float)denominator); + *r_sin = sinf(angle); + *r_cos = cosf(angle) * cos_sign; } void print_qt(const char *str, const float q[4]) @@ -1425,10 +1406,10 @@ void mat4_normalized_to_eul(float eul[3], const float m[4][4]) copy_m3_m4(mat3, m); mat3_normalized_to_eul(eul, mat3); } -void mat4_to_eul(float eul[3], const float m[4][4]) +void mat4_to_eul(float eul[3], const float mat[4][4]) { float mat3[3][3]; - copy_m3_m4(mat3, m); + copy_m3_m4(mat3, mat); mat3_to_eul(eul, mat3); } @@ -1463,7 +1444,7 @@ void eul_to_quat(float quat[4], const float eul[3]) quat[3] = cj * cs - sj * sc; } -void rotate_eul(float beul[3], const char axis, const float ang) +void rotate_eul(float beul[3], const char axis, const float angle) { float eul[3], mat1[3][3], mat2[3][3], totmat[3][3]; @@ -1471,13 +1452,13 @@ void rotate_eul(float beul[3], const char axis, const float ang) eul[0] = eul[1] = eul[2] = 0.0f; if (axis == 'X') { - eul[0] = ang; + eul[0] = angle; } else if (axis == 'Y') { - eul[1] = ang; + eul[1] = angle; } else { - eul[2] = ang; + eul[2] = angle; } eul_to_mat3(mat1, eul); @@ -1833,23 +1814,23 @@ void mat3_to_compatible_eulO(float eul[3], void mat4_normalized_to_compatible_eulO(float eul[3], const float oldrot[3], const short order, - const float m[4][4]) + const float mat[4][4]) { float mat3[3][3]; /* for now, we'll just do this the slow way (i.e. copying matrices) */ - copy_m3_m4(mat3, m); + copy_m3_m4(mat3, mat); mat3_normalized_to_compatible_eulO(eul, oldrot, order, mat3); } void mat4_to_compatible_eulO(float eul[3], const float oldrot[3], const short order, - const float m[4][4]) + const float mat[4][4]) { float mat3[3][3]; /* for now, we'll just do this the slow way (i.e. copying matrices) */ - copy_m3_m4(mat3, m); + copy_m3_m4(mat3, mat); normalize_m3(mat3); mat3_normalized_to_compatible_eulO(eul, oldrot, order, mat3); } @@ -1868,7 +1849,7 @@ void quat_to_compatible_eulO(float eul[3], /* rotate the given euler by the given angle on the specified axis */ /* NOTE: is this safe to do with different axis orders? */ -void rotate_eulO(float beul[3], const short order, char axis, float ang) +void rotate_eulO(float beul[3], const short order, const char axis, const float angle) { float eul[3], mat1[3][3], mat2[3][3], totmat[3][3]; @@ -1877,13 +1858,13 @@ void rotate_eulO(float beul[3], const short order, char axis, float ang) zero_v3(eul); if (axis == 'X') { - eul[0] = ang; + eul[0] = angle; } else if (axis == 'Y') { - eul[1] = ang; + eul[1] = angle; } else { - eul[2] = ang; + eul[2] = angle; } eulO_to_mat3(mat1, eul, order); diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index c39a2b5a27e..3ec7c3f9804 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -1125,7 +1125,7 @@ float BLI_noise_cell(float x, float y, float z) return (2.0f * BLI_cellNoiseU(x, y, z) - 1.0f); } -void BLI_noise_cell_v3(float x, float y, float z, float ca[3]) +void BLI_noise_cell_v3(float x, float y, float z, float r_ca[3]) { /* avoid precision issues on unit coordinates */ x = (x + 0.000001f) * 1.00001f; @@ -1136,9 +1136,9 @@ void BLI_noise_cell_v3(float x, float y, float z, float ca[3]) int yi = (int)(floor(y)); int zi = (int)(floor(z)); const float *p = HASHPNT(xi, yi, zi); - ca[0] = p[0]; - ca[1] = p[1]; - ca[2] = p[2]; + r_ca[0] = p[0]; + r_ca[1] = p[1]; + r_ca[2] = p[2]; } /** \} */ diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc index a514c9e5183..8a073239b31 100644 --- a/source/blender/blenlib/intern/noise.cc +++ b/source/blender/blenlib/intern/noise.cc @@ -263,7 +263,6 @@ BLI_INLINE float mix(float v0, float v1, float x) * + + | * @ + + + + @ @------> x * v0 v1 - * */ BLI_INLINE float mix(float v0, float v1, float v2, float v3, float x, float y) { @@ -809,15 +808,14 @@ float musgrave_hybrid_multi_fractal(const float co, { float p = co; const float pwHL = std::pow(lacunarity, -H); - float pwr = pwHL; - float value = perlin_signed(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0f; + float value = 0.0f; + float weight = 1.0f; const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f); - for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + for (int i = 0; (weight > 0.001f) && (i < (int)octaves); i++) { if (weight > 1.0f) { weight = 1.0f; } @@ -830,8 +828,12 @@ float musgrave_hybrid_multi_fractal(const float co, } const float rmd = octaves - floorf(octaves); - if (rmd != 0.0f) { - value += rmd * ((perlin_signed(p) + offset) * pwr); + if ((rmd != 0.0f) && (weight > 0.001f)) { + if (weight > 1.0f) { + weight = 1.0f; + } + float signal = (perlin_signed(p) + offset) * pwr; + value += rmd * weight * signal; } return value; @@ -961,15 +963,14 @@ float musgrave_hybrid_multi_fractal(const float2 co, { float2 p = co; const float pwHL = std::pow(lacunarity, -H); - float pwr = pwHL; - float value = perlin_signed(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0f; + float value = 0.0f; + float weight = 1.0f; const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f); - for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + for (int i = 0; (weight > 0.001f) && (i < (int)octaves); i++) { if (weight > 1.0f) { weight = 1.0f; } @@ -982,8 +983,12 @@ float musgrave_hybrid_multi_fractal(const float2 co, } const float rmd = octaves - floorf(octaves); - if (rmd != 0.0f) { - value += rmd * ((perlin_signed(p) + offset) * pwr); + if ((rmd != 0.0f) && (weight > 0.001f)) { + if (weight > 1.0f) { + weight = 1.0f; + } + float signal = (perlin_signed(p) + offset) * pwr; + value += rmd * weight * signal; } return value; @@ -1115,15 +1120,14 @@ float musgrave_hybrid_multi_fractal(const float3 co, { float3 p = co; const float pwHL = std::pow(lacunarity, -H); - float pwr = pwHL; - float value = perlin_signed(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0f; + float value = 0.0f; + float weight = 1.0f; const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f); - for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + for (int i = 0; (weight > 0.001f) && (i < (int)octaves); i++) { if (weight > 1.0f) { weight = 1.0f; } @@ -1136,8 +1140,12 @@ float musgrave_hybrid_multi_fractal(const float3 co, } const float rmd = octaves - floorf(octaves); - if (rmd != 0.0f) { - value += rmd * ((perlin_signed(p) + offset) * pwr); + if ((rmd != 0.0f) && (weight > 0.001f)) { + if (weight > 1.0f) { + weight = 1.0f; + } + float signal = (perlin_signed(p) + offset) * pwr; + value += rmd * weight * signal; } return value; @@ -1269,15 +1277,14 @@ float musgrave_hybrid_multi_fractal(const float4 co, { float4 p = co; const float pwHL = std::pow(lacunarity, -H); - float pwr = pwHL; - float value = perlin_signed(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0f; + float value = 0.0f; + float weight = 1.0f; const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f); - for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + for (int i = 0; (weight > 0.001f) && (i < (int)octaves); i++) { if (weight > 1.0f) { weight = 1.0f; } @@ -1290,8 +1297,12 @@ float musgrave_hybrid_multi_fractal(const float4 co, } const float rmd = octaves - floorf(octaves); - if (rmd != 0.0f) { - value += rmd * ((perlin_signed(p) + offset) * pwr); + if ((rmd != 0.0f) && (weight > 0.001f)) { + if (weight > 1.0f) { + weight = 1.0f; + } + float signal = (perlin_signed(p) + offset) * pwr; + value += rmd * weight * signal; } return value; diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 93045bd3680..17fb451e422 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -692,25 +692,25 @@ const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end) size_t BLI_str_partition_utf8(const char *str, const uint delim[], - const char **sep, - const char **suf) + const char **r_sep, + const char **r_suf) { - return BLI_str_partition_ex_utf8(str, NULL, delim, sep, suf, false); + return BLI_str_partition_ex_utf8(str, NULL, delim, r_sep, r_suf, false); } size_t BLI_str_rpartition_utf8(const char *str, const uint delim[], - const char **sep, - const char **suf) + const char **r_sep, + const char **r_suf) { - return BLI_str_partition_ex_utf8(str, NULL, delim, sep, suf, true); + return BLI_str_partition_ex_utf8(str, NULL, delim, r_sep, r_suf, true); } size_t BLI_str_partition_ex_utf8(const char *str, const char *end, const uint delim[], - const char **sep, - const char **suf, + const char **r_sep, + const char **r_suf, const bool from_right) { const size_t str_len = end ? (size_t)(end - str) : strlen(str); @@ -721,36 +721,32 @@ size_t BLI_str_partition_ex_utf8(const char *str, /* Note that here, we assume end points to a valid utf8 char! */ BLI_assert((end >= str) && (BLI_str_utf8_as_unicode(end) != BLI_UTF8_ERR)); - *suf = (char *)(str + str_len); - - size_t index; - for (*sep = (char *)(from_right ? BLI_str_find_prev_char_utf8(end, str) : str), index = 0; - from_right ? (*sep > str) : ((*sep < end) && (**sep != '\0')); - *sep = (char *)(from_right ? (str != *sep ? BLI_str_find_prev_char_utf8(*sep, str) : NULL) : - str + index)) { + char *suf = (char *)(str + str_len); + size_t index = 0; + for (char *sep = (char *)(from_right ? BLI_str_find_prev_char_utf8(end, str) : str); + from_right ? (sep > str) : ((sep < end) && (*sep != '\0')); + sep = (char *)(from_right ? (str != sep ? BLI_str_find_prev_char_utf8(sep, str) : NULL) : + str + index)) { size_t index_ofs = 0; - const uint c = BLI_str_utf8_as_unicode_step_or_error(*sep, (size_t)(end - *sep), &index_ofs); - index += index_ofs; - - if (c == BLI_UTF8_ERR) { - *suf = *sep = NULL; + const uint c = BLI_str_utf8_as_unicode_step_or_error(sep, (size_t)(end - sep), &index_ofs); + if (UNLIKELY(c == BLI_UTF8_ERR)) { break; } + index += index_ofs; for (const uint *d = delim; *d != '\0'; d++) { if (*d == c) { - /* *suf is already correct in case from_right is true. */ - if (!from_right) { - *suf = (char *)(str + index); - } - return (size_t)(*sep - str); + /* `suf` is already correct in case from_right is true. */ + *r_sep = sep; + *r_suf = from_right ? suf : (char *)(str + index); + return (size_t)(sep - str); } } - *suf = *sep; /* Useful in 'from_right' case! */ + suf = sep; /* Useful in 'from_right' case! */ } - *suf = *sep = NULL; + *r_suf = *r_sep = NULL; return str_len; } @@ -790,9 +786,9 @@ int BLI_str_utf8_offset_to_column(const char *str, int offset) int BLI_str_utf8_offset_from_column(const char *str, int column) { - int offset = 0, pos = 0, col; + int offset = 0, pos = 0; while (*(str + offset) && pos < column) { - col = BLI_str_utf8_char_width_safe(str + offset); + const int col = BLI_str_utf8_char_width_safe(str + offset); if (pos + col > column) { break; } diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c index 35e26e0cb33..781b38f713a 100644 --- a/source/blender/blenlib/intern/system.c +++ b/source/blender/blenlib/intern/system.c @@ -21,7 +21,9 @@ # include "BLI_winstuff.h" #else -# include <execinfo.h> +# if defined(HAVE_EXECINFO_H) +# include <execinfo.h> +# endif # include <unistd.h> #endif @@ -61,9 +63,9 @@ int BLI_cpu_support_sse2(void) #if !defined(_MSC_VER) void BLI_system_backtrace(FILE *fp) { - /* ------------- */ - /* Linux / Apple */ -# if defined(__linux__) || defined(__APPLE__) + /* ----------------------- */ + /* If system as execinfo.h */ +# if defined(HAVE_EXECINFO_H) # define SIZE 100 void *buffer[SIZE]; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b880f0513b8..d178c8fcd4c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2631,9 +2631,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, else if (sl->spacetype == SPACE_OUTLINER) { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - space_outliner->search_tse.id = restore_pointer_by_name( - id_map, space_outliner->search_tse.id, USER_IGNORE); - if (space_outliner->treestore) { TreeStoreElem *tselem; BLI_mempool_iter iter; diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index ffa224ea9e0..cfdae2620d0 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -989,7 +989,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) int a, tot; /* shape keys are no longer applied to the mesh itself, but rather - * to the evaluated #Mesh / #DispList, so here we ensure that the basis + * to the evaluated #Mesh, so here we ensure that the basis * shape key is always set in the mesh coordinates. */ for (me = bmain->meshes.first; me; me = me->id.next) { if ((key = blo_do_versions_newlibadr(fd, lib, me->key)) && key->refkey) { diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index e1ceed82ba7..51063f47ef9 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -689,7 +689,6 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree) * a value of -1 just to be identified later in the versioning code: * * Average Operator : 2 -> -1 - * */ static void update_vector_math_node_operators_enum_mapping(bNodeTree *ntree) { @@ -867,7 +866,6 @@ static void update_mapping_node_fcurve_rna_path_callback(ID *UNUSED(id), * and check if they control a property of the node, if they do, we update * the path to be that of the corresponding socket in the node or the added * minimum/maximum node. - * */ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) { @@ -1057,7 +1055,6 @@ static void update_voronoi_node_fac_output(bNodeTree *ntree) * the inputs of the subtract node. * 6. The output of the subtract node is connected to the * appropriate sockets. - * */ static void update_voronoi_node_crackle(bNodeTree *ntree) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 1ec056a9f50..72337f98000 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -6,7 +6,6 @@ */ /** - * * FILE FORMAT * =========== * diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 0d1eeab8eec..0efa5f73ae4 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -111,7 +111,7 @@ set(SRC intern/bmesh_query.c intern/bmesh_query.h intern/bmesh_query_inline.h - intern/bmesh_query_uv.c + intern/bmesh_query_uv.cc intern/bmesh_query_uv.h intern/bmesh_structure.c intern/bmesh_structure.h diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c index e2436e53099..8ec7dc410d0 100644 --- a/source/blender/bmesh/intern/bmesh_delete.c +++ b/source/blender/bmesh/intern/bmesh_delete.c @@ -86,7 +86,6 @@ void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) { BMEdge *e; - BMFace *f; BMIter eiter; BMIter fiter; @@ -128,6 +127,7 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) case DEL_FACES: case DEL_FACES_KEEP_BOUNDARY: { /* go through and mark all edges and all verts of all faces for delete */ + BMFace *f; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { if (BMO_face_flag_test(bm, f, oflag)) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); @@ -257,8 +257,6 @@ void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype) void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type) { - BMEdge *e; - BMFace *f; BMIter eiter; BMIter fiter; @@ -271,6 +269,7 @@ void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type) } case DEL_EDGES: { /* flush down to vert */ + BMEdge *e; BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, hflag)) { BM_elem_flag_enable(e->v1, hflag); @@ -299,6 +298,8 @@ void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type) } case DEL_FACES: { /* go through and mark all edges and all verts of all faces for delete */ + BMFace *f; + BMEdge *e; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(f, hflag)) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index eadf87d7ebd..f9efbdd74d3 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -1274,10 +1274,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * need_hide_vert = true; } - if (cd_vert_bweight_offset != -1) { - mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset); - } - CustomData_from_bmesh_block(&bm->vdata, &me->vdata, eve->head.data, i); } bm->elem_index_dirty &= ~BM_VERT; diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h index e2871dc04d3..a04136afc1d 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.h +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h @@ -61,8 +61,8 @@ struct BMeshToMeshParams { bool active_shapekey_to_mvert; struct CustomData_MeshMasks cd_mask_extra; }; + /** - * * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set. */ void BM_mesh_bm_to_me(struct Main *bmain, diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index 85eadd3076a..9d690395d72 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -138,7 +138,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_ * +----------+ <-- This loop defines the face and vertex.. * l * </pre> - * */ BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_query_uv.c b/source/blender/bmesh/intern/bmesh_query_uv.cc index 1225543cd06..5a725407c6b 100644 --- a/source/blender/bmesh/intern/bmesh_query_uv.c +++ b/source/blender/bmesh/intern/bmesh_query_uv.cc @@ -6,9 +6,10 @@ #include "MEM_guardedalloc.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_linklist.h" #include "BLI_math.h" +#include "BLI_math_vec_types.hh" #include "BLI_utildefines_stack.h" #include "BKE_customdata.h" @@ -80,7 +81,7 @@ void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, zero_v2(r_cent); l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + const MLoopUV *luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); add_v2_v2(r_cent, luv->uv); } while ((l_iter = l_iter->next) != l_first); @@ -89,16 +90,16 @@ void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) { - float(*uvs)[2] = BLI_array_alloca(uvs, f->len); + blender::Array<blender::float2, BM_DEFAULT_NGON_STACK_SIZE> uvs(f->len); const BMLoop *l_iter; const BMLoop *l_first; int i = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); - copy_v2_v2(uvs[i++], luv->uv); + const MLoopUV *luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + uvs[i++] = luv->uv; } while ((l_iter = l_iter->next) != l_first); - return cross_poly_v2(uvs, f->len); + return cross_poly_v2(reinterpret_cast<const float(*)[2]>(uvs.data()), f->len); } void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd_loop_uv_offset) @@ -107,7 +108,7 @@ void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd const BMLoop *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + const MLoopUV *luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); minmax_v2v2_v2(min, max, luv->uv); } while ((l_iter = l_iter->next) != l_first); } @@ -118,7 +119,7 @@ void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop BMLoop *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); mul_m2_v2(matrix, luv->uv); } while ((l_iter = l_iter->next) != l_first); } @@ -126,12 +127,12 @@ void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) { BLI_assert(l_a->e == l_b->e); - MLoopUV *luv_a_curr = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset); - MLoopUV *luv_a_next = BM_ELEM_CD_GET_VOID_P(l_a->next, cd_loop_uv_offset); - MLoopUV *luv_b_curr = BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset); - MLoopUV *luv_b_next = BM_ELEM_CD_GET_VOID_P(l_b->next, cd_loop_uv_offset); + MLoopUV *luv_a_curr = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset); + MLoopUV *luv_a_next = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_a->next, cd_loop_uv_offset); + MLoopUV *luv_b_curr = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset); + MLoopUV *luv_b_next = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_b->next, cd_loop_uv_offset); if (l_a->v != l_b->v) { - SWAP(MLoopUV *, luv_b_curr, luv_b_next); + std::swap(luv_b_curr, luv_b_next); } return (equals_v2v2(luv_a_curr->uv, luv_b_curr->uv) && equals_v2v2(luv_a_next->uv, luv_b_next->uv)); @@ -140,8 +141,8 @@ bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_ bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) { BLI_assert(l_a->v == l_b->v); - const MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset); - const MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset); + const MLoopUV *luv_a = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset); + const MLoopUV *luv_b = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset); if (!equals_v2v2(luv_a->uv, luv_b->uv)) { return false; } @@ -160,8 +161,10 @@ bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int const BMLoop *l_other_b = BM_loop_other_vert_loop_by_edge(l_b, e); { - const MLoopUV *luv_other_a = BM_ELEM_CD_GET_VOID_P(l_other_a, cd_loop_uv_offset); - const MLoopUV *luv_other_b = BM_ELEM_CD_GET_VOID_P(l_other_b, cd_loop_uv_offset); + const MLoopUV *luv_other_a = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_other_a, + cd_loop_uv_offset); + const MLoopUV *luv_other_b = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_other_b, + cd_loop_uv_offset); if (!equals_v2v2(luv_other_a->uv, luv_other_b->uv)) { return false; } @@ -172,7 +175,7 @@ bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset) { - float(*projverts)[2] = BLI_array_alloca(projverts, f->len); + blender::Array<blender::float2, BM_DEFAULT_NGON_STACK_SIZE> projverts(f->len); BMLoop *l_iter; int i; @@ -180,8 +183,9 @@ bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int BLI_assert(BM_face_is_normal_valid(f)); for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) { - copy_v2_v2(projverts[i], BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset)); + projverts[i] = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; } - return isect_point_poly_v2(co, projverts, f->len, false); + return isect_point_poly_v2( + co, reinterpret_cast<const float(*)[2]>(projverts.data()), f->len, false); } diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index 6baaeb43f1a..7d340f02f2e 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -182,9 +182,8 @@ void bmesh_disk_edge_remove(BMEdge *e, BMVert *v) BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) { - BMEdge *e_iter, *e_first; - if (v1->e) { + BMEdge *e_iter, *e_first; e_first = e_iter = v1->e; do { diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c index ac88ffb9065..8112844fc8a 100644 --- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c +++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c @@ -24,7 +24,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const float no[3]) { float axis_mat[3][3]; - float z_prev, z_curr; + float z_prev; float delta_z = 0.0f; /* Newell's Method */ @@ -35,7 +35,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const f z_prev = dot_m3_v3_row_z(axis_mat, l_last->v->co); do { - z_curr = dot_m3_v3_row_z(axis_mat, l_iter->v->co); + const float z_curr = dot_m3_v3_row_z(axis_mat, l_iter->v->co); delta_z += fabsf(z_curr - z_prev); z_prev = z_curr; } while ((l_iter = l_iter->next) != l_term); diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index a809fe6ee3d..9dba48a8961 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -77,7 +77,6 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) * | . * | . * +........+ <-- starts out free standing. - * */ /* Here we check for consistency and create 2 edges */ diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c index 7ff3b9b072c..6622dbf7575 100644 --- a/source/blender/bmesh/operators/bmo_poke.c +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -52,8 +52,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) } BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { - BMFace *f_new; - float f_center[3], f_center_mean[3]; + float f_center[3]; BMVert *v_center = NULL; BMLoop *l_iter, *l_first; /* only interpolate the central loop from the face once, @@ -69,15 +68,6 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP); BMO_vert_flag_enable(bm, v_center, ELE_NEW); - if (cd_loop_mdisp_offset != -1) { - if (center_mode == BMOP_POKE_MEDIAN) { - copy_v3_v3(f_center_mean, f_center); - } - else { - BM_face_calc_center_median(f, f_center_mean); - } - } - /* handled by BM_loop_interp_from_face */ // BM_vert_interp_from_face(bm, v_center, f); @@ -92,8 +82,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { BMLoop *l_new; - - f_new = BM_face_create_quad_tri( + BMFace *f_new = BM_face_create_quad_tri( bm, l_iter->v, l_iter->next->v, v_center, NULL, f, BM_CREATE_NOP); l_new = BM_FACE_FIRST_LOOP(f_new); diff --git a/source/blender/bmesh/tools/bmesh_path_region_uv.c b/source/blender/bmesh/tools/bmesh_path_region_uv.c index 5c70f7fa5ec..56090ed9916 100644 --- a/source/blender/bmesh/tools/bmesh_path_region_uv.c +++ b/source/blender/bmesh/tools/bmesh_path_region_uv.c @@ -109,9 +109,10 @@ static bool bm_loop_region_test_chain(BMLoop *l, int *const depths[2], const int static LinkNode *mesh_calc_path_region_elem(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, - const uint cd_loop_uv_offset, + const int cd_loop_uv_offset, const char path_htype) { + BLI_assert(cd_loop_uv_offset >= 0); int ele_loops_len[2]; BMLoop **ele_loops[2]; @@ -397,7 +398,7 @@ static LinkNode *mesh_calc_path_region_elem(BMesh *bm, LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, - const uint cd_loop_uv_offset, + const int cd_loop_uv_offset, bool (*filter_fn)(BMLoop *, void *user_data), void *user_data) { @@ -426,7 +427,7 @@ LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm, LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, - const uint cd_loop_uv_offset, + const int cd_loop_uv_offset, bool (*filter_fn)(BMLoop *, void *user_data), void *user_data) { @@ -455,7 +456,7 @@ LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm, LinkNode *BM_mesh_calc_path_uv_region_face(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, - const uint cd_loop_uv_offset, + const int cd_loop_uv_offset, bool (*filter_fn)(BMFace *, void *user_data), void *user_data) { diff --git a/source/blender/bmesh/tools/bmesh_path_region_uv.h b/source/blender/bmesh/tools/bmesh_path_region_uv.h index fa1b2bfcf9b..f399395e051 100644 --- a/source/blender/bmesh/tools/bmesh_path_region_uv.h +++ b/source/blender/bmesh/tools/bmesh_path_region_uv.h @@ -9,7 +9,7 @@ struct LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, - uint cd_loop_uv_offset, + int cd_loop_uv_offset, bool (*filter_fn)(BMLoop *, void *user_data), void *user_data) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); @@ -17,7 +17,7 @@ struct LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm, struct LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, - uint cd_loop_uv_offset, + int cd_loop_uv_offset, bool (*filter_fn)(BMLoop *, void *user_data), void *user_data) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); @@ -25,7 +25,7 @@ struct LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm, struct LinkNode *BM_mesh_calc_path_uv_region_face(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, - uint cd_loop_uv_offset, + int cd_loop_uv_offset, bool (*filter_fn)(BMFace *, void *user_data), void *user_data) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); diff --git a/source/blender/bmesh/tools/bmesh_path_uv.c b/source/blender/bmesh/tools/bmesh_path_uv.c index 3d736cdc3b8..6531677fce6 100644 --- a/source/blender/bmesh/tools/bmesh_path_uv.c +++ b/source/blender/bmesh/tools/bmesh_path_uv.c @@ -65,7 +65,7 @@ static void verttag_add_adjacent_uv(HeapSimple *heap, const struct BMCalcPathUVParams *params) { BLI_assert(params->aspect_y != 0.0f); - const uint cd_loop_uv_offset = params->cd_loop_uv_offset; + const int cd_loop_uv_offset = params->cd_loop_uv_offset; const int l_a_index = BM_elem_index_get(l_a); const MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset); const float uv_a[2] = {luv_a->uv[0], luv_a->uv[1] / params->aspect_y}; @@ -225,7 +225,7 @@ static void edgetag_add_adjacent_uv(HeapSimple *heap, const struct BMCalcPathUVParams *params) { BLI_assert(params->aspect_y != 0.0f); - const uint cd_loop_uv_offset = params->cd_loop_uv_offset; + const int cd_loop_uv_offset = params->cd_loop_uv_offset; BMLoop *l_a_verts[2] = {l_a, l_a->next}; const int l_a_index = BM_elem_index_get(l_a); @@ -462,7 +462,7 @@ static void facetag_add_adjacent_uv(HeapSimple *heap, const float aspect_v2[2], const struct BMCalcPathUVParams *params) { - const uint cd_loop_uv_offset = params->cd_loop_uv_offset; + const int cd_loop_uv_offset = params->cd_loop_uv_offset; const int f_a_index = BM_elem_index_get(f_a); /* Loop over faces of face, but do so by first looping over loops. */ diff --git a/source/blender/bmesh/tools/bmesh_path_uv.h b/source/blender/bmesh/tools/bmesh_path_uv.h index d7b5faa70e5..ebfedba70bb 100644 --- a/source/blender/bmesh/tools/bmesh_path_uv.h +++ b/source/blender/bmesh/tools/bmesh_path_uv.h @@ -9,7 +9,7 @@ struct BMCalcPathUVParams { uint use_topology_distance : 1; uint use_step_face : 1; - uint cd_loop_uv_offset; + int cd_loop_uv_offset; float aspect_y; }; diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index 0fdd7647f8d..fd53460f854 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -12,8 +12,8 @@ extern "C" { /* Keep ascii art. */ /* clang-format off */ + /** - * * \defgroup Model The data model of the compositor * \ingroup compositor * \defgroup Memory The memory management stuff diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cc b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc index 81fc638970f..7592b5120e6 100644 --- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cc +++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc @@ -23,7 +23,7 @@ void ChannelMatteNode::convert_to_operations(NodeConverter &converter, NodeOutput *output_socket_matte = this->get_output_socket(1); NodeOperation *convert = nullptr, *inv_convert = nullptr; - /* colorspace */ + /* color-space */ switch (node->custom1) { case CMP_NODE_CHANNEL_MATTE_CS_RGB: break; diff --git a/source/blender/compositor/nodes/COM_FilterNode.cc b/source/blender/compositor/nodes/COM_FilterNode.cc index f2efa8caefd..dce08b4cf2c 100644 --- a/source/blender/compositor/nodes/COM_FilterNode.cc +++ b/source/blender/compositor/nodes/COM_FilterNode.cc @@ -21,7 +21,7 @@ void FilterNode::convert_to_operations(NodeConverter &converter, ConvolutionFilterOperation *operation = nullptr; switch (this->get_bnode()->custom1) { - case CMP_FILT_SOFT: + case CMP_NODE_FILTER_SOFT: operation = new ConvolutionFilterOperation(); operation->set3x3Filter(1 / 16.0f, 2 / 16.0f, @@ -33,11 +33,11 @@ void FilterNode::convert_to_operations(NodeConverter &converter, 2 / 16.0f, 1 / 16.0f); break; - case CMP_FILT_SHARP_BOX: + case CMP_NODE_FILTER_SHARP_BOX: operation = new ConvolutionFilterOperation(); operation->set3x3Filter(-1, -1, -1, -1, 9, -1, -1, -1, -1); break; - case CMP_FILT_LAPLACE: + case CMP_NODE_FILTER_LAPLACE: operation = new ConvolutionEdgeFilterOperation(); operation->set3x3Filter(-1 / 8.0f, -1 / 8.0f, @@ -49,23 +49,23 @@ void FilterNode::convert_to_operations(NodeConverter &converter, -1 / 8.0f, -1 / 8.0f); break; - case CMP_FILT_SOBEL: + case CMP_NODE_FILTER_SOBEL: operation = new ConvolutionEdgeFilterOperation(); operation->set3x3Filter(1, 2, 1, 0, 0, 0, -1, -2, -1); break; - case CMP_FILT_PREWITT: + case CMP_NODE_FILTER_PREWITT: operation = new ConvolutionEdgeFilterOperation(); operation->set3x3Filter(1, 1, 1, 0, 0, 0, -1, -1, -1); break; - case CMP_FILT_KIRSCH: + case CMP_NODE_FILTER_KIRSCH: operation = new ConvolutionEdgeFilterOperation(); operation->set3x3Filter(5, 5, 5, -3, -3, -3, -2, -2, -2); break; - case CMP_FILT_SHADOW: + case CMP_NODE_FILTER_SHADOW: operation = new ConvolutionFilterOperation(); operation->set3x3Filter(1, 2, 1, 0, 1, 0, -1, -2, -1); break; - case CMP_FILT_SHARP_DIAMOND: + case CMP_NODE_FILTER_SHARP_DIAMOND: operation = new ConvolutionFilterOperation(); operation->set3x3Filter(0, -1, 0, -1, 5, -1, 0, -1, 0); break; diff --git a/source/blender/compositor/realtime_compositor/COM_domain.hh b/source/blender/compositor/realtime_compositor/COM_domain.hh index a4f9eb68db4..54d712f7578 100644 --- a/source/blender/compositor/realtime_compositor/COM_domain.hh +++ b/source/blender/compositor/realtime_compositor/COM_domain.hh @@ -149,7 +149,7 @@ class Domain { /* Transform the domain by the given transformation. This effectively pre-multiply the given * transformation by the current transformation of the domain. */ - void transform(const float3x3 &transformation); + void transform(const float3x3 &input_transformation); /* Returns a domain of size 1x1 and an identity transformation. */ static Domain identity(); diff --git a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc index a097c81a4c5..5749d8c5f2e 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc @@ -481,6 +481,10 @@ void ShaderOperation::generate_code_for_inputs(GPUMaterial *material, /* The attributes of the GPU material represents the inputs of the operation. */ ListBase attributes = GPU_material_attributes(material); + if (BLI_listbase_is_empty(&attributes)) { + return; + } + /* Add a texture sampler for each of the inputs with the same name as the attribute. */ LISTBASE_FOREACH (GPUMaterialAttribute *, attribute, &attributes) { shader_create_info.sampler(0, ImageType::FLOAT_2D, attribute->name, Frequency::BATCH); diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index ac6ab5c7666..201a534f535 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -101,7 +101,7 @@ typedef enum eDepsObjectComponentType { DEG_OB_COMP_ANIMATION, /* Transform Component (Parenting/Constraints) */ DEG_OB_COMP_TRANSFORM, - /* Geometry Component (#Mesh / #DispList). */ + /* Geometry Component (#Mesh / #Curves, etc.). */ DEG_OB_COMP_GEOMETRY, /* Evaluation-Related Outer Types (with Sub-data) */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index d6ee1286fc4..730096e3110 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2215,7 +2215,7 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key) * ========================== * * The evaluation of geometry on objects is as follows: - * - The actual evaluated of the derived geometry (e.g. Mesh, DispList) + * - The actual evaluated of the derived geometry (e.g. #Mesh, #Curves, etc.) * occurs in the Geometry component of the object which references this. * This includes modifiers, and the temporary "ubereval" for geometry. * Therefore, each user of a piece of shared geometry data ends up evaluating diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 171c9875e2a..2d2ee5dc4b4 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -153,10 +153,10 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data) if (dob->no_draw) { continue; } - if (obd->type == OB_MBALL) { + if (dob->ob_data && GS(dob->ob_data->name) == ID_MB) { continue; } - if (deg_object_hide_original(data->eval_mode, dob->ob, dob)) { + if (obd->type != OB_MBALL && deg_object_hide_original(data->eval_mode, dob->ob, dob)) { continue; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc index 7b6aec0a73c..a056ba1dfa7 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc @@ -69,6 +69,10 @@ void deg_evaluate_object_modifiers_mode_node_visibility(::Depsgraph *depsgraph, OperationNode *modifier_node = geometry_component->find_operation(OperationCode::MODIFIER, modifier->name); + BLI_assert_msg(modifier_node != nullptr, + "Modifier node in depsgraph is not found. Likely due to missing " + "DEG_relations_tag_update()."); + const bool modifier_enabled = modifier->mode & modifier_mode; const int mute_flag = modifier_enabled ? 0 : DEPSOP_FLAG_MUTE; if ((modifier_node->flag & DEPSOP_FLAG_MUTE) != mute_flag) { diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index 5b33528df33..db912ee3a82 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -64,7 +64,7 @@ enum class NodeType { ANIMATION, /* Transform Component (Parenting/Constraints) */ TRANSFORM, - /* Geometry Component (#Mesh / #DispList) */ + /* Geometry Component (#Mesh, #Curves, etc.) */ GEOMETRY, /* Sequencer Component (Scene Only) */ SEQUENCER, diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 391c3bb3512..684134609c9 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -28,7 +28,6 @@ set(INC ../../../intern/atomic ../../../intern/clog - ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/opensubdiv @@ -72,11 +71,9 @@ set(SRC intern/draw_attributes.cc intern/draw_cache_impl_curve.cc intern/draw_cache_impl_curves.cc - intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.cc - intern/draw_cache_impl_metaball.c intern/draw_cache_impl_particles.c intern/draw_cache_impl_pointcloud.cc intern/draw_cache_impl_subdivision.cc @@ -140,7 +137,9 @@ set(SRC engines/eevee_next/eevee_engine.cc engines/eevee_next/eevee_film.cc engines/eevee_next/eevee_instance.cc + engines/eevee_next/eevee_light.cc engines/eevee_next/eevee_material.cc + engines/eevee_next/eevee_hizbuffer.cc engines/eevee_next/eevee_motion_blur.cc engines/eevee_next/eevee_pipeline.cc engines/eevee_next/eevee_renderbuffers.cc @@ -391,6 +390,17 @@ 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_hiz_debug_frag.glsl + engines/eevee_next/shaders/eevee_hiz_update_comp.glsl + engines/eevee_next/shaders/eevee_light_culling_debug_frag.glsl + engines/eevee_next/shaders/eevee_light_culling_select_comp.glsl + engines/eevee_next/shaders/eevee_light_culling_sort_comp.glsl + engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl + engines/eevee_next/shaders/eevee_light_culling_zbin_comp.glsl + engines/eevee_next/shaders/eevee_light_eval_lib.glsl + engines/eevee_next/shaders/eevee_light_iter_lib.glsl + engines/eevee_next/shaders/eevee_light_lib.glsl + engines/eevee_next/shaders/eevee_ltc_lib.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 @@ -437,10 +447,12 @@ set(GLSL_SRC engines/workbench/workbench_shader_shared.h + intern/shaders/common_aabb_lib.glsl intern/shaders/common_attribute_lib.glsl intern/shaders/common_colormanagement_lib.glsl intern/shaders/common_debug_draw_lib.glsl intern/shaders/common_debug_print_lib.glsl + intern/shaders/common_debug_shape_lib.glsl intern/shaders/common_fullscreen_vert.glsl intern/shaders/common_fxaa_lib.glsl intern/shaders/common_globals_lib.glsl @@ -448,9 +460,11 @@ set(GLSL_SRC intern/shaders/common_hair_lib.glsl intern/shaders/common_hair_refine_comp.glsl intern/shaders/common_hair_refine_vert.glsl + intern/shaders/common_intersect_lib.glsl intern/shaders/common_math_geom_lib.glsl intern/shaders/common_math_lib.glsl intern/shaders/common_pointcloud_lib.glsl + intern/shaders/common_shape_lib.glsl intern/shaders/common_smaa_lib.glsl intern/shaders/common_subdiv_custom_data_interp_comp.glsl intern/shaders/common_subdiv_ibo_lines_comp.glsl diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 2f4a201637f..6ba71e2b2db 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -25,7 +25,6 @@ * they take into account to create the render passes. When accurate mode is off the number of * levels is used as the number of cryptomatte samples to take. When accuracy mode is on the number * of render samples is used. - * */ #include "DRW_engine.h" diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index ffe0863fb9f..f04405d7110 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -109,7 +109,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob) } if (DRW_object_is_renderable(ob) && (ob_visibility & OB_VISIBLE_SELF)) { - if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) { + if (ob->type == OB_MESH) { EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); } else if (ob->type == OB_CURVES) { diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index efd27c19654..94f29d64628 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -806,7 +806,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, !DRW_state_is_image_render(); /* First get materials for this mesh. */ - if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) { + if (ELEM(ob->type, OB_MESH, OB_SURF)) { const int materials_len = DRW_cache_object_material_count_get(ob); EeveeMaterialCache *matcache = BLI_array_alloca(matcache, materials_len); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 82944f237ea..c3b909f5fb9 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -224,7 +224,7 @@ void EEVEE_render_cache(void *vedata, } if (ob_visibility & OB_VISIBLE_SELF) { - if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) { + if (ob->type == OB_MESH) { EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); if (do_cryptomatte) { EEVEE_cryptomatte_cache_populate(data, sldata, ob); diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl index 688ae4915e1..7dec30a96b1 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl @@ -124,7 +124,7 @@ void dof_slight_focus_gather(float radius, out vec4 out_color, out float out_wei 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 > slight focus transitionning areas. */ + /* Fix weighting issues on perfectly focus > slight focus transitioning areas. */ if (abs(center_data.coc) < 0.5) { bg_col = center_data.color; bg_weight = 1.0; diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index 80c6b935187..488e229bff7 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -97,7 +97,7 @@ GlobalData init_globals(void) GlobalData surf; # if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) - surf.P = transform_direction(ViewMatrixInverse, viewCameraVec(viewPosition)); + surf.P = transform_direction(ViewMatrixInverse, -viewCameraVec(viewPosition)); surf.N = surf.Ng = -surf.P; surf.ray_length = 0.0; # else diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index c1e901845f1..67643471639 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -11,12 +11,18 @@ #pragma once -/** - * Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536. - * Current limiting factor is the sorting phase which is single pass and only sort within a - * thread-group which maximum size is 1024. - */ -#define CULLING_BATCH_SIZE 1024 +/* Hierarchical Z down-sampling. */ +#define HIZ_MIP_COUNT 8 +/* NOTE: The shader is written to update 5 mipmaps using LDS. */ +#define HIZ_GROUP_SIZE 32 + +/* Avoid too much overhead caused by resizing the light buffers too many time. */ +#define LIGHT_CHUNK 256 + +#define CULLING_SELECT_GROUP_SIZE 256 +#define CULLING_SORT_GROUP_SIZE 256 +#define CULLING_ZBIN_GROUP_SIZE 1024 +#define CULLING_TILE_GROUP_SIZE 1024 /** * IMPORTANT: Some data packing are tweaked for these values. @@ -34,10 +40,7 @@ #define SHADOW_MAX_PAGE 4096 #define SHADOW_PAGE_PER_ROW 64 -#define HIZ_MIP_COUNT 6u -/* Group size is 2x smaller because we simply copy the level 0. */ -#define HIZ_GROUP_SIZE 1u << (HIZ_MIP_COUNT - 2u) - +/* Ray-tracing. */ #define RAYTRACE_GROUP_SIZE 16 #define RAYTRACE_MAX_TILES (16384 / RAYTRACE_GROUP_SIZE) * (16384 / RAYTRACE_GROUP_SIZE) 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 index 3700076153e..afabeb8b729 100644 --- a/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc +++ b/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc @@ -765,4 +765,4 @@ void DepthOfField::render(GPUTexture **input_tx, /** \} */ -} // namespace blender::eevee
\ No newline at end of file +} // 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 b3fbe088471..ae41bd204d0 100644 --- a/source/blender/draw/engines/eevee_next/eevee_film.cc +++ b/source/blender/draw/engines/eevee_next/eevee_film.cc @@ -389,9 +389,8 @@ void Film::sync() 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); + DRW_shgroup_uniform_texture_ref(grp, "light_tx", &rbuffers.light_tx); DRW_shgroup_uniform_texture_ref(grp, "diffuse_color_tx", &rbuffers.diffuse_color_tx); - DRW_shgroup_uniform_texture_ref(grp, "specular_light_tx", &rbuffers.specular_light_tx); DRW_shgroup_uniform_texture_ref(grp, "specular_color_tx", &rbuffers.specular_color_tx); DRW_shgroup_uniform_texture_ref(grp, "volume_light_tx", &rbuffers.volume_light_tx); DRW_shgroup_uniform_texture_ref(grp, "emission_tx", &rbuffers.emission_tx); diff --git a/source/blender/draw/engines/eevee_next/eevee_hizbuffer.cc b/source/blender/draw/engines/eevee_next/eevee_hizbuffer.cc new file mode 100644 index 00000000000..e2022d74093 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_hizbuffer.cc @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. + */ + +#include "BKE_global.h" + +#include "eevee_instance.hh" + +#include "eevee_hizbuffer.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name Hierarchical-Z buffer + * + * \{ */ + +void HiZBuffer::sync() +{ + RenderBuffers &render_buffers = inst_.render_buffers; + + int2 render_extent = inst_.film.render_extent_get(); + /* Padding to avoid complexity during down-sampling and screen tracing. */ + int2 hiz_extent = math::ceil_to_multiple(render_extent, int2(1u << (HIZ_MIP_COUNT - 1))); + int2 dispatch_size = math::divide_ceil(hiz_extent, int2(HIZ_GROUP_SIZE)); + + hiz_tx_.ensure_2d(GPU_R32F, hiz_extent, nullptr, HIZ_MIP_COUNT); + hiz_tx_.ensure_mip_views(); + GPU_texture_mipmap_mode(hiz_tx_, true, false); + + data_.uv_scale = float2(render_extent) / float2(hiz_extent); + data_.push_update(); + + { + hiz_update_ps_ = DRW_pass_create("HizUpdate", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(HIZ_UPDATE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, hiz_update_ps_); + DRW_shgroup_storage_block(grp, "finished_tile_counter", atomic_tile_counter_); + DRW_shgroup_uniform_texture_ref_ex(grp, "depth_tx", &render_buffers.depth_tx, with_filter); + DRW_shgroup_uniform_image(grp, "out_mip_0", hiz_tx_.mip_view(0)); + DRW_shgroup_uniform_image(grp, "out_mip_1", hiz_tx_.mip_view(1)); + DRW_shgroup_uniform_image(grp, "out_mip_2", hiz_tx_.mip_view(2)); + DRW_shgroup_uniform_image(grp, "out_mip_3", hiz_tx_.mip_view(3)); + DRW_shgroup_uniform_image(grp, "out_mip_4", hiz_tx_.mip_view(4)); + DRW_shgroup_uniform_image(grp, "out_mip_5", hiz_tx_.mip_view(5)); + DRW_shgroup_uniform_image(grp, "out_mip_6", hiz_tx_.mip_view(6)); + DRW_shgroup_uniform_image(grp, "out_mip_7", hiz_tx_.mip_view(7)); + /* TODO(@fclem): There might be occasions where we might not want to + * copy mip 0 for performance reasons if there is no need for it. */ + DRW_shgroup_uniform_bool_copy(grp, "update_mip_0", true); + DRW_shgroup_call_compute(grp, UNPACK2(dispatch_size), 1); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); + } + + if (inst_.debug_mode == eDebugMode::DEBUG_HIZ_VALIDATION) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; + debug_draw_ps_ = DRW_pass_create("HizUpdate.Debug", state); + GPUShader *sh = inst_.shaders.static_shader_get(HIZ_DEBUG); + DRWShadingGroup *grp = DRW_shgroup_create(sh, debug_draw_ps_); + this->bind_resources(grp); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); + } + else { + debug_draw_ps_ = nullptr; + } +} + +void HiZBuffer::update() +{ + if (!is_dirty_) { + return; + } + + /* Bind another framebuffer in order to avoid triggering the feedback loop check. + * This is safe because we only use compute shaders in this section of the code. + * Ideally the check should be smarter. */ + GPUFrameBuffer *fb = GPU_framebuffer_active_get(); + if (G.debug & G_DEBUG_GPU) { + GPU_framebuffer_restore(); + } + + DRW_draw_pass(hiz_update_ps_); + + if (G.debug & G_DEBUG_GPU) { + GPU_framebuffer_bind(fb); + } +} + +void HiZBuffer::debug_draw(GPUFrameBuffer *view_fb) +{ + if (debug_draw_ps_ == nullptr) { + return; + } + inst_.info = "Debug Mode: HiZ Validation"; + inst_.hiz_buffer.update(); + GPU_framebuffer_bind(view_fb); + DRW_draw_pass(debug_draw_ps_); +} + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_hizbuffer.hh b/source/blender/draw/engines/eevee_next/eevee_hizbuffer.hh new file mode 100644 index 00000000000..039f7e4f16d --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_hizbuffer.hh @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * The Hierarchical-Z buffer is texture containing a copy of the depth buffer with mipmaps. + * Each mip contains the maximum depth of each 4 pixels on the upper level. + * The size of the texture is padded to avoid messing with the mipmap pixels alignments. + */ + +#pragma once + +#include "DRW_render.h" + +#include "eevee_shader_shared.hh" + +namespace blender::eevee { + +class Instance; + +/* -------------------------------------------------------------------- */ +/** \name Hierarchical-Z buffer + * \{ */ + +class HiZBuffer { + private: + Instance &inst_; + + /** The texture containing the hiz mip chain. */ + Texture hiz_tx_ = {"hiz_tx_"}; + /** + * Atomic counter counting the number of tile that have finished down-sampling. + * The last one will process the last few mip level. + */ + draw::StorageBuffer<uint4, true> atomic_tile_counter_ = {"atomic_tile_counter"}; + /** Single pass recursive downsample. */ + DRWPass *hiz_update_ps_ = nullptr; + /** Debug pass. */ + DRWPass *debug_draw_ps_ = nullptr; + /** Dirty flag to check if the update is necessary. */ + bool is_dirty_ = true; + + HiZDataBuf data_; + + public: + HiZBuffer(Instance &inst) : inst_(inst) + { + atomic_tile_counter_.clear_to_zero(); + }; + + void sync(); + + /** + * Tag the buffer for update if needed. + */ + void set_dirty() + { + is_dirty_ = true; + } + + /** + * Update the content of the HiZ buffer with the depth render target. + * Noop if the buffer has not been tagged as dirty. + * Should be called before each passes that needs to read the hiz buffer. + */ + void update(); + + void debug_draw(GPUFrameBuffer *view_fb); + + void bind_resources(DRWShadingGroup *grp) + { + DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", &hiz_tx_); + DRW_shgroup_uniform_block_ref(grp, "hiz_buf", &data_); + } +}; + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index df7a9ba7702..d28eb55c3b1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -53,6 +53,10 @@ void Instance::init(const int2 &output_res, v3d = v3d_; rv3d = rv3d_; + if (assign_if_different(debug_mode, (eDebugMode)G.debug_value)) { + sampling.reset(); + } + info = ""; update_eval_members(); @@ -96,11 +100,13 @@ void Instance::begin_sync() { materials.begin_sync(); velocity.begin_sync(); /* NOTE: Also syncs camera. */ + lights.begin_sync(); gpencil_engine_enabled = false; depth_of_field.sync(); motion_blur.sync(); + hiz_buffer.sync(); pipelines.sync(); main_view.sync(); world.sync(); @@ -109,7 +115,7 @@ void Instance::begin_sync() void Instance::object_sync(Object *ob) { - const bool is_renderable_type = ELEM(ob->type, OB_CURVES, OB_GPENCIL, OB_MESH); + const bool is_renderable_type = ELEM(ob->type, OB_CURVES, OB_GPENCIL, OB_MESH, OB_LAMP); const int ob_visibility = DRW_object_visibility_in_active_context(ob); const bool partsys_is_visible = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 && (ob->type == OB_MESH); @@ -133,15 +139,11 @@ void Instance::object_sync(Object *ob) if (object_is_visible) { switch (ob->type) { case OB_LAMP: + lights.sync_light(ob, ob_handle); break; case OB_MESH: - case OB_CURVES_LEGACY: - case OB_SURF: - case OB_FONT: - case OB_MBALL: { sync.sync_mesh(ob, ob_handle); break; - } case OB_VOLUME: break; case OB_CURVES: @@ -172,6 +174,7 @@ void Instance::object_sync_render(void *instance_, void Instance::end_sync() { velocity.end_sync(); + lights.end_sync(); sampling.end_sync(); film.end_sync(); } diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index 60dffd7c5ec..cc3d1c32fde 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -18,6 +18,8 @@ #include "eevee_camera.hh" #include "eevee_depth_of_field.hh" #include "eevee_film.hh" +#include "eevee_hizbuffer.hh" +#include "eevee_light.hh" #include "eevee_material.hh" #include "eevee_motion_blur.hh" #include "eevee_pipeline.hh" @@ -43,9 +45,11 @@ class Instance { SyncModule sync; MaterialModule materials; PipelineModule pipelines; + LightModule lights; VelocityModule velocity; MotionBlurModule motion_blur; DepthOfField depth_of_field; + HiZBuffer hiz_buffer; Sampling sampling; Camera camera; Film film; @@ -71,8 +75,10 @@ class Instance { /** True if the grease pencil engine might be running. */ bool gpencil_engine_enabled; - /* Info string displayed at the top of the render / viewport. */ + /** Info string displayed at the top of the render / viewport. */ std::string info = ""; + /** Debug mode from debug value. */ + eDebugMode debug_mode = eDebugMode::DEBUG_NONE; public: Instance() @@ -80,9 +86,11 @@ class Instance { sync(*this), materials(*this), pipelines(*this), + lights(*this), velocity(*this), motion_blur(*this), depth_of_field(*this), + hiz_buffer(*this), sampling(*this), camera(*this), film(*this), diff --git a/source/blender/draw/engines/eevee_next/eevee_light.cc b/source/blender/draw/engines/eevee_next/eevee_light.cc new file mode 100644 index 00000000000..558a9846ced --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_light.cc @@ -0,0 +1,503 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * The light module manages light data buffers and light culling system. + */ + +#include "draw_debug.hh" + +#include "eevee_instance.hh" + +#include "eevee_light.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name LightData + * \{ */ + +static eLightType to_light_type(short blender_light_type, short blender_area_type) +{ + switch (blender_light_type) { + default: + case LA_LOCAL: + return LIGHT_POINT; + case LA_SUN: + return LIGHT_SUN; + case LA_SPOT: + return LIGHT_SPOT; + case LA_AREA: + return ELEM(blender_area_type, LA_AREA_DISK, LA_AREA_ELLIPSE) ? LIGHT_ELLIPSE : LIGHT_RECT; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Light Object + * \{ */ + +void Light::sync(/* ShadowModule &shadows , */ const Object *ob, float threshold) +{ + const ::Light *la = (const ::Light *)ob->data; + float scale[3]; + + float max_power = max_fff(la->r, la->g, la->b) * fabsf(la->energy / 100.0f); + float surface_max_power = max_ff(la->diff_fac, la->spec_fac) * max_power; + float volume_max_power = la->volume_fac * max_power; + + float influence_radius_surface = attenuation_radius_get(la, threshold, surface_max_power); + float influence_radius_volume = attenuation_radius_get(la, threshold, volume_max_power); + + this->influence_radius_max = max_ff(influence_radius_surface, influence_radius_volume); + this->influence_radius_invsqr_surface = 1.0f / square_f(max_ff(influence_radius_surface, 1e-8f)); + this->influence_radius_invsqr_volume = 1.0f / square_f(max_ff(influence_radius_volume, 1e-8f)); + + this->color = float3(&la->r) * la->energy; + normalize_m4_m4_ex(this->object_mat.ptr(), ob->obmat, scale); + /* Make sure we have consistent handedness (in case of negatively scaled Z axis). */ + float3 cross = math::cross(float3(this->_right), float3(this->_up)); + if (math::dot(cross, float3(this->_back)) < 0.0f) { + negate_v3(this->_up); + } + + shape_parameters_set(la, scale); + + float shape_power = shape_power_get(la); + float point_power = point_power_get(la); + this->diffuse_power = la->diff_fac * shape_power; + this->transmit_power = la->diff_fac * point_power; + this->specular_power = la->spec_fac * shape_power; + this->volume_power = la->volume_fac * point_power; + + eLightType new_type = to_light_type(la->type, la->area_shape); + if (this->type != new_type) { + /* shadow_discard_safe(shadows); */ + this->type = new_type; + } + +#if 0 + if (la->mode & LA_SHADOW) { + if (la->type == LA_SUN) { + if (this->shadow_id == LIGHT_NO_SHADOW) { + this->shadow_id = shadows.directionals.alloc(); + } + + ShadowDirectional &shadow = shadows.directionals[this->shadow_id]; + shadow.sync(this->object_mat, la->bias * 0.05f, 1.0f); + } + else { + float cone_aperture = DEG2RAD(360.0); + if (la->type == LA_SPOT) { + cone_aperture = min_ff(DEG2RAD(179.9), la->spotsize); + } + else if (la->type == LA_AREA) { + cone_aperture = DEG2RAD(179.9); + } + + if (this->shadow_id == LIGHT_NO_SHADOW) { + this->shadow_id = shadows.punctuals.alloc(); + } + + ShadowPunctual &shadow = shadows.punctuals[this->shadow_id]; + shadow.sync(this->type, + this->object_mat, + cone_aperture, + la->clipsta, + this->influence_radius_max, + la->bias * 0.05f); + } + } + else { + shadow_discard_safe(shadows); + } +#endif + + this->initialized = true; +} + +#if 0 +void Light::shadow_discard_safe(ShadowModule &shadows) +{ + if (shadow_id != LIGHT_NO_SHADOW) { + if (this->type != LIGHT_SUN) { + shadows.punctuals.free(shadow_id); + } + else { + shadows.directionals.free(shadow_id); + } + shadow_id = LIGHT_NO_SHADOW; + } +} +#endif + +/* Returns attenuation radius inverted & squared for easy bound checking inside the shader. */ +float Light::attenuation_radius_get(const ::Light *la, float light_threshold, float light_power) +{ + if (la->type == LA_SUN) { + return (light_power > 1e-5f) ? 1e16f : 0.0f; + } + + if (la->mode & LA_CUSTOM_ATTENUATION) { + return la->att_dist; + } + /* Compute the distance (using the inverse square law) + * at which the light power reaches the light_threshold. */ + /* TODO take area light scale into account. */ + return sqrtf(light_power / light_threshold); +} + +void Light::shape_parameters_set(const ::Light *la, const float scale[3]) +{ + if (la->type == LA_AREA) { + float area_size_y = (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) ? la->area_sizey : + la->area_size; + _area_size_x = max_ff(0.003f, la->area_size * scale[0] * 0.5f); + _area_size_y = max_ff(0.003f, area_size_y * scale[1] * 0.5f); + /* For volume point lighting. */ + radius_squared = max_ff(0.001f, hypotf(_area_size_x, _area_size_y) * 0.5f); + radius_squared = square_f(radius_squared); + } + else { + if (la->type == LA_SPOT) { + /* Spot size & blend */ + spot_size_inv[0] = scale[2] / scale[0]; + spot_size_inv[1] = scale[2] / scale[1]; + float spot_size = cosf(la->spotsize * 0.5f); + float spot_blend = (1.0f - spot_size) * la->spotblend; + _spot_mul = 1.0f / max_ff(1e-8f, spot_blend); + _spot_bias = -spot_size * _spot_mul; + spot_tan = tanf(min_ff(la->spotsize * 0.5f, M_PI_2 - 0.0001f)); + } + + if (la->type == LA_SUN) { + _area_size_x = tanf(min_ff(la->sun_angle, DEG2RADF(179.9f)) / 2.0f); + } + else { + _area_size_x = la->area_size; + } + _area_size_y = _area_size_x = max_ff(0.001f, _area_size_x); + radius_squared = square_f(_area_size_x); + } +} + +float Light::shape_power_get(const ::Light *la) +{ + /* Make illumination power constant */ + switch (la->type) { + case LA_AREA: { + float area = _area_size_x * _area_size_y; + float power = 1.0f / (area * 4.0f * float(M_PI)); + /* FIXME : Empirical, Fit cycles power */ + power *= 0.8f; + if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { + /* Scale power to account for the lower area of the ellipse compared to the surrounding + * rectangle. */ + power *= 4.0f / M_PI; + } + return power; + } + case LA_SPOT: + case LA_LOCAL: { + return 1.0f / (4.0f * square_f(_radius) * float(M_PI * M_PI)); + } + default: + case LA_SUN: { + float power = 1.0f / (square_f(_radius) * float(M_PI)); + /* Make illumination power closer to cycles for bigger radii. Cycles uses a cos^3 term that + * we cannot reproduce so we account for that by scaling the light power. This function is + * the result of a rough manual fitting. */ + /* Simplification of: power *= 1 + r²/2 */ + power += 1.0f / (2.0f * M_PI); + + return power; + } + } +} + +float Light::point_power_get(const ::Light *la) +{ + /* Volume light is evaluated as point lights. Remove the shape power. */ + switch (la->type) { + case LA_AREA: { + /* Match cycles. Empirical fit... must correspond to some constant. */ + float power = 0.0792f * M_PI; + + /* This corrects for area light most representative point trick. The fit was found by + * reducing the average error compared to cycles. */ + float area = _area_size_x * _area_size_y; + float tmp = M_PI_2 / (M_PI_2 + sqrtf(area)); + /* Lerp between 1.0 and the limit (1 / pi). */ + power *= tmp + (1.0f - tmp) * M_1_PI; + + return power; + } + case LA_SPOT: + case LA_LOCAL: { + /* Match cycles. Empirical fit... must correspond to some constant. */ + return 0.0792f; + } + default: + case LA_SUN: { + return 1.0f; + } + } +} + +void Light::debug_draw() +{ +#ifdef DEBUG + drw_debug_sphere(_position, influence_radius_max, float4(0.8f, 0.3f, 0.0f, 1.0f)); +#endif +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name LightModule + * \{ */ + +void LightModule::begin_sync() +{ + use_scene_lights_ = inst_.use_scene_lights(); + + /* In begin_sync so it can be animated. */ + if (assign_if_different(light_threshold_, max_ff(1e-16f, inst_.scene->eevee.light_threshold))) { + inst_.sampling.reset(); + } + + sun_lights_len_ = 0; + local_lights_len_ = 0; +} + +void LightModule::sync_light(const Object *ob, ObjectHandle &handle) +{ + if (use_scene_lights_ == false) { + return; + } + Light &light = light_map_.lookup_or_add_default(handle.object_key); + light.used = true; + if (handle.recalc != 0 || !light.initialized) { + light.sync(/* inst_.shadows, */ ob, light_threshold_); + } + sun_lights_len_ += int(light.type == LIGHT_SUN); + local_lights_len_ += int(light.type != LIGHT_SUN); +} + +void LightModule::end_sync() +{ + // ShadowModule &shadows = inst_.shadows; + + /* NOTE: We resize this buffer before removing deleted lights. */ + int lights_allocated = ceil_to_multiple_u(max_ii(light_map_.size(), 1), LIGHT_CHUNK); + light_buf_.resize(lights_allocated); + + /* Track light deletion. */ + Vector<ObjectKey, 0> deleted_keys; + /* Indices inside GPU data array. */ + int sun_lights_idx = 0; + int local_lights_idx = sun_lights_len_; + + /* Fill GPU data with scene data. */ + for (auto item : light_map_.items()) { + Light &light = item.value; + + if (!light.used) { + /* Deleted light. */ + deleted_keys.append(item.key); + // light.shadow_discard_safe(shadows); + continue; + } + + int dst_idx = (light.type == LIGHT_SUN) ? sun_lights_idx++ : local_lights_idx++; + /* Put all light data into global data SSBO. */ + light_buf_[dst_idx] = light; + +#if 0 + if (light.shadow_id != LIGHT_NO_SHADOW) { + if (light.type == LIGHT_SUN) { + light_buf_[dst_idx].shadow_data = shadows.directionals[light.shadow_id]; + } + else { + light_buf_[dst_idx].shadow_data = shadows.punctuals[light.shadow_id]; + } + } +#endif + /* Untag for next sync. */ + light.used = false; + } + /* This scene data buffer is then immutable after this point. */ + light_buf_.push_update(); + + for (auto key : deleted_keys) { + light_map_.remove(key); + } + + /* Update sampling on deletion or un-hiding (use_scene_lights). */ + if (assign_if_different(light_map_size_, light_map_.size())) { + inst_.sampling.reset(); + } + + /* If exceeding the limit, just trim off the excess to avoid glitchy rendering. */ + if (sun_lights_len_ + local_lights_len_ > CULLING_MAX_ITEM) { + sun_lights_len_ = min_ii(sun_lights_len_, CULLING_MAX_ITEM); + local_lights_len_ = min_ii(local_lights_len_, CULLING_MAX_ITEM - sun_lights_len_); + inst_.info = "Error: Too many lights in the scene."; + } + lights_len_ = sun_lights_len_ + local_lights_len_; + + /* Resize to the actual number of lights after pruning. */ + lights_allocated = ceil_to_multiple_u(max_ii(lights_len_, 1), LIGHT_CHUNK); + culling_key_buf_.resize(lights_allocated); + culling_zdist_buf_.resize(lights_allocated); + culling_light_buf_.resize(lights_allocated); + + { + /* Compute tile size and total word count. */ + uint word_per_tile = divide_ceil_u(max_ii(lights_len_, 1), 32); + int2 render_extent = inst_.film.render_extent_get(); + int2 tiles_extent; + /* Default to 32 as this is likely to be the maximum + * tile size used by hardware or compute shading. */ + uint tile_size = 16; + do { + tile_size *= 2; + tiles_extent = math::divide_ceil(render_extent, int2(tile_size)); + uint tile_count = tiles_extent.x * tiles_extent.y; + if (tile_count > max_tile_count_threshold) { + continue; + } + total_word_count_ = tile_count * word_per_tile; + + } while (total_word_count_ > max_word_count_threshold); + /* Keep aligned with storage buffer requirements. */ + total_word_count_ = ceil_to_multiple_u(total_word_count_, 32); + + culling_data_buf_.tile_word_len = word_per_tile; + culling_data_buf_.tile_size = tile_size; + culling_data_buf_.tile_x_len = tiles_extent.x; + culling_data_buf_.tile_y_len = tiles_extent.y; + culling_data_buf_.items_count = lights_len_; + culling_data_buf_.local_lights_len = local_lights_len_; + culling_data_buf_.sun_lights_len = sun_lights_len_; + } + culling_tile_buf_.resize(total_word_count_); + + culling_pass_sync(); + debug_pass_sync(); +} + +void LightModule::culling_pass_sync() +{ + uint safe_lights_len = max_ii(lights_len_, 1); + uint culling_select_dispatch_size = divide_ceil_u(safe_lights_len, CULLING_SELECT_GROUP_SIZE); + uint culling_sort_dispatch_size = divide_ceil_u(safe_lights_len, CULLING_SORT_GROUP_SIZE); + uint culling_tile_dispatch_size = divide_ceil_u(total_word_count_, CULLING_TILE_GROUP_SIZE); + + /* NOTE: We reference the buffers that may be resized or updated later. */ + { + DRW_PASS_CREATE(culling_select_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(LIGHT_CULLING_SELECT); + DRWShadingGroup *grp = DRW_shgroup_create(sh, culling_select_ps_); + DRW_shgroup_storage_block_ref(grp, "light_cull_buf", &culling_data_buf_); + DRW_shgroup_storage_block(grp, "in_light_buf", light_buf_); + DRW_shgroup_storage_block(grp, "out_light_buf", culling_light_buf_); + DRW_shgroup_storage_block(grp, "out_zdist_buf", culling_zdist_buf_); + DRW_shgroup_storage_block(grp, "out_key_buf", culling_key_buf_); + DRW_shgroup_call_compute(grp, culling_select_dispatch_size, 1, 1); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE); + } + { + DRW_PASS_CREATE(culling_sort_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(LIGHT_CULLING_SORT); + DRWShadingGroup *grp = DRW_shgroup_create(sh, culling_sort_ps_); + DRW_shgroup_storage_block_ref(grp, "light_cull_buf", &culling_data_buf_); + DRW_shgroup_storage_block(grp, "in_light_buf", light_buf_); + DRW_shgroup_storage_block(grp, "out_light_buf", culling_light_buf_); + DRW_shgroup_storage_block(grp, "in_zdist_buf", culling_zdist_buf_); + DRW_shgroup_storage_block(grp, "in_key_buf", culling_key_buf_); + DRW_shgroup_call_compute(grp, culling_sort_dispatch_size, 1, 1); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE); + } + { + DRW_PASS_CREATE(culling_zbin_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(LIGHT_CULLING_ZBIN); + DRWShadingGroup *grp = DRW_shgroup_create(sh, culling_zbin_ps_); + DRW_shgroup_storage_block_ref(grp, "light_cull_buf", &culling_data_buf_); + DRW_shgroup_storage_block(grp, "light_buf", culling_light_buf_); + DRW_shgroup_storage_block(grp, "out_zbin_buf", culling_zbin_buf_); + DRW_shgroup_call_compute(grp, 1, 1, 1); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE); + } + { + DRW_PASS_CREATE(culling_tile_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(LIGHT_CULLING_TILE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, culling_tile_ps_); + DRW_shgroup_storage_block_ref(grp, "light_cull_buf", &culling_data_buf_); + DRW_shgroup_storage_block(grp, "light_buf", culling_light_buf_); + DRW_shgroup_storage_block(grp, "out_light_tile_buf", culling_tile_buf_); + DRW_shgroup_call_compute(grp, culling_tile_dispatch_size, 1, 1); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE); + } +} + +void LightModule::debug_pass_sync() +{ + if (inst_.debug_mode != eDebugMode::DEBUG_LIGHT_CULLING) { + debug_draw_ps_ = nullptr; + return; + } + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; + debug_draw_ps_ = DRW_pass_create("LightCulling.Debug", state); + GPUShader *sh = inst_.shaders.static_shader_get(LIGHT_CULLING_DEBUG); + DRWShadingGroup *grp = DRW_shgroup_create(sh, debug_draw_ps_); + inst_.hiz_buffer.bind_resources(grp); + DRW_shgroup_storage_block_ref(grp, "light_buf", &culling_light_buf_); + DRW_shgroup_storage_block_ref(grp, "light_cull_buf", &culling_data_buf_); + DRW_shgroup_storage_block_ref(grp, "light_zbin_buf", &culling_zbin_buf_); + DRW_shgroup_storage_block_ref(grp, "light_tile_buf", &culling_tile_buf_); + DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &inst_.render_buffers.depth_tx); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); +} + +void LightModule::set_view(const DRWView *view, const int2 extent) +{ + float far_z = DRW_view_far_distance_get(view); + float near_z = DRW_view_near_distance_get(view); + + culling_data_buf_.zbin_scale = -CULLING_ZBIN_COUNT / fabsf(far_z - near_z); + culling_data_buf_.zbin_bias = -near_z * culling_data_buf_.zbin_scale; + culling_data_buf_.tile_to_uv_fac = (culling_data_buf_.tile_size / float2(extent)); + culling_data_buf_.visible_count = 0; + culling_data_buf_.push_update(); + + DRW_stats_group_start("Light Culling"); + + DRW_view_set_active(view); + DRW_draw_pass(culling_select_ps_); + DRW_draw_pass(culling_sort_ps_); + DRW_draw_pass(culling_zbin_ps_); + DRW_draw_pass(culling_tile_ps_); + + DRW_stats_group_end(); +} + +void LightModule::debug_draw(GPUFrameBuffer *view_fb) +{ + if (debug_draw_ps_ == nullptr) { + return; + } + inst_.info = "Debug Mode: Light Culling Validation"; + inst_.hiz_buffer.update(); + GPU_framebuffer_bind(view_fb); + DRW_draw_pass(debug_draw_ps_); +} + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_light.hh b/source/blender/draw/engines/eevee_next/eevee_light.hh new file mode 100644 index 00000000000..aad798ccec2 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_light.hh @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * The light module manages light data buffers and light culling system. + * + * The culling follows the principles of Tiled Culling + Z binning from: + * "Improved Culling for Tiled and Clustered Rendering" + * by Michal Drobot + * http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf + * + * The culling is separated in 4 compute phases: + * - View Culling (select pass): Create a z distance and a index buffer of visible lights. + * - Light sorting: Outputs visible lights sorted by Z distance. + * - Z binning: Compute the Z bins min/max light indices. + * - Tile intersection: Fine grained 2D culling of each lights outputting a bitmap per tile. + */ + +#pragma once + +#include "BLI_bitmap.h" +#include "BLI_vector.hh" +#include "DNA_light_types.h" + +#include "eevee_camera.hh" +#include "eevee_sampling.hh" +#include "eevee_shader.hh" +#include "eevee_shader_shared.hh" +#include "eevee_sync.hh" + +namespace blender::eevee { + +class Instance; + +/* -------------------------------------------------------------------- */ +/** \name Light Object + * \{ */ + +struct Light : public LightData { + public: + bool initialized = false; + bool used = false; + + public: + Light() + { + shadow_id = LIGHT_NO_SHADOW; + } + + void sync(/* ShadowModule &shadows, */ const Object *ob, float threshold); + + // void shadow_discard_safe(ShadowModule &shadows); + + void debug_draw(); + + private: + float attenuation_radius_get(const ::Light *la, float light_threshold, float light_power); + void shape_parameters_set(const ::Light *la, const float scale[3]); + float shape_power_get(const ::Light *la); + float point_power_get(const ::Light *la); +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name LightModule + * \{ */ + +/** + * The light module manages light data buffers and light culling system. + */ +class LightModule { + // friend ShadowModule; + + private: + /* Keep tile count reasonable for memory usage and 2D culling performance. */ + static constexpr uint max_memory_threshold = 32 * 1024 * 1024; /* 32 MiB */ + static constexpr uint max_word_count_threshold = max_memory_threshold / sizeof(uint); + static constexpr uint max_tile_count_threshold = 8192; + + Instance &inst_; + + /** Map of light objects data. Converted to flat array each frame. */ + Map<ObjectKey, Light> light_map_; + /** Flat array sent to GPU, populated from light_map_. Source buffer for light culling. */ + LightDataBuf light_buf_ = {"Lights_no_cull"}; + /** Recorded size of light_map_ (after pruning) to detect deletion. */ + int64_t light_map_size_ = 0; + /** Luminous intensity to consider the light boundary at. Used for culling. */ + float light_threshold_ = 0.01f; + /** If false, will prevent all scene light from being synced. */ + bool use_scene_lights_ = false; + /** Number of sun lights synced during the last sync. Used as offset. */ + int sun_lights_len_ = 0; + int local_lights_len_ = 0; + /** Sun plus local lights count for convenience. */ + int lights_len_ = 0; + + /** + * Light Culling + */ + + /** LightData buffer used for rendering. Filled by the culling pass. */ + LightDataBuf culling_light_buf_ = {"Lights_culled"}; + /** Culling infos. */ + LightCullingDataBuf culling_data_buf_ = {"LightCull_data"}; + /** Z-distance matching the key for each visible lights. Used for sorting. */ + LightCullingZdistBuf culling_zdist_buf_ = {"LightCull_zdist"}; + /** Key buffer containing only visible lights indices. Used for sorting. */ + LightCullingKeyBuf culling_key_buf_ = {"LightCull_key"}; + /** Zbins containing min and max light index for each Z bin. */ + LightCullingZbinBuf culling_zbin_buf_ = {"LightCull_zbin"}; + /** Bitmap of lights touching each tiles. */ + LightCullingTileBuf culling_tile_buf_ = {"LightCull_tile"}; + /** Culling compute passes. */ + DRWPass *culling_select_ps_ = nullptr; + DRWPass *culling_sort_ps_ = nullptr; + DRWPass *culling_zbin_ps_ = nullptr; + DRWPass *culling_tile_ps_ = nullptr; + /** Total number of words the tile buffer needs to contain for the render resolution. */ + uint total_word_count_ = 0; + + /** Debug Culling visualization. */ + DRWPass *debug_draw_ps_ = nullptr; + /* GPUTexture *input_depth_tx_ = nullptr; */ + + public: + LightModule(Instance &inst) : inst_(inst){}; + ~LightModule(){}; + + void begin_sync(); + void sync_light(const Object *ob, ObjectHandle &handle); + void end_sync(); + + /** + * Update acceleration structure for the given view. + */ + void set_view(const DRWView *view, const int2 extent); + + void debug_draw(GPUFrameBuffer *view_fb); + + void bind_resources(DRWShadingGroup *grp) + { + DRW_shgroup_storage_block_ref(grp, "light_buf", &culling_light_buf_); + DRW_shgroup_storage_block_ref(grp, "light_cull_buf", &culling_data_buf_); + DRW_shgroup_storage_block_ref(grp, "light_zbin_buf", &culling_zbin_buf_); + DRW_shgroup_storage_block_ref(grp, "light_tile_buf", &culling_tile_buf_); +#if 0 + DRW_shgroup_uniform_texture(grp, "shadow_atlas_tx", inst_.shadows.atlas_tx_get()); + DRW_shgroup_uniform_texture(grp, "shadow_tilemaps_tx", inst_.shadows.tilemap_tx_get()); +#endif + } + + private: + void culling_pass_sync(); + void debug_pass_sync(); +}; + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc index 660eb9f1e22..d9545e2e972 100644 --- a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc +++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc @@ -259,4 +259,4 @@ void MotionBlurModule::render(GPUTexture **input_tx, GPUTexture **output_tx) /** \} */ -} // namespace blender::eevee
\ No newline at end of file +} // 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 db169ec361f..d9ac39f4fb9 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -43,9 +43,8 @@ void WorldPipeline::sync(GPUMaterial *gpumat) DRW_shgroup_storage_block_ref(grp, "aov_buf", &inst_.film.aovs_info); /* RenderPasses. Cleared by background (even if bad practice). */ 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_light_img", &rbufs.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); /* To allow opaque pass rendering over it. */ @@ -101,12 +100,14 @@ DRWShadingGroup *ForwardPipeline::material_opaque_add(::Material *blender_mat, G { RenderBuffers &rbufs = inst_.render_buffers; DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? opaque_culled_ps_ : opaque_ps_; - // LightModule &lights = inst_.lights; + LightModule &lights = inst_.lights; + Sampling &sampling = inst_.sampling; // LightProbeModule &lightprobes = inst_.lightprobes; // RaytracingModule &raytracing = inst_.raytracing; // eGPUSamplerState no_interp = GPU_SAMPLER_DEFAULT; DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, pass); - // lights.shgroup_resources(grp); + lights.bind_resources(grp); + sampling.bind_resources(grp); // DRW_shgroup_uniform_block(grp, "sampling_buf", inst_.sampling.ubo_get()); // DRW_shgroup_uniform_block(grp, "grids_buf", lightprobes.grid_ubo_get()); // DRW_shgroup_uniform_block(grp, "cubes_buf", lightprobes.cube_ubo_get()); @@ -120,9 +121,8 @@ DRWShadingGroup *ForwardPipeline::material_opaque_add(::Material *blender_mat, G 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_light_img", &rbufs.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); @@ -163,19 +163,21 @@ DRWShadingGroup *ForwardPipeline::material_transparent_add(::Material *blender_m GPUMaterial *gpumat) { RenderBuffers &rbufs = inst_.render_buffers; - // LightModule &lights = inst_.lights; + LightModule &lights = inst_.lights; + Sampling &sampling = inst_.sampling; // LightProbeModule &lightprobes = inst_.lightprobes; // RaytracingModule &raytracing = inst_.raytracing; // eGPUSamplerState no_interp = GPU_SAMPLER_DEFAULT; DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, transparent_ps_); - // lights.shgroup_resources(grp); + lights.bind_resources(grp); + sampling.bind_resources(grp); // DRW_shgroup_uniform_block(grp, "sampling_buf", inst_.sampling.ubo_get()); // DRW_shgroup_uniform_block(grp, "grids_buf", lightprobes.grid_ubo_get()); // DRW_shgroup_uniform_block(grp, "cubes_buf", lightprobes.cube_ubo_get()); // DRW_shgroup_uniform_block(grp, "probes_buf", lightprobes.info_ubo_get()); // DRW_shgroup_uniform_texture_ref(grp, "lightprobe_grid_tx", lightprobes.grid_tx_ref_get()); // DRW_shgroup_uniform_texture_ref(grp, "lightprobe_cube_tx", lightprobes.cube_tx_ref_get()); - // DRW_shgroup_uniform_texture(grp, "utility_tx", inst_.pipelines.utility_tx); + DRW_shgroup_uniform_texture(grp, "utility_tx", inst_.pipelines.utility_tx); /* TODO(fclem): Make this only needed if material uses it ... somehow. */ // if (true) { // DRW_shgroup_uniform_texture_ref( @@ -202,9 +204,8 @@ DRWShadingGroup *ForwardPipeline::material_transparent_add(::Material *blender_m 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_light_img", &rbufs.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); } @@ -241,22 +242,22 @@ DRWShadingGroup *ForwardPipeline::prepass_transparent_add(::Material *blender_ma void ForwardPipeline::render(const DRWView *view, Framebuffer &prepass_fb, Framebuffer &combined_fb, - GPUTexture *depth_tx, GPUTexture *UNUSED(combined_tx)) { - UNUSED_VARS(view, depth_tx, prepass_fb, combined_fb); - // HiZBuffer &hiz = inst_.hiz_front; + UNUSED_VARS(view); DRW_stats_group_start("ForwardOpaque"); GPU_framebuffer_bind(prepass_fb); DRW_draw_pass(prepass_ps_); - // hiz.set_dirty(); + if (!DRW_pass_is_empty(prepass_ps_)) { + inst_.hiz_buffer.set_dirty(); + } // if (inst_.raytracing.enabled()) { // rt_buffer.radiance_copy(combined_tx); - // hiz.update(depth_tx); + // inst_.hiz_buffer.update(); // } // inst_.shadows.set_view(view, depth_tx); diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index 3bdc718767b..ed6986b9b61 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -91,7 +91,6 @@ class ForwardPipeline { void render(const DRWView *view, Framebuffer &prepass_fb, Framebuffer &combined_fb, - GPUTexture *depth_tx, GPUTexture *combined_tx); }; diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc index b69fde7b26c..c18c913d797 100644 --- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc +++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc @@ -26,9 +26,11 @@ namespace blender::eevee { void RenderBuffers::acquire(int2 extent) { + const eViewLayerEEVEEPassType enabled_passes = inst_.film.enabled_passes_get(); + auto pass_extent = [&](eViewLayerEEVEEPassType pass_bit) -> int2 { /* Use dummy texture for disabled passes. Allows correct bindings. */ - return (inst_.film.enabled_passes_get() & pass_bit) ? extent : int2(1); + return (enabled_passes & pass_bit) ? extent : int2(1); }; eGPUTextureFormat color_format = GPU_RGBA16F; @@ -38,17 +40,22 @@ void RenderBuffers::acquire(int2 extent) 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 = (enabled_passes & EEVEE_RENDER_PASS_VECTOR) || (inst_.motion_blur.postfx_enabled() && !inst_.is_viewport()); + uint32_t max_light_color_layer = max_ii(enabled_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT ? + (int)RENDER_PASS_LAYER_DIFFUSE_LIGHT : + -1, + enabled_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT ? + (int)RENDER_PASS_LAYER_SPECULAR_LIGHT : + -1) + + 1; /* 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); 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); @@ -56,6 +63,10 @@ void RenderBuffers::acquire(int2 extent) shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format); ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format); + light_tx.ensure_2d_array(color_format, + max_light_color_layer > 0 ? extent : int2(1), + max_ii(1, max_light_color_layer)); + const AOVsInfoData &aovs = inst_.film.aovs_info; aov_color_tx.ensure_2d_array( color_format, (aovs.color_len > 0) ? extent : int2(1), max_ii(1, aovs.color_len)); @@ -70,9 +81,7 @@ void RenderBuffers::release() normal_tx.release(); vector_tx.release(); - diffuse_light_tx.release(); diffuse_color_tx.release(); - specular_light_tx.release(); specular_color_tx.release(); volume_light_tx.release(); emission_tx.release(); diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh index 787f5604aa4..0b761d618cc 100644 --- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh +++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh @@ -28,9 +28,7 @@ class RenderBuffers { // TextureFromPool mist_tx; /* Derived from depth_tx during accumulation. */ TextureFromPool normal_tx; TextureFromPool vector_tx; - TextureFromPool diffuse_light_tx; TextureFromPool diffuse_color_tx; - TextureFromPool specular_light_tx; TextureFromPool specular_color_tx; TextureFromPool volume_light_tx; TextureFromPool emission_tx; @@ -39,6 +37,7 @@ class RenderBuffers { TextureFromPool ambient_occlusion_tx; // TextureFromPool cryptomatte_tx; /* TODO */ /* TODO(fclem): Use texture from pool once they support texture array. */ + Texture light_tx; Texture aov_color_tx; Texture aov_value_tx; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 357f2796a7e..0e49b195ea2 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -82,6 +82,10 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_film_frag"; case FILM_COMP: return "eevee_film_comp"; + case HIZ_DEBUG: + return "eevee_hiz_debug"; + case HIZ_UPDATE: + return "eevee_hiz_update"; case MOTION_BLUR_GATHER: return "eevee_motion_blur_gather"; case MOTION_BLUR_TILE_DILATE: @@ -124,6 +128,16 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_depth_of_field_tiles_dilate_minmax"; case DOF_TILES_FLATTEN: return "eevee_depth_of_field_tiles_flatten"; + case LIGHT_CULLING_DEBUG: + return "eevee_light_culling_debug"; + case LIGHT_CULLING_SELECT: + return "eevee_light_culling_select"; + case LIGHT_CULLING_SORT: + return "eevee_light_culling_sort"; + case LIGHT_CULLING_TILE: + return "eevee_light_culling_tile"; + case LIGHT_CULLING_ZBIN: + return "eevee_light_culling_zbin"; /* 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 dd6b9c9d4ab..9ef42c84373 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh @@ -47,6 +47,15 @@ enum eShaderType { DOF_TILES_DILATE_MINMAX, DOF_TILES_FLATTEN, + HIZ_UPDATE, + HIZ_DEBUG, + + LIGHT_CULLING_DEBUG, + LIGHT_CULLING_SELECT, + LIGHT_CULLING_SORT, + LIGHT_CULLING_TILE, + LIGHT_CULLING_ZBIN, + MOTION_BLUR_GATHER, MOTION_BLUR_TILE_DILATE, MOTION_BLUR_TILE_FLATTEN_RENDER, 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 fe36cb1a17c..a0829bc49aa 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -31,6 +31,56 @@ constexpr eGPUSamplerState with_filter = GPU_SAMPLER_FILTER; #define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14 /* -------------------------------------------------------------------- */ +/** \name Debug Mode + * \{ */ + +/** These are just to make more sense of G.debug_value's values. Reserved range is 1-30. */ +enum eDebugMode : uint32_t { + DEBUG_NONE = 0u, + /** + * Gradient showing light evaluation hot-spots. + */ + DEBUG_LIGHT_CULLING = 1u, + /** + * Show incorrectly downsample tiles in red. + */ + DEBUG_HIZ_VALIDATION = 2u, + /** + * Tile-maps to screen. Is also present in other modes. + * - Black pixels, no pages allocated. + * - Green pixels, pages cached. + * - Red pixels, pages allocated. + */ + DEBUG_SHADOW_TILEMAPS = 10u, + /** + * Random color per pages. Validates page density allocation and sampling. + */ + DEBUG_SHADOW_PAGES = 11u, + /** + * Outputs random color per tile-map (or tile-map level). Validates tile-maps coverage. + * Black means not covered by any tile-maps LOD of the shadow. + */ + DEBUG_SHADOW_LOD = 12u, + /** + * Outputs white pixels for pages allocated and black pixels for unused pages. + * This needs DEBUG_SHADOW_PAGE_ALLOCATION_ENABLED defined in order to work. + */ + DEBUG_SHADOW_PAGE_ALLOCATION = 13u, + /** + * Outputs the tile-map atlas. Default tile-map is too big for the usual screen resolution. + * Try lowering SHADOW_TILEMAP_PER_ROW and SHADOW_MAX_TILEMAP before using this option. + */ + DEBUG_SHADOW_TILE_ALLOCATION = 14u, + /** + * Visualize linear depth stored in the atlas regions of the active light. + * This way, one can check if the rendering, the copying and the shadow sampling functions works. + */ + DEBUG_SHADOW_SHADOW_DEPTH = 15u +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Sampling * \{ */ @@ -242,6 +292,17 @@ static inline float film_filter_weight(float filter_radius, float sample_distanc /** \} */ /* -------------------------------------------------------------------- */ +/** \name Render passes + * \{ */ + +enum eRenderPassLayerIndex : uint32_t { + RENDER_PASS_LAYER_DIFFUSE_LIGHT = 0u, + RENDER_PASS_LAYER_SPECULAR_LIGHT = 1u, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Arbitrary Output Variables * \{ */ @@ -460,6 +521,127 @@ static inline float circle_to_polygon_angle(float sides_count, float theta) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Light Culling + * \{ */ + +/* Number of items we can cull. Limited by how we store CullingZBin. */ +#define CULLING_MAX_ITEM 65536 +/* Fine grained subdivision in the Z direction. Limited by the LDS in z-binning compute shader. */ +#define CULLING_ZBIN_COUNT 4096 +/* Max tile map resolution per axes. */ +#define CULLING_TILE_RES 16 + +struct LightCullingData { + /** Scale applied to tile pixel coordinates to get target UV coordinate. */ + float2 tile_to_uv_fac; + /** Scale and bias applied to linear Z to get zbin. */ + float zbin_scale; + float zbin_bias; + /** Valid item count in the source data array. */ + uint items_count; + /** Items that are processed by the 2.5D culling. */ + uint local_lights_len; + /** Items that are **NOT** processed by the 2.5D culling (i.e: Sun Lights). */ + uint sun_lights_len; + /** Number of items that passes the first culling test. */ + uint visible_count; + /** Extent of one square tile in pixels. */ + float tile_size; + /** Number of tiles on the X/Y axis. */ + uint tile_x_len; + uint tile_y_len; + /** Number of word per tile. Depends on the maximum number of lights. */ + uint tile_word_len; +}; +BLI_STATIC_ASSERT_ALIGN(LightCullingData, 16) + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lights + * \{ */ + +#define LIGHT_NO_SHADOW -1 + +enum eLightType : uint32_t { + LIGHT_SUN = 0u, + LIGHT_POINT = 1u, + LIGHT_SPOT = 2u, + LIGHT_RECT = 3u, + LIGHT_ELLIPSE = 4u +}; + +static inline bool is_area_light(eLightType type) +{ + return type >= LIGHT_RECT; +} + +struct LightData { + /** Normalized object matrix. Last column contains data accessible using the following macros. */ + float4x4 object_mat; + /** Packed data in the last column of the object_mat. */ +#define _area_size_x object_mat[0][3] +#define _area_size_y object_mat[1][3] +#define _radius _area_size_x +#define _spot_mul object_mat[2][3] +#define _spot_bias object_mat[3][3] + /** Aliases for axes. */ +#ifndef USE_GPU_SHADER_CREATE_INFO +# define _right object_mat[0] +# define _up object_mat[1] +# define _back object_mat[2] +# define _position object_mat[3] +#else +# define _right object_mat[0].xyz +# define _up object_mat[1].xyz +# define _back object_mat[2].xyz +# define _position object_mat[3].xyz +#endif + /** Influence radius (inverted and squared) adjusted for Surface / Volume power. */ + float influence_radius_invsqr_surface; + float influence_radius_invsqr_volume; + /** Maximum influence radius. Used for culling. */ + float influence_radius_max; + /** Index of the shadow struct on CPU. -1 means no shadow. */ + int shadow_id; + /** NOTE: It is ok to use float3 here. A float is declared right after it. + * float3 is also aligned to 16 bytes. */ + float3 color; + /** Power depending on shader type. */ + float diffuse_power; + float specular_power; + float volume_power; + float transmit_power; + /** Special radius factor for point lighting. */ + float radius_squared; + /** Light Type. */ + eLightType type; + /** Spot angle tangent. */ + float spot_tan; + /** Spot size. Aligned to size of float2. */ + float2 spot_size_inv; + /** Associated shadow data. Only valid if shadow_id is not LIGHT_NO_SHADOW. */ + // ShadowData shadow_data; +}; +BLI_STATIC_ASSERT_ALIGN(LightData, 16) + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hierarchical-Z Buffer + * \{ */ + +struct HiZData { + /** Scale factor to remove HiZBuffer padding. */ + float2 uv_scale; + + float2 _pad0; +}; +BLI_STATIC_ASSERT_ALIGN(HiZData, 16) + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Ray-Tracing * \{ */ @@ -480,6 +662,34 @@ enum eClosureBits : uint32_t { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Subsurface + * \{ */ + +#define SSS_SAMPLE_MAX 64 +#define SSS_BURLEY_TRUNCATE 16.0 +#define SSS_BURLEY_TRUNCATE_CDF 0.9963790093708328 +#define SSS_TRANSMIT_LUT_SIZE 64.0 +#define SSS_TRANSMIT_LUT_RADIUS 1.218 +#define SSS_TRANSMIT_LUT_SCALE ((SSS_TRANSMIT_LUT_SIZE - 1.0) / float(SSS_TRANSMIT_LUT_SIZE)) +#define SSS_TRANSMIT_LUT_BIAS (0.5 / float(SSS_TRANSMIT_LUT_SIZE)) +#define SSS_TRANSMIT_LUT_STEP_RES 64.0 + +struct SubsurfaceData { + /** xy: 2D sample position [-1..1], zw: sample_bounds. */ + /* NOTE(fclem) Using float4 for alignment. */ + float4 samples[SSS_SAMPLE_MAX]; + /** Sample index after which samples are not randomly rotated anymore. */ + int jitter_threshold; + /** Number of samples precomputed in the set. */ + int sample_len; + int _pad0; + int _pad1; +}; +BLI_STATIC_ASSERT_ALIGN(SubsurfaceData, 16) + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Utility Texture * \{ */ @@ -522,6 +732,13 @@ using DepthOfFieldDataBuf = draw::UniformBuffer<DepthOfFieldData>; using DepthOfFieldScatterListBuf = draw::StorageArrayBuffer<ScatterRect, 16, true>; using DrawIndirectBuf = draw::StorageBuffer<DrawCommand, true>; using FilmDataBuf = draw::UniformBuffer<FilmData>; +using HiZDataBuf = draw::UniformBuffer<HiZData>; +using LightCullingDataBuf = draw::StorageBuffer<LightCullingData>; +using LightCullingKeyBuf = draw::StorageArrayBuffer<uint, LIGHT_CHUNK, true>; +using LightCullingTileBuf = draw::StorageArrayBuffer<uint, LIGHT_CHUNK, true>; +using LightCullingZbinBuf = draw::StorageArrayBuffer<uint, CULLING_ZBIN_COUNT, true>; +using LightCullingZdistBuf = draw::StorageArrayBuffer<float, LIGHT_CHUNK, true>; +using LightDataBuf = draw::StorageArrayBuffer<LightData, LIGHT_CHUNK>; using MotionBlurDataBuf = draw::UniformBuffer<MotionBlurData>; using MotionBlurTileIndirectionBuf = draw::StorageBuffer<MotionBlurTileIndirection, true>; using SamplingDataBuf = draw::StorageBuffer<SamplingData>; diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index c195f68380c..44067aff9ca 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -102,6 +102,8 @@ void ShadingView::render() update_view(); + inst_.hiz_buffer.set_dirty(); + DRW_stats_group_start(name_); DRW_view_set_active(render_view_); @@ -118,6 +120,9 @@ void ShadingView::render() inst_.pipelines.world.render(); + /* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */ + inst_.lights.set_view(render_view_, extent_); + // inst_.pipelines.deferred.render( // render_view_, rt_buffer_opaque_, rt_buffer_refract_, depth_tx_, combined_tx_); @@ -125,16 +130,17 @@ void ShadingView::render() // inst_.lookdev.render_overlay(view_fb_); - inst_.pipelines.forward.render( - render_view_, prepass_fb_, combined_fb_, rbufs.depth_tx, rbufs.combined_tx); + inst_.pipelines.forward.render(render_view_, prepass_fb_, combined_fb_, rbufs.combined_tx); - // inst_.lights.debug_draw(view_fb_); - // inst_.shadows.debug_draw(view_fb_); + inst_.lights.debug_draw(combined_fb_); + inst_.hiz_buffer.debug_draw(combined_fb_); GPUTexture *combined_final_tx = render_postfx(rbufs.combined_tx); inst_.film.accumulate(sub_view_, combined_final_tx); + // inst_.shadows.debug_draw(); + rbufs.release(); postfx_tx_.release(); @@ -176,13 +182,10 @@ void ShadingView::update_view() window_translate_m4(winmat.ptr(), winmat.ptr(), UNPACK2(jitter)); DRW_view_update_sub(sub_view_, viewmat.ptr(), winmat.ptr()); - /* FIXME(fclem): The offset may be is noticeably large and the culling might make object pop + /* FIXME(fclem): The offset may be noticeably large and the culling might make object pop * out of the blurring radius. To fix this, use custom enlarged culling matrix. */ 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_); - // inst_.lights.set_view(render_view_, extent_, !inst_.use_scene_lights()); } /** \} */ 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 index 57f229feedb..99a47c541e9 100644 --- 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 @@ -665,7 +665,7 @@ void dof_slight_focus_gather(sampler2D depth_tx, 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. */ + /* Fix weighting issues on perfectly focus to slight focus transitioning areas. */ if (abs(center_data.coc) < 0.5) { bg_col = center_data.color; bg_weight = 1.0; 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 index c5c0e210109..49c93ca63cd 100644 --- 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 @@ -134,8 +134,8 @@ 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. + * filtering in the resolve pass. Not outputting to a tile means that border texels have + * undefined value and tile border will be noticeable in the final image. */ cache_init(); 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 index e9905cd8aaf..cf8dd7a36e6 100644 --- 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 @@ -2,8 +2,8 @@ /** * 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. + * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene + *color. A fast gather path is taken if there is not many CoC variation inside the tile. * * We sample using an octaweb sampling pattern. We randomize the kernel center and each ring * rotation to ensure maximum coverage. 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 index 2b664520bba..5cdabbc2d4b 100644 --- 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 @@ -2,8 +2,8 @@ /** * 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. + * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene + *color. A fast gather path is taken if there is not many CoC variation inside the tile. * * We sample using an octaweb sampling pattern. We randomize the kernel center and each ring * rotation to ensure maximum coverage. 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 index c757e8304ac..80555367478 100644 --- 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 @@ -8,7 +8,7 @@ * 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). + * - Halfres padded to avoid mipmap misalignment (so possibly not matching input size). * - Gather input color (whole mip chain), Scatter rect list, Signed CoC (whole mip chain). **/ @@ -98,7 +98,7 @@ void main() 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. */ + /* For debugging. */ if (no_scatter_pass) { do_scatter[LOCAL_INDEX] = 0.0; } 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 index d21f6d69541..8873a9da235 100644 --- 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 @@ -36,7 +36,7 @@ float dof_slight_focus_coc_tile_get(vec2 frag_coord) } /* Use atomic reduce operation. */ atomicMax(shared_max_slight_focus_abs_coc, floatBitsToUint(local_abs_max)); - /* "Broadcast" result accross all threads. */ + /* "Broadcast" result across all threads. */ barrier(); return uintBitsToFloat(shared_max_slight_focus_abs_coc); @@ -44,7 +44,7 @@ float dof_slight_focus_coc_tile_get(vec2 frag_coord) vec3 dof_neighborhood_clamp(vec2 frag_coord, vec3 color, float center_coc, float weight) { - /* Stabilize color by clamping with the stable half res neighboorhood. */ + /* Stabilize color by clamping with the stable half res neighborhood. */ 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++) { 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 index b22af0e88f0..5ffedf3068b 100644 --- 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 @@ -211,7 +211,7 @@ vec2 dof_pixel_history_motion_vector(ivec2 texel_sample) return vector.xy * vec2(textureSize(color_tx, 0)); } -/* 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. */ DofSample dof_sample_history(vec2 input_texel) { @@ -285,17 +285,17 @@ float dof_history_blend_factor( /* 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. */ /* 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. + * 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); /* 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 @@ -335,7 +335,7 @@ void main() DofSample dst = dof_sample_history(history_texel); - /* Get local color bounding box of source neighboorhood. */ + /* Get local color bounding box of source neighborhood. */ DofNeighborhoodMinMax bbox = dof_neighbor_boundbox(); float blend = dof_history_blend_factor(velocity, history_texel, bbox, src, dst); 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 bf6293d5561..964c078036b 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 @@ -105,12 +105,18 @@ void film_sample_accum(FilmSample samp, int pass_id, sampler2D tex, inout float accum += texelFetch(tex, samp.texel, 0).x * samp.weight; } -void film_sample_accum(FilmSample samp, int pass_id, sampler2DArray tex, inout vec4 accum) +void film_sample_accum( + FilmSample samp, int pass_id, uint layer, sampler2DArray tex, inout vec4 accum) { if (pass_id == -1) { return; } - accum += texelFetch(tex, ivec3(samp.texel, pass_id), 0) * samp.weight; + accum += texelFetch(tex, ivec3(samp.texel, layer), 0) * samp.weight; +} + +void film_sample_accum(FilmSample samp, int pass_id, sampler2DArray tex, inout vec4 accum) +{ + film_sample_accum(samp, pass_id, pass_id, tex, accum); } void film_sample_accum(FilmSample samp, int pass_id, sampler2DArray tex, inout float accum) @@ -632,8 +638,16 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth for (int i = 0; i < film_buf.samples_len; i++) { FilmSample src = film_sample_get(i, texel_film); - film_sample_accum(src, film_buf.diffuse_light_id, diffuse_light_tx, diffuse_light_accum); - film_sample_accum(src, film_buf.specular_light_id, specular_light_tx, specular_light_accum); + film_sample_accum(src, + film_buf.diffuse_light_id, + RENDER_PASS_LAYER_DIFFUSE_LIGHT, + light_tx, + diffuse_light_accum); + film_sample_accum(src, + film_buf.specular_light_id, + RENDER_PASS_LAYER_SPECULAR_LIGHT, + light_tx, + specular_light_accum); film_sample_accum(src, film_buf.volume_light_id, volume_light_tx, volume_light_accum); film_sample_accum(src, film_buf.emission_id, emission_tx, emission_accum); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_debug_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_debug_frag.glsl new file mode 100644 index 00000000000..e93d0f472fa --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_debug_frag.glsl @@ -0,0 +1,24 @@ + +/** + * Debug hiz down sampling pass. + * Output red if above any max pixels, blue otherwise. + */ + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + + float depth0 = texelFetch(hiz_tx, texel, 0).r; + + vec4 color = vec4(0.1, 0.1, 1.0, 1.0); + for (int i = 1; i < HIZ_MIP_COUNT; i++) { + ivec2 lvl_texel = texel / ivec2(uvec2(1) << uint(i)); + lvl_texel = min(lvl_texel, textureSize(hiz_tx, i) - 1); + if (texelFetch(hiz_tx, lvl_texel, i).r < depth0) { + color = vec4(1.0, 0.1, 0.1, 1.0); + break; + } + } + out_debug_color_add = vec4(color.rgb, 0.0) * 0.2; + out_debug_color_mul = color; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl new file mode 100644 index 00000000000..597bc73e2ad --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl @@ -0,0 +1,121 @@ + +/** + * Shader that down-sample depth buffer, creating a Hierarchical-Z buffer. + * Saves max value of each 2x2 texel in the mipmap above the one we are + * rendering to. Adapted from + * http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/ + * + * Major simplification has been made since we pad the buffer to always be + * bigger than input to avoid mipmapping misalignement. + * + * Start by copying the base level by quad loading the depth. + * Then each thread compute it's local depth for level 1. + * After that we use shared variables to do inter thread comunication and + * downsample to max level. + */ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +shared float local_depths[gl_WorkGroupSize.y][gl_WorkGroupSize.x]; + +/* Load values from the previous lod level. */ +vec4 load_local_depths(ivec2 pixel) +{ + pixel *= 2; + return vec4(local_depths[pixel.y + 1][pixel.x + 0], + local_depths[pixel.y + 1][pixel.x + 1], + local_depths[pixel.y + 0][pixel.x + 1], + local_depths[pixel.y + 0][pixel.x + 0]); +} + +void store_local_depth(ivec2 pixel, float depth) +{ + local_depths[pixel.y][pixel.x] = depth; +} + +void main() +{ + ivec2 local_px = ivec2(gl_LocalInvocationID.xy); + /* Bottom left corner of the kernel. */ + ivec2 kernel_origin = ivec2(gl_WorkGroupSize.xy * gl_WorkGroupID.xy); + + /* Copy level 0. */ + ivec2 src_px = ivec2(kernel_origin + local_px) * 2; + vec2 samp_co = (vec2(src_px) + 0.5) / vec2(textureSize(depth_tx, 0)); + vec4 samp = textureGather(depth_tx, samp_co); + + if (update_mip_0) { + imageStore(out_mip_0, src_px + ivec2(0, 1), samp.xxxx); + imageStore(out_mip_0, src_px + ivec2(1, 1), samp.yyyy); + imageStore(out_mip_0, src_px + ivec2(1, 0), samp.zzzz); + imageStore(out_mip_0, src_px + ivec2(0, 0), samp.wwww); + } + + /* Level 1. (No load) */ + float max_depth = max_v4(samp); + ivec2 dst_px = ivec2(kernel_origin + local_px); + imageStore(out_mip_1, dst_px, vec4(max_depth)); + store_local_depth(local_px, max_depth); + + /* Level 2-5. */ + bool active_thread; + int mask_shift = 1; + +#define downsample_level(out_mip__, lod_) \ + active_thread = all(lessThan(local_px, gl_WorkGroupSize.xy >> uint(mask_shift))); \ + barrier(); /* Wait for previous writes to finish. */ \ + if (active_thread) { \ + max_depth = max_v4(load_local_depths(local_px)); \ + dst_px = ivec2((kernel_origin >> mask_shift) + local_px); \ + imageStore(out_mip__, dst_px, vec4(max_depth)); \ + } \ + barrier(); /* Wait for previous reads to finish. */ \ + if (active_thread) { \ + store_local_depth(local_px, max_depth); \ + } \ + mask_shift++; + + downsample_level(out_mip_2, 2); + downsample_level(out_mip_3, 3); + downsample_level(out_mip_4, 4); + downsample_level(out_mip_5, 5); + + /* Since we pad the destination texture, the mip size is equal to the dispatch size. */ + uint tile_count = uint(imageSize(out_mip_5).x * imageSize(out_mip_5).y); + /* Let the last tile handle the remaining LOD. */ + bool last_tile = atomicAdd(finished_tile_counter, 1u) + 1u < tile_count; + if (last_tile == false) { + return; + } + finished_tile_counter = 0u; + + ivec2 iter = divide_ceil(imageSize(out_mip_5), ivec2(gl_WorkGroupSize * 2u)); + ivec2 image_border = imageSize(out_mip_5) - 1; + for (int y = 0; y < iter.y; y++) { + for (int x = 0; x < iter.x; x++) { + /* Load result of the other work groups. */ + kernel_origin = ivec2(gl_WorkGroupSize) * ivec2(x, y); + src_px = ivec2(kernel_origin + local_px) * 2; + vec4 samp; + samp.x = imageLoad(out_mip_5, min(src_px + ivec2(0, 1), image_border)).x; + samp.y = imageLoad(out_mip_5, min(src_px + ivec2(1, 1), image_border)).x; + samp.z = imageLoad(out_mip_5, min(src_px + ivec2(1, 0), image_border)).x; + samp.w = imageLoad(out_mip_5, min(src_px + ivec2(0, 0), image_border)).x; + /* Level 6. */ + float max_depth = max_v4(samp); + ivec2 dst_px = ivec2(kernel_origin + local_px); + imageStore(out_mip_6, dst_px, vec4(max_depth)); + store_local_depth(local_px, max_depth); + + mask_shift = 1; + + /* Level 7. */ + downsample_level(out_mip_7, 7); + + /* Limited by OpenGL maximum of 8 image slot. */ + // downsample_level(out_mip_8, 8); + // downsample_level(out_mip_9, 9); + // downsample_level(out_mip_10, 10); + } + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_debug_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_debug_frag.glsl new file mode 100644 index 00000000000..eefc024d0b8 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_debug_frag.glsl @@ -0,0 +1,54 @@ + +/** + * Debug Shader outputing a gradient of orange - white - blue to mark culling hotspots. + * Green pixels are error pixels that are missing lights from the culling pass (i.e: when culling + * pass is not conservative enough). + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + + float depth = texelFetch(hiz_tx, texel, 0).r; + float vP_z = get_view_z_from_depth(depth); + vec3 P = get_world_space_from_depth(uvcoordsvar.xy, depth); + + float light_count = 0.0; + uint light_cull = 0u; + vec2 px = gl_FragCoord.xy; + LIGHT_FOREACH_BEGIN_LOCAL(light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx) + { + LightData light = light_buf[l_idx]; + light_cull |= 1u << l_idx; + light_count += 1.0; + } + LIGHT_FOREACH_END + + uint light_nocull = 0u; + LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(light_cull_buf, l_idx) + { + LightData light = light_buf[l_idx]; + vec3 L; + float dist; + light_vector_get(light, P, L, dist); + if (light_attenuation(light, L, dist) > 0.0) { + light_nocull |= 1u << l_idx; + } + } + LIGHT_FOREACH_END + + vec4 color = vec4(heatmap_gradient(light_count / 4.0), 1.0); + + if ((light_cull & light_nocull) != light_nocull) { + /* ERROR. Some lights were culled incorrectly. */ + color = vec4(0.0, 1.0, 0.0, 1.0); + } + + out_debug_color_add = vec4(color.rgb, 0.0) * 0.2; + out_debug_color_mul = color; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_select_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_select_comp.glsl new file mode 100644 index 00000000000..9c12b0e50e6 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_select_comp.glsl @@ -0,0 +1,62 @@ + +/** + * Select the visible items inside the active view and put them inside the sorting buffer. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(common_intersect_lib.glsl) + +void main() +{ + uint l_idx = gl_GlobalInvocationID.x; + if (l_idx >= light_cull_buf.items_count) { + return; + } + + LightData light = in_light_buf[l_idx]; + + /* Do not select 0 power lights. */ + if (light.influence_radius_max < 1e-8) { + return; + } + + /* Sun lights are packed at the end of the array. Perform early copy. */ + if (light.type == LIGHT_SUN) { + /* NOTE: We know the index because sun lights are packed at the start of the input buffer. */ + out_light_buf[light_cull_buf.local_lights_len + l_idx] = light; + return; + } + + Sphere sphere; + switch (light.type) { + case LIGHT_SPOT: + /* Only for < ~170° Cone due to plane extraction precision. */ + if (light.spot_tan < 10.0) { + Pyramid pyramid = shape_pyramid_non_oblique( + light._position, + light._position - light._back * light.influence_radius_max, + light._right * light.influence_radius_max * light.spot_tan / light.spot_size_inv.x, + light._up * light.influence_radius_max * light.spot_tan / light.spot_size_inv.y); + if (!intersect_view(pyramid)) { + return; + } + } + case LIGHT_RECT: + case LIGHT_ELLIPSE: + case LIGHT_POINT: + sphere = Sphere(light._position, light.influence_radius_max); + break; + } + + /* TODO(fclem): HiZ culling? Could be quite beneficial given the nature of the 2.5D culling. */ + + /* TODO(fclem): Small light culling / fading? */ + + if (intersect_view(sphere)) { + uint index = atomicAdd(light_cull_buf.visible_count, 1u); + + out_zdist_buf[index] = dot(cameraForward, light._position) - dot(cameraForward, cameraPos); + out_key_buf[index] = l_idx; + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_sort_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_sort_comp.glsl new file mode 100644 index 00000000000..e98b170cd4c --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_sort_comp.glsl @@ -0,0 +1,57 @@ + +/** + * Sort the lights by their Z distance to the camera. + * Outputs ordered light buffer. + * One thread processes one Light entity. + */ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +shared float zdists_cache[gl_WorkGroupSize.x]; + +void main() +{ + uint src_index = gl_GlobalInvocationID.x; + bool valid_thread = true; + + if (src_index >= light_cull_buf.visible_count) { + /* Do not return because we use barriers later on (which need uniform control flow). + * Just process the same last item but avoid insertion. */ + src_index = light_cull_buf.visible_count - 1; + valid_thread = false; + } + + float local_zdist = in_zdist_buf[src_index]; + + int prefix_sum = 0; + /* Iterate over the whole key buffer. */ + uint iter = divide_ceil(light_cull_buf.visible_count, gl_WorkGroupSize.x); + for (uint i = 0u; i < iter; i++) { + uint index = gl_WorkGroupSize.x * i + gl_LocalInvocationID.x; + /* NOTE: This will load duplicated values, but they will be discarded. */ + index = min(index, light_cull_buf.visible_count - 1); + zdists_cache[gl_LocalInvocationID.x] = in_zdist_buf[index]; + + barrier(); + + /* Iterate over the cache line. */ + uint line_end = min(gl_WorkGroupSize.x, light_cull_buf.visible_count - gl_WorkGroupSize.x * i); + for (uint j = 0u; j < line_end; j++) { + if (zdists_cache[j] < local_zdist) { + prefix_sum++; + } + else if (zdists_cache[j] == local_zdist) { + /* Same depth, use index to order and avoid same prefix for 2 different lights. */ + if ((gl_WorkGroupSize.x * i + j) < src_index) { + prefix_sum++; + } + } + } + } + + if (valid_thread) { + /* Copy sorted light to render light buffer. */ + uint input_index = in_key_buf[src_index]; + out_light_buf[prefix_sum] = in_light_buf[input_index]; + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl new file mode 100644 index 00000000000..37705e22b22 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl @@ -0,0 +1,188 @@ + +/** + * 2D Culling pass for lights. + * We iterate over all items and check if they intersect with the tile frustum. + * Dispatch one thread per word. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_intersect_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl) + +/* ---------------------------------------------------------------------- */ +/** \name Culling shapes extraction + * \{ */ + +struct CullingTile { + IsectFrustum frustum; + vec4 bounds; +}; + +/* Corners are expected to be in viewspace so that the cone is starting from the origin. + * Corner order does not matter. */ +vec4 tile_bound_cone(vec3 v00, vec3 v01, vec3 v10, vec3 v11) +{ + v00 = normalize(v00); + v01 = normalize(v01); + v10 = normalize(v10); + v11 = normalize(v11); + vec3 center = normalize(v00 + v01 + v10 + v11); + float angle_cosine = dot(center, v00); + angle_cosine = max(angle_cosine, dot(center, v01)); + angle_cosine = max(angle_cosine, dot(center, v10)); + angle_cosine = max(angle_cosine, dot(center, v11)); + return vec4(center, angle_cosine); +} + +/* Corners are expected to be in viewspace. Returns Z-aligned bounding cylinder. + * Corner order does not matter. */ +vec4 tile_bound_cylinder(vec3 v00, vec3 v01, vec3 v10, vec3 v11) +{ + vec3 center = (v00 + v01 + v10 + v11) * 0.25; + vec4 corners_dist; + float dist_sqr = distance_squared(center, v00); + dist_sqr = max(dist_sqr, distance_squared(center, v01)); + dist_sqr = max(dist_sqr, distance_squared(center, v10)); + dist_sqr = max(dist_sqr, distance_squared(center, v11)); + /* Return a cone. Later converted to cylinder. */ + return vec4(center, sqrt(dist_sqr)); +} + +vec2 tile_to_ndc(vec2 tile_co, vec2 offset) +{ + /* Add a margin to prevent culling too much if the frustum becomes too much unstable. */ + const float margin = 0.02; + tile_co += margin * (offset * 2.0 - 1.0); + + tile_co += offset; + return tile_co * light_cull_buf.tile_to_uv_fac * 2.0 - 1.0; +} + +CullingTile tile_culling_get(uvec2 tile_co) +{ + vec2 ftile = vec2(tile_co); + /* Culling frustum corners for this tile. */ + vec3 corners[8]; + /* Follow same corners order as view frustum. */ + corners[1].xy = corners[0].xy = tile_to_ndc(ftile, vec2(0, 0)); + corners[5].xy = corners[4].xy = tile_to_ndc(ftile, vec2(1, 0)); + corners[6].xy = corners[7].xy = tile_to_ndc(ftile, vec2(1, 1)); + corners[2].xy = corners[3].xy = tile_to_ndc(ftile, vec2(0, 1)); + corners[1].z = corners[5].z = corners[6].z = corners[2].z = -1.0; + corners[0].z = corners[4].z = corners[7].z = corners[3].z = 1.0; + + for (int i = 0; i < 8; i++) { + /* Culling in view space for precision. */ + corners[i] = project_point(ProjectionMatrixInverse, corners[i]); + } + + bool is_persp = ProjectionMatrix[3][3] == 0.0; + CullingTile tile; + tile.bounds = (is_persp) ? tile_bound_cone(corners[0], corners[4], corners[7], corners[3]) : + tile_bound_cylinder(corners[0], corners[4], corners[7], corners[3]); + + tile.frustum = isect_data_setup(shape_frustum(corners)); + return tile; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Intersection Tests + * \{ */ + +bool intersect(CullingTile tile, Sphere sphere) +{ + bool isect = true; + /* Test tile intersection using bounding cone or bounding cylinder. + * This has less false positive cases when the sphere is large. */ + if (ProjectionMatrix[3][3] == 0.0) { + isect = intersect(shape_cone(tile.bounds.xyz, tile.bounds.w), sphere); + } + else { + /* Simplify to a 2D circle test on the view Z axis plane. */ + isect = intersect(shape_circle(tile.bounds.xy, tile.bounds.w), + shape_circle(sphere.center.xy, sphere.radius)); + } + /* Refine using frustum test. If the sphere is small it avoids intersection + * with a neighbor tile. */ + if (isect) { + isect = intersect(tile.frustum, sphere); + } + return isect; +} + +bool intersect(CullingTile tile, Box bbox) +{ + return intersect(tile.frustum, bbox); +} + +bool intersect(CullingTile tile, Pyramid pyramid) +{ + return intersect(tile.frustum, pyramid); +} + +/** \} */ + +void main() +{ + uint word_idx = gl_GlobalInvocationID.x % light_cull_buf.tile_word_len; + uint tile_idx = gl_GlobalInvocationID.x / light_cull_buf.tile_word_len; + uvec2 tile_co = uvec2(tile_idx % light_cull_buf.tile_x_len, + tile_idx / light_cull_buf.tile_x_len); + + if (tile_co.y >= light_cull_buf.tile_y_len) { + return; + } + + /* TODO(fclem): We could stop the tile at the HiZ depth. */ + CullingTile tile = tile_culling_get(tile_co); + + uint l_idx = word_idx * 32u; + uint l_end = min(l_idx + 32u, light_cull_buf.visible_count); + uint word = 0u; + for (; l_idx < l_end; l_idx++) { + LightData light = light_buf[l_idx]; + + /* Culling in view space for precision and simplicity. */ + vec3 vP = transform_point(ViewMatrix, light._position); + vec3 v_right = transform_direction(ViewMatrix, light._right); + vec3 v_up = transform_direction(ViewMatrix, light._up); + vec3 v_back = transform_direction(ViewMatrix, light._back); + float radius = light.influence_radius_max; + + Sphere sphere = shape_sphere(vP, radius); + bool intersect_tile = intersect(tile, sphere); + + switch (light.type) { + case LIGHT_SPOT: + /* Only for < ~170° Cone due to plane extraction precision. */ + if (light.spot_tan < 10.0) { + Pyramid pyramid = shape_pyramid_non_oblique( + vP, + vP - v_back * radius, + v_right * radius * light.spot_tan / light.spot_size_inv.x, + v_up * radius * light.spot_tan / light.spot_size_inv.y); + intersect_tile = intersect_tile && intersect(tile, pyramid); + break; + } + /* Fallthrough to the hemispheric case. */ + case LIGHT_RECT: + case LIGHT_ELLIPSE: + vec3 v000 = vP - v_right * radius - v_up * radius; + vec3 v100 = v000 + v_right * (radius * 2.0); + vec3 v010 = v000 + v_up * (radius * 2.0); + vec3 v001 = v000 - v_back * radius; + Box bbox = shape_box(v000, v100, v010, v001); + intersect_tile = intersect_tile && intersect(tile, bbox); + default: + break; + } + + if (intersect_tile) { + word |= 1u << (l_idx % 32u); + } + } + + out_light_tile_buf[gl_GlobalInvocationID.x] = word; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_zbin_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_zbin_comp.glsl new file mode 100644 index 00000000000..ae20153f26c --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_zbin_comp.glsl @@ -0,0 +1,56 @@ + +/** + * Create the Zbins from Z-sorted lights. + * Perform min-max operation in LDS memory for speed. + * For this reason, we only dispatch 1 thread group. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl) + +/* Fits the limit of 32KB. */ +shared uint zbin_max[CULLING_ZBIN_COUNT]; +shared uint zbin_min[CULLING_ZBIN_COUNT]; + +void main() +{ + const uint zbin_iter = CULLING_ZBIN_COUNT / gl_WorkGroupSize.x; + const uint zbin_local = gl_LocalInvocationID.x * zbin_iter; + + uint src_index = gl_GlobalInvocationID.x; + + for (uint i = 0u, l = zbin_local; i < zbin_iter; i++, l++) { + zbin_max[l] = 0x0u; + zbin_min[l] = ~0x0u; + } + barrier(); + + uint light_iter = divide_ceil(light_cull_buf.visible_count, gl_WorkGroupSize.x); + for (uint i = 0u; i < light_iter; i++) { + uint index = i * gl_WorkGroupSize.x + gl_LocalInvocationID.x; + if (index >= light_cull_buf.visible_count) { + continue; + } + vec3 P = light_buf[index]._position; + /* TODO(fclem): Could have better bounds for spot and area lights. */ + float radius = light_buf[index].influence_radius_max; + float z_dist = dot(cameraForward, P) - dot(cameraForward, cameraPos); + int z_min = culling_z_to_zbin( + light_cull_buf.zbin_scale, light_cull_buf.zbin_bias, z_dist + radius); + int z_max = culling_z_to_zbin( + light_cull_buf.zbin_scale, light_cull_buf.zbin_bias, z_dist - radius); + z_min = clamp(z_min, 0, CULLING_ZBIN_COUNT - 1); + z_max = clamp(z_max, 0, CULLING_ZBIN_COUNT - 1); + /* Register to Z bins. */ + for (int z = z_min; z <= z_max; z++) { + atomicMin(zbin_min[z], index); + atomicMax(zbin_max[z], index); + } + } + barrier(); + + /* Write result to zbins buffer. Pack min & max into 1 uint. */ + for (uint i = 0u, l = zbin_local; i < zbin_iter; i++, l++) { + out_zbin_buf[l] = (zbin_max[l] << 16u) | (zbin_min[l] & 0xFFFFu); + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl new file mode 100644 index 00000000000..d4abdd43aa4 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl @@ -0,0 +1,129 @@ + +/** + * The resources expected to be defined are: + * - light_buf + * - light_zbin_buf + * - light_cull_buf + * - light_tile_buf + * - shadow_atlas_tx + * - shadow_tilemaps_tx + * - sss_transmittance_tx + * - utility_tx + */ + +#pragma BLENDER_REQUIRE(eevee_light_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl) + +/* TODO(fclem): We could reduce register pressure by only having static branches for sun lights. */ +void light_eval_ex(ClosureDiffuse diffuse, + ClosureReflection reflection, + const bool is_directional, + vec3 P, + vec3 V, + float vP_z, + float thickness, + vec4 ltc_mat, + uint l_idx, + inout vec3 out_diffuse, + inout vec3 out_specular) +{ + LightData light = light_buf[l_idx]; + vec3 L; + float dist; + light_vector_get(light, P, L, dist); + + float visibility = light_attenuation(light, L, dist); + +#if 0 /* TODO(fclem): Shadows */ + if ((light.shadow_id != LIGHT_NO_SHADOW) && (visibility > 0.0)) { + vec3 lL = light_world_to_local(light, -L) * dist; + + float shadow_delta = shadow_delta_get( + shadow_atlas_tx, shadow_tilemaps_tx, light, light.shadow_data, lL, dist, P); + +# ifdef SSS_TRANSMITTANCE + /* Transmittance evaluation first to use initial visibility. */ + if (diffuse.sss_id != 0u && light.diffuse_power > 0.0) { + float delta = max(thickness, shadow_delta); + + vec3 intensity = visibility * light.transmit_power * + light_translucent(sss_transmittance_tx, + is_directional, + light, + diffuse.N, + L, + dist, + diffuse.sss_radius, + delta); + out_diffuse += light.color * intensity; + } +# endif + + visibility *= float(shadow_delta - light.shadow_data.bias <= 0.0); + } +#endif + + if (visibility < 1e-6) { + return; + } + + if (light.diffuse_power > 0.0) { + float intensity = visibility * light.diffuse_power * + light_diffuse(utility_tx, is_directional, light, diffuse.N, V, L, dist); + out_diffuse += light.color * intensity; + } + + if (light.specular_power > 0.0) { + float intensity = visibility * light.specular_power * + light_ltc( + utility_tx, is_directional, light, reflection.N, V, L, dist, ltc_mat); + out_specular += light.color * intensity; + } +} + +void light_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + vec3 P, + vec3 V, + float vP_z, + float thickness, + inout vec3 out_diffuse, + inout vec3 out_specular) +{ + vec2 uv = vec2(reflection.roughness, safe_sqrt(1.0 - dot(reflection.N, V))); + uv = uv * UTIL_TEX_UV_SCALE + UTIL_TEX_UV_BIAS; + vec4 ltc_mat = utility_tx_sample(utility_tx, uv, UTIL_LTC_MAT_LAYER); + + LIGHT_FOREACH_BEGIN_DIRECTIONAL(light_cull_buf, l_idx) + { + light_eval_ex(diffuse, + reflection, + true, + P, + V, + vP_z, + thickness, + ltc_mat, + l_idx, + out_diffuse, + out_specular); + } + LIGHT_FOREACH_END + + vec2 px = gl_FragCoord.xy; + LIGHT_FOREACH_BEGIN_LOCAL(light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx) + { + light_eval_ex(diffuse, + reflection, + false, + P, + V, + vP_z, + thickness, + ltc_mat, + l_idx, + out_diffuse, + out_specular); + } + LIGHT_FOREACH_END +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_iter_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_iter_lib.glsl new file mode 100644 index 00000000000..22a5f98e6c3 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_iter_lib.glsl @@ -0,0 +1,72 @@ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +uint zbin_mask(uint word_index, uint zbin_min, uint zbin_max) +{ + uint word_start = word_index * 32u; + uint word_end = word_start + 31u; + uint local_min = max(zbin_min, word_start); + uint local_max = min(zbin_max, word_end); + uint mask_width = local_max - local_min + 1; + return bit_field_mask(mask_width, local_min); +} + +int culling_z_to_zbin(float scale, float bias, float z) +{ + return int(z * scale + bias); +} + +/* Waiting to implement extensions support. We need: + * - GL_KHR_shader_subgroup_ballot + * - GL_KHR_shader_subgroup_arithmetic + * or + * - Vulkan 1.1 + */ +#if 1 +# define subgroupMin(a) a +# define subgroupMax(a) a +# define subgroupOr(a) a +# define subgroupBroadcastFirst(a) a +#endif + +#define LIGHT_FOREACH_BEGIN_DIRECTIONAL(_culling, _index) \ + { \ + { \ + for (uint _index = _culling.local_lights_len; _index < _culling.items_count; _index++) { + +#define LIGHT_FOREACH_BEGIN_LOCAL(_culling, _zbins, _words, _pixel, _linearz, _item_index) \ + { \ + uvec2 tile_co = uvec2(_pixel / _culling.tile_size); \ + uint tile_word_offset = (tile_co.x + tile_co.y * _culling.tile_x_len) * \ + _culling.tile_word_len; \ + int zbin_index = culling_z_to_zbin(_culling.zbin_scale, _culling.zbin_bias, _linearz); \ + zbin_index = clamp(zbin_index, 0, CULLING_ZBIN_COUNT - 1); \ + uint zbin_data = _zbins[zbin_index]; \ + uint min_index = zbin_data & 0xFFFFu; \ + uint max_index = zbin_data >> 16u; \ + /* Ensure all threads inside a subgroup get the same value to reduce VGPR usage. */ \ + min_index = subgroupBroadcastFirst(subgroupMin(min_index)); \ + max_index = subgroupBroadcastFirst(subgroupMax(max_index)); \ + /* Same as divide by 32 but avoid interger division. */ \ + uint word_min = min_index >> 5u; \ + uint word_max = max_index >> 5u; \ + for (uint word_idx = word_min; word_idx <= word_max; word_idx++) { \ + uint word = _words[tile_word_offset + word_idx]; \ + word &= zbin_mask(word_idx, min_index, max_index); \ + /* Ensure all threads inside a subgroup get the same value to reduce VGPR usage. */ \ + word = subgroupBroadcastFirst(subgroupOr(word)); \ + int bit_index; \ + while ((bit_index = findLSB(word)) != -1) { \ + word &= ~1u << uint(bit_index); \ + uint _item_index = word_idx * 32u + bit_index; + +/* No culling. Iterate over all items. */ +#define LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(_culling, _item_index) \ + { \ + { \ + for (uint _item_index = 0; _item_index < _culling.visible_count; _item_index++) { + +#define LIGHT_FOREACH_END \ + } \ + } \ + } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl new file mode 100644 index 00000000000..58608f6e1f0 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl @@ -0,0 +1,209 @@ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_ltc_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl) + +/* ---------------------------------------------------------------------- */ +/** \name Light Functions + * \{ */ + +void light_vector_get(LightData ld, vec3 P, out vec3 L, out float dist) +{ + if (ld.type == LIGHT_SUN) { + L = ld._back; + dist = 1.0; + } + else { + L = ld._position - P; + dist = inversesqrt(len_squared(L)); + L *= dist; + dist = 1.0 / dist; + } +} + +/* Rotate vector to light's local space. Does not translate. */ +vec3 light_world_to_local(LightData ld, vec3 L) +{ + /* Avoid relying on compiler to optimize this. + * vec3 lL = transpose(mat3(ld.object_mat)) * L; */ + vec3 lL; + lL.x = dot(ld.object_mat[0].xyz, L); + lL.y = dot(ld.object_mat[1].xyz, L); + lL.z = dot(ld.object_mat[2].xyz, L); + return lL; +} + +/* From Frostbite PBR Course + * Distance based attenuation + * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */ +float light_influence_attenuation(float dist, float inv_sqr_influence) +{ + float factor = sqr(dist) * inv_sqr_influence; + float fac = saturate(1.0 - sqr(factor)); + return sqr(fac); +} + +float light_spot_attenuation(LightData ld, vec3 L) +{ + vec3 lL = light_world_to_local(ld, L); + float ellipse = inversesqrt(1.0 + len_squared(lL.xy * ld.spot_size_inv / lL.z)); + float spotmask = smoothstep(0.0, 1.0, ellipse * ld._spot_mul + ld._spot_bias); + return spotmask; +} + +float light_attenuation(LightData ld, vec3 L, float dist) +{ + float vis = 1.0; + if (ld.type == LIGHT_SPOT) { + vis *= light_spot_attenuation(ld, L); + } + if (ld.type >= LIGHT_SPOT) { + vis *= step(0.0, -dot(L, -ld._back)); + } + if (ld.type != LIGHT_SUN) { +#ifdef VOLUME_LIGHTING + vis *= light_influence_attenuation(dist, ld.influence_radius_invsqr_volume); +#else + vis *= light_influence_attenuation(dist, ld.influence_radius_invsqr_surface); +#endif + } + return vis; +} + +/* Cheaper alternative than evaluating the LTC. + * The result needs to be multiplied by BSDF or Phase Function. */ +float light_point_light(LightData ld, const bool is_directional, vec3 L, float dist) +{ + if (is_directional) { + return 1.0; + } + /** + * Using "Point Light Attenuation Without Singularity" from Cem Yuksel + * http://www.cemyuksel.com/research/pointlightattenuation/pointlightattenuation.pdf + * http://www.cemyuksel.com/research/pointlightattenuation/ + **/ + float d_sqr = sqr(dist); + float r_sqr = ld.radius_squared; + /* Using reformulation that has better numerical percision. */ + float power = 2.0 / (d_sqr + r_sqr + dist * sqrt(d_sqr + r_sqr)); + + if (is_area_light(ld.type)) { + /* Modulate by light plane orientation / solid angle. */ + power *= saturate(dot(ld._back, L)); + } + return power; +} + +float light_diffuse(sampler2DArray utility_tx, + const bool is_directional, + LightData ld, + vec3 N, + vec3 V, + vec3 L, + float dist) +{ + if (is_directional || !is_area_light(ld.type)) { + float radius = ld._radius / dist; + return ltc_evaluate_disk_simple(utility_tx, radius, dot(N, L)); + } + else if (ld.type == LIGHT_RECT) { + vec3 corners[4]; + corners[0] = ld._right * ld._area_size_x + ld._up * -ld._area_size_y; + corners[1] = ld._right * ld._area_size_x + ld._up * ld._area_size_y; + corners[2] = -corners[0]; + corners[3] = -corners[1]; + + corners[0] = normalize(L * dist + corners[0]); + corners[1] = normalize(L * dist + corners[1]); + corners[2] = normalize(L * dist + corners[2]); + corners[3] = normalize(L * dist + corners[3]); + + return ltc_evaluate_quad(utility_tx, corners, N); + } + else /* (ld.type == LIGHT_ELLIPSE) */ { + vec3 points[3]; + points[0] = ld._right * -ld._area_size_x + ld._up * -ld._area_size_y; + points[1] = ld._right * ld._area_size_x + ld._up * -ld._area_size_y; + points[2] = -points[0]; + + points[0] += L * dist; + points[1] += L * dist; + points[2] += L * dist; + + return ltc_evaluate_disk(utility_tx, N, V, mat3(1.0), points); + } +} + +float light_ltc(sampler2DArray utility_tx, + const bool is_directional, + LightData ld, + vec3 N, + vec3 V, + vec3 L, + float dist, + vec4 ltc_mat) +{ + if (is_directional || ld.type != LIGHT_RECT) { + vec3 Px = ld._right; + vec3 Py = ld._up; + + if (is_directional || !is_area_light(ld.type)) { + make_orthonormal_basis(L, Px, Py); + } + + vec3 points[3]; + points[0] = Px * -ld._area_size_x + Py * -ld._area_size_y; + points[1] = Px * ld._area_size_x + Py * -ld._area_size_y; + points[2] = -points[0]; + + points[0] += L * dist; + points[1] += L * dist; + points[2] += L * dist; + + return ltc_evaluate_disk(utility_tx, N, V, ltc_matrix(ltc_mat), points); + } + else { + vec3 corners[4]; + corners[0] = ld._right * ld._area_size_x + ld._up * -ld._area_size_y; + corners[1] = ld._right * ld._area_size_x + ld._up * ld._area_size_y; + corners[2] = -corners[0]; + corners[3] = -corners[1]; + + corners[0] += L * dist; + corners[1] += L * dist; + corners[2] += L * dist; + corners[3] += L * dist; + + ltc_transform_quad(N, V, ltc_matrix(ltc_mat), corners); + + return ltc_evaluate_quad(utility_tx, corners, vec3(0.0, 0.0, 1.0)); + } +} + +vec3 light_translucent(sampler1D transmittance_tx, + const bool is_directional, + LightData ld, + vec3 N, + vec3 L, + float dist, + vec3 sss_radius, + float delta) +{ + /* TODO(fclem): We should compute the power at the entry point. */ + /* NOTE(fclem): we compute the light attenuation using the light vector but the transmittance + * using the shadow depth delta. */ + float power = light_point_light(ld, is_directional, L, dist); + /* Do not add more energy on front faces. Also apply lambertian BSDF. */ + power *= max(0.0, dot(-N, L)) * M_1_PI; + + sss_radius *= SSS_TRANSMIT_LUT_RADIUS; + vec3 channels_co = saturate(delta / sss_radius) * SSS_TRANSMIT_LUT_SCALE + SSS_TRANSMIT_LUT_BIAS; + + vec3 translucency; + translucency.x = (sss_radius.x > 0.0) ? texture(transmittance_tx, channels_co.x).r : 0.0; + translucency.y = (sss_radius.y > 0.0) ? texture(transmittance_tx, channels_co.y).r : 0.0; + translucency.z = (sss_radius.z > 0.0) ? texture(transmittance_tx, channels_co.z).r : 0.0; + return translucency * power; +} + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ltc_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ltc_lib.glsl new file mode 100644 index 00000000000..57e92b0b9b4 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ltc_lib.glsl @@ -0,0 +1,299 @@ + +/** + * Adapted from : + * Real-Time Polygonal-Light Shading with Linearly Transformed Cosines. + * Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt. + * ACM Transactions on Graphics (Proceedings of ACM SIGGRAPH 2016) 35(4), 2016. + * Project page: https://eheitzresearch.wordpress.com/415-2/ + */ + +/* Diffuse *clipped* sphere integral. */ +float ltc_diffuse_sphere_integral(sampler2DArray utility_tx, float avg_dir_z, float form_factor) +{ +#if 1 + /* use tabulated horizon-clipped sphere */ + vec2 uv = vec2(avg_dir_z * 0.5 + 0.5, form_factor); + uv = uv * UTIL_TEX_UV_SCALE + UTIL_TEX_UV_BIAS; + + return texture(utility_tx, vec3(uv, UTIL_DISK_INTEGRAL_LAYER))[UTIL_DISK_INTEGRAL_COMP]; +#else + /* Cheap approximation. Less smooth and have energy issues. */ + return max((form_factor * form_factor + avg_dir_z) / (form_factor + 1.0), 0.0); +#endif +} + +/** + * An extended version of the implementation from + * "How to solve a cubic equation, revisited" + * http://momentsingraphics.de/?p=105 + */ +vec3 ltc_solve_cubic(vec4 coefs) +{ + /* Normalize the polynomial */ + coefs.xyz /= coefs.w; + /* Divide middle coefficients by three */ + coefs.yz /= 3.0; + + float A = coefs.w; + float B = coefs.z; + float C = coefs.y; + float D = coefs.x; + + /* Compute the Hessian and the discriminant */ + vec3 delta = vec3(-coefs.zy * coefs.zz + coefs.yx, dot(vec2(coefs.z, -coefs.y), coefs.xy)); + + /* Discriminant */ + float discr = dot(vec2(4.0 * delta.x, -delta.y), delta.zy); + + /* Clamping avoid NaN output on some platform. (see T67060) */ + float sqrt_discr = sqrt(clamp(discr, 0.0, FLT_MAX)); + + vec2 xlc, xsc; + + /* Algorithm A */ + { + float A_a = 1.0; + float C_a = delta.x; + float D_a = -2.0 * B * delta.x + delta.y; + + /* Take the cubic root of a normalized complex number */ + float theta = atan(sqrt_discr, -D_a) / 3.0; + + float _2_sqrt_C_a = 2.0 * sqrt(-C_a); + float x_1a = _2_sqrt_C_a * cos(theta); + float x_3a = _2_sqrt_C_a * cos(theta + (2.0 / 3.0) * M_PI); + + float xl; + if ((x_1a + x_3a) > 2.0 * B) { + xl = x_1a; + } + else { + xl = x_3a; + } + + xlc = vec2(xl - B, A); + } + + /* Algorithm D */ + { + float A_d = D; + float C_d = delta.z; + float D_d = -D * delta.y + 2.0 * C * delta.z; + + /* Take the cubic root of a normalized complex number */ + float theta = atan(D * sqrt_discr, -D_d) / 3.0; + + float _2_sqrt_C_d = 2.0 * sqrt(-C_d); + float x_1d = _2_sqrt_C_d * cos(theta); + float x_3d = _2_sqrt_C_d * cos(theta + (2.0 / 3.0) * M_PI); + + float xs; + if (x_1d + x_3d < 2.0 * C) { + xs = x_1d; + } + else { + xs = x_3d; + } + + xsc = vec2(-D, xs + C); + } + + float E = xlc.y * xsc.y; + float F = -xlc.x * xsc.y - xlc.y * xsc.x; + float G = xlc.x * xsc.x; + + vec2 xmc = vec2(C * F - B * G, -B * F + C * E); + + vec3 root = vec3(xsc.x / xsc.y, xmc.x / xmc.y, xlc.x / xlc.y); + + if (root.x < root.y && root.x < root.z) { + root.xyz = root.yxz; + } + else if (root.z < root.x && root.z < root.y) { + root.xyz = root.xzy; + } + + return root; +} + +/* from Real-Time Area Lighting: a Journey from Research to Production + * Stephen Hill and Eric Heitz */ +vec3 ltc_edge_integral_vec(vec3 v1, vec3 v2) +{ + float x = dot(v1, v2); + float y = abs(x); + + float a = 0.8543985 + (0.4965155 + 0.0145206 * y) * y; + float b = 3.4175940 + (4.1616724 + y) * y; + float v = a / b; + + float theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt(max(1.0 - x * x, 1e-7)) - v; + + return cross(v1, v2) * theta_sintheta; +} + +mat3 ltc_matrix(vec4 lut) +{ + /* Load inverse matrix. */ + return mat3(vec3(lut.x, 0, lut.y), vec3(0, 1, 0), vec3(lut.z, 0, lut.w)); +} + +void ltc_transform_quad(vec3 N, vec3 V, mat3 Minv, inout vec3 corners[4]) +{ + /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */ + V = normalize(V + 1e-8); + + /* Construct orthonormal basis around N. */ + vec3 T1, T2; + T1 = normalize(V - N * dot(N, V)); + T2 = cross(N, T1); + + /* Rotate area light in (T1, T2, R) basis. */ + Minv = Minv * transpose(mat3(T1, T2, N)); + + /* Apply LTC inverse matrix. */ + corners[0] = normalize(Minv * corners[0]); + corners[1] = normalize(Minv * corners[1]); + corners[2] = normalize(Minv * corners[2]); + corners[3] = normalize(Minv * corners[3]); +} + +/* If corners have already pass through ltc_transform_quad(), + * then N **MUST** be vec3(0.0, 0.0, 1.0), corresponding to the Up axis of the shading basis. */ +float ltc_evaluate_quad(sampler2DArray utility_tx, vec3 corners[4], vec3 N) +{ + /* Approximation using a sphere of the same solid angle than the quad. + * Finding the clipped sphere diffuse integral is easier than clipping the quad. */ + vec3 avg_dir; + avg_dir = ltc_edge_integral_vec(corners[0], corners[1]); + avg_dir += ltc_edge_integral_vec(corners[1], corners[2]); + avg_dir += ltc_edge_integral_vec(corners[2], corners[3]); + avg_dir += ltc_edge_integral_vec(corners[3], corners[0]); + + float form_factor = length(avg_dir); + float avg_dir_z = dot(N, avg_dir / form_factor); + return form_factor * ltc_diffuse_sphere_integral(utility_tx, avg_dir_z, form_factor); +} + +/* If disk does not need to be transformed and is already front facing. */ +float ltc_evaluate_disk_simple(sampler2DArray utility_tx, float disk_radius, float NL) +{ + float r_sqr = disk_radius * disk_radius; + float one_r_sqr = 1.0 + r_sqr; + float form_factor = r_sqr * inversesqrt(one_r_sqr * one_r_sqr); + return form_factor * ltc_diffuse_sphere_integral(utility_tx, NL, form_factor); +} + +/* disk_points are WS vectors from the shading point to the disk "bounding domain" */ +float ltc_evaluate_disk(sampler2DArray utility_tx, vec3 N, vec3 V, mat3 Minv, vec3 disk_points[3]) +{ + /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */ + V = normalize(V + 1e-8); + + /* construct orthonormal basis around N */ + vec3 T1, T2; + T1 = normalize(V - N * dot(V, N)); + T2 = cross(N, T1); + + /* rotate area light in (T1, T2, R) basis */ + mat3 R = transpose(mat3(T1, T2, N)); + + /* Intermediate step: init ellipse. */ + vec3 L_[3]; + L_[0] = mul(R, disk_points[0]); + L_[1] = mul(R, disk_points[1]); + L_[2] = mul(R, disk_points[2]); + + vec3 C = 0.5 * (L_[0] + L_[2]); + vec3 V1 = 0.5 * (L_[1] - L_[2]); + vec3 V2 = 0.5 * (L_[1] - L_[0]); + + /* Transform ellipse by Minv. */ + C = Minv * C; + V1 = Minv * V1; + V2 = Minv * V2; + + /* Compute eigenvectors of new ellipse. */ + + float d11 = dot(V1, V1); + float d22 = dot(V2, V2); + float d12 = dot(V1, V2); + float a, b; /* Eigenvalues */ + const float threshold = 0.0007; /* Can be adjusted. Fix artifacts. */ + if (abs(d12) / sqrt(d11 * d22) > threshold) { + float tr = d11 + d22; + float det = -d12 * d12 + d11 * d22; + + /* use sqrt matrix to solve for eigenvalues */ + det = sqrt(det); + float u = 0.5 * sqrt(tr - 2.0 * det); + float v = 0.5 * sqrt(tr + 2.0 * det); + float e_max = (u + v); + float e_min = (u - v); + e_max *= e_max; + e_min *= e_min; + + vec3 V1_, V2_; + if (d11 > d22) { + V1_ = d12 * V1 + (e_max - d11) * V2; + V2_ = d12 * V1 + (e_min - d11) * V2; + } + else { + V1_ = d12 * V2 + (e_max - d22) * V1; + V2_ = d12 * V2 + (e_min - d22) * V1; + } + + a = 1.0 / e_max; + b = 1.0 / e_min; + V1 = normalize(V1_); + V2 = normalize(V2_); + } + else { + a = 1.0 / d11; + b = 1.0 / d22; + V1 *= sqrt(a); + V2 *= sqrt(b); + } + + /* Now find front facing ellipse with same solid angle. */ + + vec3 V3 = normalize(cross(V1, V2)); + if (dot(C, V3) < 0.0) { + V3 *= -1.0; + } + + float L = dot(V3, C); + float inv_L = 1.0 / L; + float x0 = dot(V1, C) * inv_L; + float y0 = dot(V2, C) * inv_L; + + float L_sqr = L * L; + a *= L_sqr; + b *= L_sqr; + + float t = 1.0 + x0 * x0; + float c0 = a * b; + float c1 = c0 * (t + y0 * y0) - a - b; + float c2 = (1.0 - a * t) - b * (1.0 + y0 * y0); + float c3 = 1.0; + + vec3 roots = ltc_solve_cubic(vec4(c0, c1, c2, c3)); + float e1 = roots.x; + float e2 = roots.y; + float e3 = roots.z; + + vec3 avg_dir = vec3(a * x0 / (a - e2), b * y0 / (b - e2), 1.0); + + mat3 rotate = mat3(V1, V2, V3); + + avg_dir = rotate * avg_dir; + avg_dir = normalize(avg_dir); + + /* L1, L2 are the extends of the front facing ellipse. */ + float L1 = sqrt(-e2 / e3); + float L2 = sqrt(-e2 / e1); + + /* Find the sphere and compute lighting. */ + float form_factor = max(0.0, L1 * L2 * inversesqrt((1.0 + L1 * L1) * (1.0 + L2 * L2))); + return form_factor * ltc_diffuse_sphere_integral(utility_tx, avg_dir.z, form_factor); +} 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 index 99186ab6f67..c3606dca4f7 100644 --- 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 @@ -2,7 +2,6 @@ /** * 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) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index c488216eeac..13ad387289d 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -39,6 +39,8 @@ bool closure_select(float weight, inout float total_weight, inout float r) destination = candidate; \ } +float g_closure_rand; + void closure_weights_reset() { g_diffuse_data.weight = 0.0; @@ -58,18 +60,8 @@ void closure_weights_reset() g_refraction_data.roughness = 0.0; g_refraction_data.ior = 0.0; - /* TEMP */ -#define P(x) ((x + 0.5) / 16.0) - const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)), - vec4(P(12.0), P(4.0), P(14.0), P(6.0)), - vec4(P(3.0), P(11.0), P(1.0), P(9.0)), - vec4(P(15.0), P(7.0), P(13.0), P(5.0))); -#undef P #if defined(GPU_FRAGMENT_SHADER) - ivec2 pix = ivec2(gl_FragCoord.xy) % ivec2(4); - g_diffuse_rand = dither_mat4x4[pix.x][pix.y]; - g_reflection_rand = dither_mat4x4[pix.x][pix.y]; - g_refraction_rand = dither_mat4x4[pix.x][pix.y]; + g_diffuse_rand = g_reflection_rand = g_refraction_rand = g_closure_rand; #else g_diffuse_rand = 0.0; g_reflection_rand = 0.0; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl index 48ced4e5374..3f2349b30a1 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl @@ -5,35 +5,36 @@ * This is used by alpha blended materials and materials using Shader to RGB nodes. **/ -#pragma BLENDER_REQUIRE(common_view_lib.glsl) -#pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(common_hair_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) -float spec_light(ClosureReflection ref) -{ - float gloss = saturate(1.0 - ref.roughness); - float shininess = exp2(10.0 * gloss + 1.0); - vec3 N = ref.N; - vec3 L = vec3(0.0, 0.0, 1.0); - vec3 H = normalize(L + cameraVec(g_data.P)); - float spec_angle = saturate(dot(N, H)); - float normalization_factor = shininess * 0.125 + 1.0; - float spec_light = pow(spec_angle, shininess) * saturate(dot(N, L)) * normalization_factor; - return spec_light; -} - vec4 closure_to_rgba(Closure cl) { + vec3 diffuse_light = vec3(0.0); + vec3 reflection_light = vec3(0.0); + vec3 refraction_light = vec3(0.0); + + float vP_z = dot(cameraForward, g_data.P) - dot(cameraForward, cameraPos); + + light_eval(g_diffuse_data, + g_reflection_data, + g_data.P, + cameraVec(g_data.P), + vP_z, + 0.01 /* TODO(fclem) thickness. */, + diffuse_light, + reflection_light); + vec4 out_color; out_color.rgb = g_emission; - out_color.rgb += g_diffuse_data.color * g_diffuse_data.weight * - saturate(g_diffuse_data.N.z * 0.5 + 0.5); - out_color.rgb += g_reflection_data.color * g_reflection_data.weight * - spec_light(g_reflection_data); - out_color.rgb += g_refraction_data.color * g_refraction_data.weight * - saturate(g_refraction_data.N.z * 0.5 + 0.5); + out_color.rgb += g_diffuse_data.color * g_diffuse_data.weight * diffuse_light; + out_color.rgb += g_reflection_data.color * g_reflection_data.weight * reflection_light; + out_color.rgb += g_refraction_data.color * g_refraction_data.weight * refraction_light; out_color.a = saturate(1.0 - avg(g_transmittance)); @@ -47,15 +48,29 @@ void main() { init_globals(); + float noise = utility_tx_fetch(utility_tx, gl_FragCoord.xy, UTIL_BLUE_NOISE_LAYER).r; + g_closure_rand = fract(noise + sampling_rng_1D_get(SAMPLING_CLOSURE)); + fragment_displacement(); nodetree_surface(); g_holdout = saturate(g_holdout); - vec3 diffuse_light = vec3(saturate(g_diffuse_data.N.z * 0.5 + 0.5)); - vec3 reflection_light = vec3(spec_light(g_reflection_data)); - vec3 refraction_light = vec3(saturate(g_refraction_data.N.z * 0.5 + 0.5)); + vec3 diffuse_light = vec3(0.0); + vec3 reflection_light = vec3(0.0); + vec3 refraction_light = vec3(0.0); + + float vP_z = dot(cameraForward, g_data.P) - dot(cameraForward, cameraPos); + + light_eval(g_diffuse_data, + g_reflection_data, + g_data.P, + cameraVec(g_data.P), + vP_z, + 0.01 /* TODO(fclem) thickness. */, + diffuse_light, + reflection_light); g_diffuse_data.color *= g_diffuse_data.weight; g_reflection_data.color *= g_reflection_data.weight; @@ -84,9 +99,11 @@ void main() ivec2 out_texel = ivec2(gl_FragCoord.xy); imageStore(rp_normal_img, out_texel, vec4(out_normal, 1.0)); - imageStore(rp_diffuse_light_img, out_texel, vec4(diffuse_light, 1.0)); + imageStore( + rp_light_img, ivec3(out_texel, RENDER_PASS_LAYER_DIFFUSE_LIGHT), vec4(diffuse_light, 1.0)); + imageStore( + rp_light_img, ivec3(out_texel, RENDER_PASS_LAYER_SPECULAR_LIGHT), vec4(specular_light, 1.0)); imageStore(rp_diffuse_color_img, out_texel, vec4(g_diffuse_data.color, 1.0)); - imageStore(rp_specular_light_img, out_texel, vec4(specular_light, 1.0)); imageStore(rp_specular_color_img, out_texel, vec4(specular_color, 1.0)); imageStore(rp_emission_img, out_texel, vec4(g_emission, 1.0)); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl index ed75282a550..1ef1c1f84b8 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl @@ -26,9 +26,11 @@ void main() ivec2 out_texel = ivec2(gl_FragCoord.xy); imageStore(rp_normal_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0)); - imageStore(rp_diffuse_light_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0)); + imageStore( + rp_light_img, ivec3(out_texel, RENDER_PASS_LAYER_DIFFUSE_LIGHT), vec4(0.0, 0.0, 0.0, 1.0)); + imageStore( + rp_light_img, ivec3(out_texel, RENDER_PASS_LAYER_SPECULAR_LIGHT), vec4(0.0, 0.0, 0.0, 1.0)); imageStore(rp_diffuse_color_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0)); - imageStore(rp_specular_light_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0)); imageStore(rp_specular_color_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0)); imageStore(rp_emission_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0)); diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh index a5baaca51f9..c94171db6a9 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh @@ -9,19 +9,18 @@ GPU_SHADER_CREATE_INFO(eevee_film) .sampler(1, ImageType::FLOAT_2D, "combined_tx") .sampler(2, ImageType::FLOAT_2D, "normal_tx") .sampler(3, ImageType::FLOAT_2D, "vector_tx") - .sampler(4, ImageType::FLOAT_2D, "diffuse_light_tx") + .sampler(4, ImageType::FLOAT_2D_ARRAY, "light_tx") .sampler(5, ImageType::FLOAT_2D, "diffuse_color_tx") - .sampler(6, ImageType::FLOAT_2D, "specular_light_tx") - .sampler(7, ImageType::FLOAT_2D, "specular_color_tx") - .sampler(8, ImageType::FLOAT_2D, "volume_light_tx") - .sampler(9, ImageType::FLOAT_2D, "emission_tx") - .sampler(10, ImageType::FLOAT_2D, "environment_tx") - .sampler(11, ImageType::FLOAT_2D, "shadow_tx") - .sampler(12, ImageType::FLOAT_2D, "ambient_occlusion_tx") - .sampler(13, ImageType::FLOAT_2D_ARRAY, "aov_color_tx") - .sampler(14, ImageType::FLOAT_2D_ARRAY, "aov_value_tx") + .sampler(6, ImageType::FLOAT_2D, "specular_color_tx") + .sampler(7, ImageType::FLOAT_2D, "volume_light_tx") + .sampler(8, ImageType::FLOAT_2D, "emission_tx") + .sampler(9, ImageType::FLOAT_2D, "environment_tx") + .sampler(10, ImageType::FLOAT_2D, "shadow_tx") + .sampler(11, ImageType::FLOAT_2D, "ambient_occlusion_tx") + .sampler(12, ImageType::FLOAT_2D_ARRAY, "aov_color_tx") + .sampler(13, ImageType::FLOAT_2D_ARRAY, "aov_value_tx") /* Color History for TAA needs to be sampler to leverage bilinear sampling. */ - .sampler(15, ImageType::FLOAT_2D, "in_combined_tx") + .sampler(14, ImageType::FLOAT_2D, "in_combined_tx") // .sampler(15, ImageType::FLOAT_2D, "cryptomatte_tx") /* TODO */ .image(0, GPU_R32F, Qualifier::READ, ImageType::FLOAT_2D_ARRAY, "in_weight_img") .image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_hiz_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_hiz_info.hh new file mode 100644 index 00000000000..5e32631a8f8 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_hiz_info.hh @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "eevee_defines.hh" +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(eevee_hiz_data) + .sampler(15, ImageType::FLOAT_2D, "hiz_tx") + .uniform_buf(5, "HiZData", "hiz_buf"); + +GPU_SHADER_CREATE_INFO(eevee_hiz_update) + .do_static_compilation(true) + .local_group_size(FILM_GROUP_SIZE, FILM_GROUP_SIZE) + .storage_buf(0, Qualifier::READ_WRITE, "uint", "finished_tile_counter") + .sampler(0, ImageType::DEPTH_2D, "depth_tx") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_mip_0") + .image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_mip_1") + .image(2, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_mip_2") + .image(3, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_mip_3") + .image(4, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_mip_4") + .image(5, GPU_R32F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "out_mip_5") + .image(6, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_mip_6") + .image(7, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_mip_7") + .push_constant(Type::BOOL, "update_mip_0") + .compute_source("eevee_hiz_update_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_hiz_debug) + .do_static_compilation(true) + .fragment_out(0, Type::VEC4, "out_debug_color_add", DualBlend::SRC_0) + .fragment_out(0, Type::VEC4, "out_debug_color_mul", DualBlend::SRC_1) + .fragment_source("eevee_hiz_debug_frag.glsl") + .additional_info("eevee_shared", "eevee_hiz_data", "draw_fullscreen"); diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_light_culling_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_light_culling_info.hh new file mode 100644 index 00000000000..c54f05719d3 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_light_culling_info.hh @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "eevee_defines.hh" +#include "gpu_shader_create_info.hh" + +/* -------------------------------------------------------------------- */ +/** \name Shared + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_light_data) + .storage_buf(0, Qualifier::READ, "LightCullingData", "light_cull_buf") + .storage_buf(1, Qualifier::READ, "LightData", "light_buf[]") + .storage_buf(2, Qualifier::READ, "uint", "light_zbin_buf[]") + .storage_buf(3, Qualifier::READ, "uint", "light_tile_buf[]"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Culling + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_light_culling_select) + .do_static_compilation(true) + .additional_info("eevee_shared", "draw_view") + .local_group_size(CULLING_SELECT_GROUP_SIZE) + .storage_buf(0, Qualifier::READ_WRITE, "LightCullingData", "light_cull_buf") + .storage_buf(1, Qualifier::READ, "LightData", "in_light_buf[]") + .storage_buf(2, Qualifier::WRITE, "LightData", "out_light_buf[]") + .storage_buf(3, Qualifier::WRITE, "float", "out_zdist_buf[]") + .storage_buf(4, Qualifier::WRITE, "uint", "out_key_buf[]") + .compute_source("eevee_light_culling_select_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_light_culling_sort) + .do_static_compilation(true) + .additional_info("eevee_shared", "draw_view") + .storage_buf(0, Qualifier::READ, "LightCullingData", "light_cull_buf") + .storage_buf(1, Qualifier::READ, "LightData", "in_light_buf[]") + .storage_buf(2, Qualifier::WRITE, "LightData", "out_light_buf[]") + .storage_buf(3, Qualifier::READ, "float", "in_zdist_buf[]") + .storage_buf(4, Qualifier::READ, "uint", "in_key_buf[]") + .local_group_size(CULLING_SORT_GROUP_SIZE) + .compute_source("eevee_light_culling_sort_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_light_culling_zbin) + .do_static_compilation(true) + .additional_info("eevee_shared", "draw_view") + .local_group_size(CULLING_ZBIN_GROUP_SIZE) + .storage_buf(0, Qualifier::READ, "LightCullingData", "light_cull_buf") + .storage_buf(1, Qualifier::READ, "LightData", "light_buf[]") + .storage_buf(2, Qualifier::WRITE, "uint", "out_zbin_buf[]") + .compute_source("eevee_light_culling_zbin_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_light_culling_tile) + .do_static_compilation(true) + .additional_info("eevee_shared", "draw_view") + .local_group_size(CULLING_TILE_GROUP_SIZE) + .storage_buf(0, Qualifier::READ, "LightCullingData", "light_cull_buf") + .storage_buf(1, Qualifier::READ, "LightData", "light_buf[]") + .storage_buf(2, Qualifier::WRITE, "uint", "out_light_tile_buf[]") + .compute_source("eevee_light_culling_tile_comp.glsl"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Debug + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_light_culling_debug) + .do_static_compilation(true) + .fragment_out(0, Type::VEC4, "out_debug_color_add", DualBlend::SRC_0) + .fragment_out(0, Type::VEC4, "out_debug_color_mul", DualBlend::SRC_1) + .fragment_source("eevee_light_culling_debug_frag.glsl") + .additional_info( + "eevee_shared", "draw_view", "draw_fullscreen", "eevee_light_data", "eevee_hiz_data"); + +/** \} */ 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 db3cfc4a7a2..dad1f28ef8e 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 @@ -16,6 +16,8 @@ GPU_SHADER_CREATE_INFO(eevee_sampling_data) .additional_info("eevee_shared") .storage_buf(14, Qualifier::READ, "SamplingData", "sampling_buf"); +GPU_SHADER_CREATE_INFO(eevee_utility_texture).sampler(8, ImageType::FLOAT_2D_ARRAY, "utility_tx"); + /** \} */ /* -------------------------------------------------------------------- */ @@ -76,8 +78,8 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp") GPU_SHADER_CREATE_INFO(eevee_aov_out) .define("MAT_AOV_SUPPORT") - .image_array_out(6, Qualifier::WRITE, GPU_RGBA16F, "aov_color_img") - .image_array_out(7, Qualifier::WRITE, GPU_R16F, "aov_value_img") + .image_array_out(5, Qualifier::WRITE, GPU_RGBA16F, "aov_color_img") + .image_array_out(6, Qualifier::WRITE, GPU_R16F, "aov_value_img") .storage_buf(7, Qualifier::READ, "AOVsInfoData", "aov_buf"); GPU_SHADER_CREATE_INFO(eevee_surf_deferred) @@ -111,19 +113,18 @@ GPU_SHADER_CREATE_INFO(eevee_surf_forward) .fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1) .fragment_source("eevee_surf_forward_frag.glsl") .image_out(0, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_normal_img") - .image_out(1, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_light_img") + .image_array_out(1, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_light_img") .image_out(2, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_color_img") - .image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_light_img") - .image_out(4, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img") - .image_out(5, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img") - .additional_info("eevee_aov_out" - // "eevee_sampling_data", + .image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img") + .image_out(4, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img") + .additional_info("eevee_aov_out", + "eevee_light_data", + "eevee_utility_texture", + "eevee_sampling_data" // "eevee_lightprobe_data", /* Optionally added depending on the material. */ // "eevee_raytrace_data", // "eevee_transmittance_data", - // "eevee_utility_texture", - // "eevee_light_data", // "eevee_shadow_data" ); @@ -136,11 +137,10 @@ GPU_SHADER_CREATE_INFO(eevee_surf_depth) GPU_SHADER_CREATE_INFO(eevee_surf_world) .vertex_out(eevee_surf_iface) .image_out(0, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_normal_img") - .image_out(1, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_light_img") + .image_array_out(1, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_light_img") .image_out(2, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_color_img") - .image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_light_img") - .image_out(4, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img") - .image_out(5, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img") + .image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img") + .image_out(4, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img") .push_constant(Type::FLOAT, "world_opacity_fade") .fragment_out(0, Type::VEC4, "out_background") .fragment_source("eevee_surf_world_frag.glsl") diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 332c7f67c64..2f9d20b3902 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -19,6 +19,8 @@ extern "C" { #endif +#define GP_LIGHT + #include "gpencil_defines.h" #include "gpencil_shader_shared.h" diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h index 50ff7e7efc7..4c621e955b9 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h +++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h @@ -7,7 +7,9 @@ typedef struct gpMaterial gpMaterial; typedef struct gpLight gpLight; typedef enum gpMaterialFlag gpMaterialFlag; +# ifdef GP_LIGHT typedef enum gpLightType gpLightType; +# endif # endif #endif @@ -75,8 +77,9 @@ struct gpMaterial { }; BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16) +#ifdef GP_LIGHT struct gpLight { -#ifndef GPU_SHADER +# ifndef GPU_SHADER float3 color; gpLightType type; float3 right; @@ -87,7 +90,7 @@ struct gpLight { float _pad0; float3 position; float _pad1; -#else +# else /* Some drivers are completely messing the alignment or the fetches here. * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */ /* NOTE(@fclem): This was the case on MacOS OpenGL implementation. @@ -97,17 +100,18 @@ struct gpLight { float4 packed2; float4 packed3; float4 packed4; -# define _color packed0.xyz -# define _type packed0.w -# define _right packed1.xyz -# define _spot_size packed1.w -# define _up packed2.xyz -# define _spot_blend packed2.w -# define _forward packed3.xyz -# define _position packed4.xyz -#endif +# define _color packed0.xyz +# define _type packed0.w +# define _right packed1.xyz +# define _spot_size packed1.w +# define _up packed2.xyz +# define _spot_blend packed2.w +# define _forward packed3.xyz +# define _position packed4.xyz +# endif }; BLI_STATIC_ASSERT_ALIGN(gpLight, 16) +#endif #ifndef GPU_SHADER # undef gpMaterialFlag diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh index 3b4de704c00..1db98d13c4a 100644 --- a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh +++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh @@ -20,8 +20,8 @@ GPU_SHADER_INTERFACE_INFO(gpencil_geometry_iface, "gp_interp") GPU_SHADER_CREATE_INFO(gpencil_geometry) .do_static_compilation(true) + .define("GP_LIGHT") .typedef_source("gpencil_defines.h") - .typedef_source("gpencil_shader_shared.h") .sampler(0, ImageType::FLOAT_2D, "gpFillTexture") .sampler(1, ImageType::FLOAT_2D, "gpStrokeTexture") .sampler(2, ImageType::DEPTH_2D, "gpSceneDepthTexture") diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 5edd68bffff..6e2da95e405 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -320,7 +320,6 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) OB_MESH, OB_CURVES_LEGACY, OB_SURF, - OB_MBALL, OB_FONT, OB_GPENCIL, OB_CURVES, diff --git a/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl index 612ce8c6300..ca5a6aff2ca 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl @@ -130,7 +130,7 @@ void main() gl_Position = p1; /* compute position from 3 vertex because the change in direction - * can happen very quicky and lead to very thin edges. */ + * can happen very quickly and lead to very thin edges. */ vec2 ss0 = proj(p0); vec2 ss1 = proj(p1); vec2 ss2 = proj(p2); diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 9eb35c25bf4..a0459a967f3 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -409,7 +409,7 @@ void workbench_cache_populate(void *ved, Object *ob) return; } - if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL, OB_POINTCLOUD)) { + if (ELEM(ob->type, OB_MESH, OB_POINTCLOUD)) { bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false; eV3DShadingColorType color_type = workbench_color_type_get( wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow); diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index 5405afd2a90..8ed6594c31e 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -50,7 +50,6 @@ * * `draw::Framebuffer` * Simple wrapper to #GPUFramebuffer that can be moved. - * */ #include "DRW_render.h" @@ -399,10 +398,10 @@ class Texture : NonCopyable { int extent, float *data = nullptr, bool cubemap = false, - int mips = 1) + int mip_len = 1) : name_(name) { - tx_ = create(extent, 0, 0, mips, format, data, false, cubemap); + tx_ = create(extent, 0, 0, mip_len, format, data, false, cubemap); } Texture(const char *name, @@ -411,17 +410,20 @@ class Texture : NonCopyable { int layers, float *data = nullptr, bool cubemap = false, - int mips = 1) + int mip_len = 1) : name_(name) { - tx_ = create(extent, layers, 0, mips, format, data, true, cubemap); + tx_ = create(extent, layers, 0, mip_len, format, data, true, cubemap); } - Texture( - const char *name, eGPUTextureFormat format, int2 extent, float *data = nullptr, int mips = 1) + Texture(const char *name, + eGPUTextureFormat format, + int2 extent, + float *data = nullptr, + int mip_len = 1) : name_(name) { - tx_ = create(UNPACK2(extent), 0, mips, format, data, false, false); + tx_ = create(UNPACK2(extent), 0, mip_len, format, data, false, false); } Texture(const char *name, @@ -429,17 +431,20 @@ class Texture : NonCopyable { int2 extent, int layers, float *data = nullptr, - int mips = 1) + int mip_len = 1) : name_(name) { - tx_ = create(UNPACK2(extent), layers, mips, format, data, true, false); + tx_ = create(UNPACK2(extent), layers, mip_len, format, data, true, false); } - Texture( - const char *name, eGPUTextureFormat format, int3 extent, float *data = nullptr, int mips = 1) + Texture(const char *name, + eGPUTextureFormat format, + int3 extent, + float *data = nullptr, + int mip_len = 1) : name_(name) { - tx_ = create(UNPACK3(extent), mips, format, data, false, false); + tx_ = create(UNPACK3(extent), mip_len, format, data, false, false); } ~Texture() @@ -474,9 +479,9 @@ class Texture : NonCopyable { * Ensure the texture has the correct properties. Recreating it if needed. * Return true if a texture has been created. */ - bool ensure_1d(eGPUTextureFormat format, int extent, float *data = nullptr, int mips = 1) + bool ensure_1d(eGPUTextureFormat format, int extent, float *data = nullptr, int mip_len = 1) { - return ensure_impl(extent, 0, 0, mips, format, data, false, false); + return ensure_impl(extent, 0, 0, mip_len, format, data, false, false); } /** @@ -484,18 +489,18 @@ class Texture : NonCopyable { * Return true if a texture has been created. */ bool ensure_1d_array( - eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mips = 1) + eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mip_len = 1) { - return ensure_impl(extent, layers, 0, mips, format, data, true, false); + return ensure_impl(extent, layers, 0, mip_len, format, data, true, false); } /** * Ensure the texture has the correct properties. Recreating it if needed. * Return true if a texture has been created. */ - bool ensure_2d(eGPUTextureFormat format, int2 extent, float *data = nullptr, int mips = 1) + bool ensure_2d(eGPUTextureFormat format, int2 extent, float *data = nullptr, int mip_len = 1) { - return ensure_impl(UNPACK2(extent), 0, mips, format, data, false, false); + return ensure_impl(UNPACK2(extent), 0, mip_len, format, data, false, false); } /** @@ -503,27 +508,27 @@ class Texture : NonCopyable { * Return true if a texture has been created. */ bool ensure_2d_array( - eGPUTextureFormat format, int2 extent, int layers, float *data = nullptr, int mips = 1) + eGPUTextureFormat format, int2 extent, int layers, float *data = nullptr, int mip_len = 1) { - return ensure_impl(UNPACK2(extent), layers, mips, format, data, true, false); + return ensure_impl(UNPACK2(extent), layers, mip_len, format, data, true, false); } /** * Ensure the texture has the correct properties. Recreating it if needed. * Return true if a texture has been created. */ - bool ensure_3d(eGPUTextureFormat format, int3 extent, float *data = nullptr, int mips = 1) + bool ensure_3d(eGPUTextureFormat format, int3 extent, float *data = nullptr, int mip_len = 1) { - return ensure_impl(UNPACK3(extent), mips, format, data, false, false); + return ensure_impl(UNPACK3(extent), mip_len, format, data, false, false); } /** * Ensure the texture has the correct properties. Recreating it if needed. * Return true if a texture has been created. */ - bool ensure_cube(eGPUTextureFormat format, int extent, float *data = nullptr, int mips = 1) + bool ensure_cube(eGPUTextureFormat format, int extent, float *data = nullptr, int mip_len = 1) { - return ensure_impl(extent, extent, 0, mips, format, data, false, true); + return ensure_impl(extent, extent, 0, mip_len, format, data, false, true); } /** @@ -531,9 +536,9 @@ class Texture : NonCopyable { * Return true if a texture has been created. */ bool ensure_cube_array( - eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mips = 1) + eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mip_len = 1) { - return ensure_impl(extent, extent, layers, mips, format, data, false, true); + return ensure_impl(extent, extent, layers, mip_len, format, data, false, true); } /** @@ -562,6 +567,11 @@ class Texture : NonCopyable { return mip_views_[miplvl]; } + int mip_count() const + { + return GPU_texture_mip_count(tx_); + } + /** * Ensure the availability of mipmap views. * Layer views covers all layers of array textures. @@ -721,7 +731,7 @@ class Texture : NonCopyable { bool ensure_impl(int w, int h = 0, int d = 0, - int mips = 1, + int mip_len = 1, eGPUTextureFormat format = GPU_RGBA8, float *data = nullptr, bool layered = false, @@ -738,7 +748,7 @@ class Texture : NonCopyable { } } if (tx_ == nullptr) { - tx_ = create(w, h, d, mips, format, data, layered, cubemap); + tx_ = create(w, h, d, mip_len, format, data, layered, cubemap); return true; } return false; @@ -747,37 +757,37 @@ class Texture : NonCopyable { GPUTexture *create(int w, int h, int d, - int mips, + int mip_len, eGPUTextureFormat format, float *data, bool layered, bool cubemap) { if (h == 0) { - return GPU_texture_create_1d(name_, w, mips, format, data); + return GPU_texture_create_1d(name_, w, mip_len, format, data); } else if (cubemap) { if (layered) { - return GPU_texture_create_cube_array(name_, w, d, mips, format, data); + return GPU_texture_create_cube_array(name_, w, d, mip_len, format, data); } else { - return GPU_texture_create_cube(name_, w, mips, format, data); + return GPU_texture_create_cube(name_, w, mip_len, format, data); } } else if (d == 0) { if (layered) { - return GPU_texture_create_1d_array(name_, w, h, mips, format, data); + return GPU_texture_create_1d_array(name_, w, h, mip_len, format, data); } else { - return GPU_texture_create_2d(name_, w, h, mips, format, data); + return GPU_texture_create_2d(name_, w, h, mip_len, format, data); } } else { if (layered) { - return GPU_texture_create_2d_array(name_, w, h, d, mips, format, data); + return GPU_texture_create_2d_array(name_, w, h, d, mip_len, format, data); } else { - return GPU_texture_create_3d(name_, w, h, d, mips, format, GPU_DATA_FLOAT, data); + return GPU_texture_create_3d(name_, w, h, d, mip_len, format, GPU_DATA_FLOAT, data); } } } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index a3097251d35..8745d1100e4 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -409,7 +409,7 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, void *user_data); /** - * If ob is NULL, unit modelmatrix is assumed and culling is bypassed. + * If ob is NULL, unit model-matrix is assumed and culling is bypassed. */ #define DRW_shgroup_call(shgroup, geom, ob) \ DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, NULL) @@ -420,8 +420,8 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, #define DRW_shgroup_call_obmat(shgroup, geom, obmat) \ DRW_shgroup_call_ex(shgroup, NULL, obmat, geom, false, NULL) -/* TODO(fclem): remove this when we have DRWView */ -/* user_data is used by DRWCallVisibilityFn defined in DRWView. */ +/* TODO(fclem): remove this when we have #DRWView */ +/* user_data is used by #DRWCallVisibilityFn defined in #DRWView. */ #define DRW_shgroup_call_with_callback(shgroup, geom, ob, user_data) \ DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, user_data) diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 4c0f025e934..4ff5745fc86 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -780,6 +780,39 @@ GPUBatch *DRW_cache_normal_arrow_get(void) return SHC.drw_normal_arrow; } +void DRW_vertbuf_create_wiredata(GPUVertBuf *vbo, const int vert_len) +{ + static GPUVertFormat format = {0}; + static struct { + uint wd; + } attr_id; + if (format.attr_len == 0) { + /* initialize vertex format */ + if (!GPU_crappy_amd_driver()) { + /* Some AMD drivers strangely crash with a vbo with this format. */ + attr_id.wd = GPU_vertformat_attr_add( + &format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + else { + attr_id.wd = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, vert_len); + + if (GPU_vertbuf_get_format(vbo)->stride == 1) { + memset(GPU_vertbuf_get_data(vbo), 0xFF, (size_t)vert_len); + } + else { + GPUVertBufRaw wd_step; + GPU_vertbuf_attr_get_raw_data(vbo, attr_id.wd, &wd_step); + for (int i = 0; i < vert_len; i++) { + *((float *)GPU_vertbuf_raw_step(&wd_step)) = 1.0f; + } + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -818,7 +851,6 @@ GPUBatch *DRW_cache_object_all_edges_get(Object *ob) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_all_edges_get(ob); - /* TODO: should match #DRW_cache_object_surface_get. */ default: return NULL; @@ -830,20 +862,6 @@ GPUBatch *DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_edge_detection_get(ob, r_is_manifold); - case OB_CURVES_LEGACY: - return NULL; - case OB_SURF: - return NULL; - case OB_FONT: - return NULL; - case OB_MBALL: - return DRW_cache_mball_edge_detection_get(ob, r_is_manifold); - case OB_CURVES: - return NULL; - case OB_POINTCLOUD: - return NULL; - case OB_VOLUME: - return NULL; default: return NULL; } @@ -854,23 +872,12 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_face_wireframe_get(ob); - case OB_CURVES_LEGACY: - return NULL; - case OB_SURF: - return NULL; - case OB_FONT: - return NULL; - case OB_MBALL: - return DRW_cache_mball_face_wireframe_get(ob); - case OB_CURVES: - return NULL; case OB_POINTCLOUD: return DRW_pointcloud_batch_cache_get_dots(ob); case OB_VOLUME: return DRW_cache_volume_face_wireframe_get(ob); - case OB_GPENCIL: { + case OB_GPENCIL: return DRW_cache_gpencil_face_wireframe_get(ob); - } default: return NULL; } @@ -881,20 +888,6 @@ GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_loose_edges_get(ob); - case OB_CURVES_LEGACY: - return NULL; - case OB_SURF: - return NULL; - case OB_FONT: - return NULL; - case OB_MBALL: - return NULL; - case OB_CURVES: - return NULL; - case OB_POINTCLOUD: - return NULL; - case OB_VOLUME: - return NULL; default: return NULL; } @@ -905,20 +898,8 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_surface_get(ob); - case OB_CURVES_LEGACY: - return NULL; - case OB_SURF: - return NULL; - case OB_FONT: - return NULL; - case OB_MBALL: - return DRW_cache_mball_surface_get(ob); - case OB_CURVES: - return NULL; case OB_POINTCLOUD: return DRW_cache_pointcloud_surface_get(ob); - case OB_VOLUME: - return NULL; default: return NULL; } @@ -932,18 +913,6 @@ GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) switch (type) { case OB_MESH: return DRW_mesh_batch_cache_pos_vertbuf_get((me != NULL) ? me : ob->data); - case OB_CURVES_LEGACY: - case OB_SURF: - case OB_FONT: - return NULL; - case OB_MBALL: - return DRW_mball_batch_cache_pos_vertbuf_get(ob); - case OB_CURVES: - return NULL; - case OB_POINTCLOUD: - return NULL; - case OB_VOLUME: - return NULL; default: return NULL; } @@ -968,8 +937,6 @@ int DRW_cache_object_material_count_get(struct Object *ob) case OB_SURF: case OB_FONT: return DRW_curve_material_count_get(ob->data); - case OB_MBALL: - return DRW_metaball_material_count_get(ob->data); case OB_CURVES: return DRW_curves_material_count_get(ob->data); case OB_POINTCLOUD: @@ -991,20 +958,8 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, switch (ob->type) { case OB_MESH: return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len); - case OB_CURVES_LEGACY: - return NULL; - case OB_SURF: - return NULL; - case OB_FONT: - return NULL; - case OB_MBALL: - return DRW_cache_mball_surface_shaded_get(ob, gpumat_array, gpumat_array_len); - case OB_CURVES: - return NULL; case OB_POINTCLOUD: return DRW_cache_pointcloud_surface_shaded_get(ob, gpumat_array, gpumat_array_len); - case OB_VOLUME: - return NULL; default: return NULL; } @@ -2972,39 +2927,6 @@ GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob) /** \} */ /* -------------------------------------------------------------------- */ -/** \name MetaBall - * \{ */ - -GPUBatch *DRW_cache_mball_surface_get(Object *ob) -{ - BLI_assert(ob->type == OB_MBALL); - return DRW_metaball_batch_cache_get_triangles_with_normals(ob); -} - -GPUBatch *DRW_cache_mball_edge_detection_get(Object *ob, bool *r_is_manifold) -{ - BLI_assert(ob->type == OB_MBALL); - return DRW_metaball_batch_cache_get_edge_detection(ob, r_is_manifold); -} - -GPUBatch *DRW_cache_mball_face_wireframe_get(Object *ob) -{ - BLI_assert(ob->type == OB_MBALL); - return DRW_metaball_batch_cache_get_wireframes_face(ob); -} - -GPUBatch **DRW_cache_mball_surface_shaded_get(Object *ob, - struct GPUMaterial **gpumat_array, - uint gpumat_array_len) -{ - BLI_assert(ob->type == OB_MBALL); - MetaBall *mb = ob->data; - return DRW_metaball_batch_cache_get_surface_shaded(ob, mb, gpumat_array, gpumat_array_len); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Font * \{ */ @@ -3322,9 +3244,6 @@ void drw_batch_cache_validate(Object *ob) case OB_SURF: DRW_curve_batch_cache_validate((Curve *)ob->data); break; - case OB_MBALL: - DRW_mball_batch_cache_validate((MetaBall *)ob->data); - break; case OB_LATTICE: DRW_lattice_batch_cache_validate((Lattice *)ob->data); break; diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index a107eb7c75c..4e8788ada08 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -213,15 +213,6 @@ struct GPUBatch *DRW_cache_particles_get_edit_tip_points(struct Object *object, struct PTCacheEdit *edit); struct GPUBatch *DRW_cache_particles_get_prim(int type); -/* Metaball */ - -struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob); -struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob, - struct GPUMaterial **gpumat_array, - uint gpumat_array_len); -struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob); -struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold); - /* Curves */ struct GPUBatch *DRW_cache_curves_surface_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index 0159c9fc86e..86b20a5cb7c 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -494,17 +494,6 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->bm_poly_centers = mr->edit_data->polyCos; } - /* A subdivision wrapper may be created in edit mode when X-ray is turned on to ensure that the - * topology seen by the user matches the one used for the selection routines. This wrapper - * seemingly takes precedence over the MDATA one, however the mesh we use for rendering is not - * the subdivided one, but the one where the MDATA wrapper would have been added. So consider - * the subdivision wrapper as well for the `has_mdata` case. */ - bool has_mdata = is_mode_active && ELEM(mr->me->runtime.wrapper_type, - ME_WRAPPER_TYPE_MDATA, - ME_WRAPPER_TYPE_SUBD); - bool use_mapped = is_mode_active && - (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original); - int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types); @@ -523,43 +512,51 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE); #endif - if (use_mapped) { - mr->v_origindex = static_cast<const int *>( - CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX)); - mr->e_origindex = static_cast<const int *>( - CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); - mr->p_origindex = static_cast<const int *>( - CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); - - use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); + /* Use bmesh directly when the object is in edit mode unchanged by any modifiers. + * For non-final UVs, always use original bmesh since the UV editor does not support + * using the cage mesh with deformed coordinates. */ + if ((is_mode_active && mr->me->runtime.is_original_bmesh && + mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) || + (do_uvedit && !do_final)) { + mr->extract_type = MR_EXTRACT_BMESH; } - - mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH; - - /* Seems like the mesh_eval_final do not have the right origin indices. - * Force not mapped in this case. */ - if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) { - // mr->edit_bmesh = NULL; + else { mr->extract_type = MR_EXTRACT_MESH; + + /* Use mapping from final to original mesh when the object is in edit mode. */ + if (is_mode_active && do_final) { + mr->v_origindex = static_cast<const int *>( + CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX)); + mr->e_origindex = static_cast<const int *>( + CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); + mr->p_origindex = static_cast<const int *>( + CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); + } + else { + mr->v_origindex = nullptr; + mr->e_origindex = nullptr; + mr->p_origindex = nullptr; + } } } else { mr->me = me; mr->edit_bmesh = nullptr; + mr->extract_type = MR_EXTRACT_MESH; - bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original; - if (use_mapped) { + if (is_paint_mode && mr->me) { mr->v_origindex = static_cast<const int *>( CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX)); mr->e_origindex = static_cast<const int *>( CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); mr->p_origindex = static_cast<const int *>( CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); - - use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); } - - mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH; + else { + mr->v_origindex = nullptr; + mr->e_origindex = nullptr; + mr->p_origindex = nullptr; + } } if (mr->extract_type != MR_EXTRACT_BMESH) { diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 91dbef8d7b1..7f7d0a7613f 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -36,10 +36,6 @@ extern "C" { /** \name Expose via BKE callbacks * \{ */ -void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode); -void DRW_mball_batch_cache_validate(struct MetaBall *mb); -void DRW_mball_batch_cache_free(struct MetaBall *mb); - void DRW_curve_batch_cache_dirty_tag(struct Curve *cu, int mode); void DRW_curve_batch_cache_validate(struct Curve *cu); void DRW_curve_batch_cache_free(struct Curve *cu); @@ -111,39 +107,6 @@ struct GPUBatch *DRW_curve_batch_cache_get_edit_verts(struct Curve *cu); /** \} */ /* -------------------------------------------------------------------- */ -/** \name Metaball - * \{ */ - -int DRW_metaball_material_count_get(struct MetaBall *mb); - -struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob); -struct GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(struct Object *ob, - struct MetaBall *mb, - struct GPUMaterial **gpumat_array, - uint gpumat_array_len); -struct GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(struct Object *ob); -struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob, - bool *r_is_manifold); - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name DispList - * \{ */ - -void DRW_displist_vertbuf_create_pos_and_nor(struct ListBase *lb, - struct GPUVertBuf *vbo, - const struct Scene *scene); -void DRW_displist_vertbuf_create_wiredata(struct ListBase *lb, struct GPUVertBuf *vbo); -void DRW_displist_indexbuf_create_lines_in_order(struct ListBase *lb, struct GPUIndexBuf *ibo); -void DRW_displist_indexbuf_create_triangles_in_order(struct ListBase *lb, struct GPUIndexBuf *ibo); -void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb, - struct GPUIndexBuf *ibo, - bool *r_is_manifold); - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Lattice * \{ */ @@ -309,7 +272,6 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me); * \{ */ struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me); -struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob); int DRW_mesh_material_count_get(const struct Object *object, const struct Mesh *me); diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c deleted file mode 100644 index 96c088c3ee9..00000000000 --- a/source/blender/draw/intern/draw_cache_impl_displist.c +++ /dev/null @@ -1,354 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2017 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup draw - * - * \brief DispList API for render engines - * - * \note DispList may be removed soon! This is a utility for object types that use render. - */ - -#include "BLI_edgehash.h" -#include "BLI_listbase.h" -#include "BLI_math_vector.h" -#include "BLI_utildefines.h" - -#include "DNA_curve_types.h" -#include "DNA_scene_types.h" - -#include "BKE_displist.h" - -#include "GPU_batch.h" -#include "GPU_capabilities.h" - -#include "draw_cache_inline.h" - -#include "draw_cache_impl.h" /* own include */ - -static int dl_vert_len(const DispList *dl) -{ - switch (dl->type) { - case DL_INDEX3: - case DL_INDEX4: - return dl->nr; - case DL_SURF: - return dl->parts * dl->nr; - } - return 0; -} - -static int dl_tri_len(const DispList *dl) -{ - switch (dl->type) { - case DL_INDEX3: - return dl->parts; - case DL_INDEX4: - return dl->parts * 2; - case DL_SURF: - return dl->totindex * 2; - } - return 0; -} - -/* see: displist_vert_coords_alloc */ -static int curve_render_surface_vert_len_get(const ListBase *lb) -{ - int vert_len = 0; - LISTBASE_FOREACH (const DispList *, dl, lb) { - vert_len += dl_vert_len(dl); - } - return vert_len; -} - -static int curve_render_surface_tri_len_get(const ListBase *lb) -{ - int tri_len = 0; - LISTBASE_FOREACH (const DispList *, dl, lb) { - tri_len += dl_tri_len(dl); - } - return tri_len; -} - -typedef void(SetTriIndicesFn)(void *thunk, uint v1, uint v2, uint v3); - -static void displist_indexbufbuilder_set( - SetTriIndicesFn *set_tri_indices, - SetTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */ - void *thunk, - const DispList *dl, - const int ofs) -{ - if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { - const int *idx = dl->index; - if (dl->type == DL_INDEX3) { - const int i_end = dl->parts; - for (int i = 0; i < i_end; i++, idx += 3) { - set_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs); - } - } - else if (dl->type == DL_SURF) { - const int i_end = dl->totindex; - for (int i = 0; i < i_end; i++, idx += 4) { - set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs); - set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[3] + ofs); - } - } - else { - BLI_assert(dl->type == DL_INDEX4); - const int i_end = dl->parts; - for (int i = 0; i < i_end; i++, idx += 4) { - if (idx[2] != idx[3]) { - set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs); - set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs); - } - else { - set_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs); - } - } - } - } -} - -void DRW_displist_vertbuf_create_pos_and_nor(ListBase *lb, GPUVertBuf *vbo, const Scene *scene) -{ - const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 || - GPU_use_hq_normals_workaround(); - - static GPUVertFormat format = {0}; - static GPUVertFormat format_hq = {0}; - static struct { - uint pos, nor; - uint pos_hq, nor_hq; - } attr_id; - if (format.attr_len == 0) { - /* initialize vertex format */ - attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.nor = GPU_vertformat_attr_add( - &format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - /* initialize vertex format */ - attr_id.pos_hq = GPU_vertformat_attr_add(&format_hq, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - attr_id.nor_hq = GPU_vertformat_attr_add( - &format_hq, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - uint pos_id = do_hq_normals ? attr_id.pos_hq : attr_id.pos; - uint nor_id = do_hq_normals ? attr_id.nor_hq : attr_id.nor; - - GPU_vertbuf_init_with_format(vbo, do_hq_normals ? &format_hq : &format); - GPU_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb)); - - BKE_displist_normals_add(lb); - - int vbo_len_used = 0; - LISTBASE_FOREACH (const DispList *, dl, lb) { - const bool ndata_is_single = dl->type == DL_INDEX3; - if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { - const float *fp_co = dl->verts; - const float *fp_no = dl->nors; - const int vbo_end = vbo_len_used + dl_vert_len(dl); - while (vbo_len_used < vbo_end) { - GPU_vertbuf_attr_set(vbo, pos_id, vbo_len_used, fp_co); - if (fp_no) { - GPUNormal vnor_pack; - GPU_normal_convert_v3(&vnor_pack, fp_no, do_hq_normals); - GPU_vertbuf_attr_set(vbo, nor_id, vbo_len_used, &vnor_pack); - if (ndata_is_single == false) { - fp_no += 3; - } - } - fp_co += 3; - vbo_len_used += 1; - } - } - } -} - -void DRW_vertbuf_create_wiredata(GPUVertBuf *vbo, const int vert_len) -{ - static GPUVertFormat format = {0}; - static struct { - uint wd; - } attr_id; - if (format.attr_len == 0) { - /* initialize vertex format */ - if (!GPU_crappy_amd_driver()) { - /* Some AMD drivers strangely crash with a vbo with this format. */ - attr_id.wd = GPU_vertformat_attr_add( - &format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - else { - attr_id.wd = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, vert_len); - - if (GPU_vertbuf_get_format(vbo)->stride == 1) { - memset(GPU_vertbuf_get_data(vbo), 0xFF, (size_t)vert_len); - } - else { - GPUVertBufRaw wd_step; - GPU_vertbuf_attr_get_raw_data(vbo, attr_id.wd, &wd_step); - for (int i = 0; i < vert_len; i++) { - *((float *)GPU_vertbuf_raw_step(&wd_step)) = 1.0f; - } - } -} - -void DRW_displist_vertbuf_create_wiredata(ListBase *lb, GPUVertBuf *vbo) -{ - const int vert_len = curve_render_surface_vert_len_get(lb); - DRW_vertbuf_create_wiredata(vbo, vert_len); -} - -void DRW_displist_indexbuf_create_triangles_in_order(ListBase *lb, GPUIndexBuf *ibo) -{ - const int tri_len = curve_render_surface_tri_len_get(lb); - const int vert_len = curve_render_surface_vert_len_get(lb); - - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len); - - int ofs = 0; - LISTBASE_FOREACH (const DispList *, dl, lb) { - displist_indexbufbuilder_set((SetTriIndicesFn *)GPU_indexbuf_add_tri_verts, - (SetTriIndicesFn *)GPU_indexbuf_add_tri_verts, - &elb, - dl, - ofs); - ofs += dl_vert_len(dl); - } - - GPU_indexbuf_build_in_place(&elb, ibo); -} - -static void set_overlay_wires_tri_indices(void *thunk, uint v1, uint v2, uint v3) -{ - GPUIndexBufBuilder *eld = (GPUIndexBufBuilder *)thunk; - GPU_indexbuf_add_line_verts(eld, v1, v2); - GPU_indexbuf_add_line_verts(eld, v2, v3); - GPU_indexbuf_add_line_verts(eld, v3, v1); -} - -static void set_overlay_wires_quad_tri_indices(void *thunk, uint v1, uint v2, uint v3) -{ - GPUIndexBufBuilder *eld = (GPUIndexBufBuilder *)thunk; - GPU_indexbuf_add_line_verts(eld, v1, v3); - GPU_indexbuf_add_line_verts(eld, v3, v2); -} - -void DRW_displist_indexbuf_create_lines_in_order(ListBase *lb, GPUIndexBuf *ibo) -{ - const int tri_len = curve_render_surface_tri_len_get(lb); - const int vert_len = curve_render_surface_vert_len_get(lb); - - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_LINES, tri_len * 3, vert_len); - - int ofs = 0; - LISTBASE_FOREACH (const DispList *, dl, lb) { - displist_indexbufbuilder_set( - set_overlay_wires_tri_indices, set_overlay_wires_quad_tri_indices, &elb, dl, ofs); - ofs += dl_vert_len(dl); - } - - GPU_indexbuf_build_in_place(&elb, ibo); -} - -/* Edge detection/adjacency. */ -#define NO_EDGE INT_MAX -static void set_edge_adjacency_lines_indices( - EdgeHash *eh, GPUIndexBufBuilder *elb, bool *r_is_manifold, uint v1, uint v2, uint v3) -{ - bool inv_indices = (v2 > v3); - void **pval; - bool value_is_init = BLI_edgehash_ensure_p(eh, v2, v3, &pval); - int v_data = POINTER_AS_INT(*pval); - if (!value_is_init || v_data == NO_EDGE) { - /* Save the winding order inside the sign bit. Because the - * edgehash sort the keys and we need to compare winding later. */ - int value = (int)v1 + 1; /* Int 0 bm_looptricannot be signed */ - *pval = POINTER_FROM_INT((inv_indices) ? -value : value); - } - else { - /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */ - *pval = POINTER_FROM_INT(NO_EDGE); - bool inv_opposite = (v_data < 0); - uint v_opposite = (uint)abs(v_data) - 1; - - if (inv_opposite == inv_indices) { - /* Don't share edge if triangles have non matching winding. */ - GPU_indexbuf_add_line_adj_verts(elb, v1, v2, v3, v1); - GPU_indexbuf_add_line_adj_verts(elb, v_opposite, v2, v3, v_opposite); - *r_is_manifold = false; - } - else { - GPU_indexbuf_add_line_adj_verts(elb, v1, v2, v3, v_opposite); - } - } -} - -static void set_edges_adjacency_lines_indices(void *thunk, uint v1, uint v2, uint v3) -{ - void **packed = (void **)thunk; - GPUIndexBufBuilder *elb = (GPUIndexBufBuilder *)packed[0]; - EdgeHash *eh = (EdgeHash *)packed[1]; - bool *r_is_manifold = (bool *)packed[2]; - - set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v1, v2, v3); - set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v2, v3, v1); - set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v3, v1, v2); -} - -void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb, - struct GPUIndexBuf *ibo, - bool *r_is_manifold) -{ - const int tri_len = curve_render_surface_tri_len_get(lb); - const int vert_len = curve_render_surface_vert_len_get(lb); - - *r_is_manifold = true; - - /* Allocate max but only used indices are sent to GPU. */ - GPUIndexBufBuilder elb; - GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, tri_len * 3, vert_len); - - EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3); - - /* pack values to pass to `set_edges_adjacency_lines_indices` function. */ - void *thunk[3] = {&elb, eh, r_is_manifold}; - int v_idx = 0; - LISTBASE_FOREACH (const DispList *, dl, lb) { - displist_indexbufbuilder_set((SetTriIndicesFn *)set_edges_adjacency_lines_indices, - (SetTriIndicesFn *)set_edges_adjacency_lines_indices, - thunk, - dl, - v_idx); - v_idx += dl_vert_len(dl); - } - - /* Create edges for remaining non manifold edges. */ - EdgeHashIterator *ehi; - for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false; - BLI_edgehashIterator_step(ehi)) { - uint v1, v2; - int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); - if (v_data == NO_EDGE) { - continue; - } - BLI_edgehashIterator_getKey(ehi, &v1, &v2); - uint v0 = (uint)abs(v_data) - 1; - if (v_data < 0) { /* inv_opposite */ - SWAP(uint, v1, v2); - } - GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0); - *r_is_manifold = false; - } - BLI_edgehashIterator_free(ehi); - BLI_edgehash_free(eh, NULL); - - GPU_indexbuf_build_in_place(&elb, ibo); -} -#undef NO_EDGE diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c index cb621c6ceb9..0f12e78d60e 100644 --- a/source/blender/draw/intern/draw_cache_impl_lattice.c +++ b/source/blender/draw/intern/draw_cache_impl_lattice.c @@ -27,12 +27,6 @@ #define SELECT 1 -/** - * TODO - * - 'DispList' is currently not used - * (we could avoid using since it will be removed) - */ - static void lattice_batch_cache_clear(Lattice *lt); /* ---------------------------------------------------------------------- */ diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index 5de9f1b44c8..e60689f0237 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -1509,12 +1509,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, cache->batch_ready |= batch_requested; bool do_cage = false, do_uvcage = false; - if (is_editmode) { + if (is_editmode && is_mode_active) { Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); do_cage = editmesh_eval_final != editmesh_eval_cage; - do_uvcage = !editmesh_eval_final->runtime.is_original; + do_uvcage = !(editmesh_eval_final->runtime.is_original_bmesh && + editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH); } const bool do_subdivision = BKE_subsurf_modifier_has_gpu_subdiv(me); diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c deleted file mode 100644 index 1408dc91069..00000000000 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ /dev/null @@ -1,294 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2017 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup draw - * - * \brief MetaBall API for render engines - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math_base.h" -#include "BLI_utildefines.h" - -#include "DNA_meta_types.h" -#include "DNA_object_types.h" - -#include "BKE_curve.h" -#include "BKE_mball.h" - -#include "GPU_batch.h" - -#include "DRW_render.h" -#include "draw_cache_impl.h" /* own include */ - -static void metaball_batch_cache_clear(MetaBall *mb); - -/* -------------------------------------------------------------------- */ -/** \name MetaBall GPUBatch Cache - * \{ */ - -typedef struct MetaBallBatchCache { - GPUBatch *batch; - GPUBatch **shaded_triangles; - - int mat_len; - - /* Shared */ - GPUVertBuf *pos_nor_in_order; - - /* Wireframe */ - struct { - GPUBatch *batch; - } face_wire; - - /* Edge detection */ - GPUBatch *edge_detection; - GPUIndexBuf *edges_adj_lines; - - /* settings to determine if cache is invalid */ - bool is_dirty; - - /* Valid only if edge_detection is up to date. */ - bool is_manifold; -} MetaBallBatchCache; - -/* GPUBatch cache management. */ - -static bool metaball_batch_cache_valid(MetaBall *mb) -{ - MetaBallBatchCache *cache = mb->batch_cache; - - if (cache == NULL) { - return false; - } - - return cache->is_dirty == false; -} - -static void metaball_batch_cache_init(MetaBall *mb) -{ - MetaBallBatchCache *cache = mb->batch_cache; - - if (!cache) { - cache = mb->batch_cache = MEM_mallocN(sizeof(*cache), __func__); - } - cache->batch = NULL; - cache->mat_len = 0; - cache->shaded_triangles = NULL; - cache->is_dirty = false; - cache->pos_nor_in_order = NULL; - cache->face_wire.batch = NULL; - cache->edge_detection = NULL; - cache->edges_adj_lines = NULL; - cache->is_manifold = false; -} - -void DRW_mball_batch_cache_validate(MetaBall *mb) -{ - if (!metaball_batch_cache_valid(mb)) { - metaball_batch_cache_clear(mb); - metaball_batch_cache_init(mb); - } -} - -static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb) -{ - return mb->batch_cache; -} - -void DRW_mball_batch_cache_dirty_tag(MetaBall *mb, int mode) -{ - MetaBallBatchCache *cache = mb->batch_cache; - if (cache == NULL) { - return; - } - switch (mode) { - case BKE_MBALL_BATCH_DIRTY_ALL: - cache->is_dirty = true; - break; - default: - BLI_assert(0); - } -} - -static void metaball_batch_cache_clear(MetaBall *mb) -{ - MetaBallBatchCache *cache = mb->batch_cache; - if (!cache) { - return; - } - - GPU_BATCH_DISCARD_SAFE(cache->face_wire.batch); - GPU_BATCH_DISCARD_SAFE(cache->batch); - GPU_BATCH_DISCARD_SAFE(cache->edge_detection); - GPU_VERTBUF_DISCARD_SAFE(cache->pos_nor_in_order); - GPU_INDEXBUF_DISCARD_SAFE(cache->edges_adj_lines); - /* NOTE: shaded_triangles[0] is already freed by `cache->batch`. */ - MEM_SAFE_FREE(cache->shaded_triangles); - cache->mat_len = 0; - cache->is_manifold = false; -} - -void DRW_mball_batch_cache_free(MetaBall *mb) -{ - metaball_batch_cache_clear(mb); - MEM_SAFE_FREE(mb->batch_cache); -} - -static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob, - MetaBallBatchCache *cache, - const struct Scene *scene) -{ - if (cache->pos_nor_in_order == NULL) { - ListBase *lb = &ob->runtime.curve_cache->disp; - cache->pos_nor_in_order = GPU_vertbuf_calloc(); - DRW_displist_vertbuf_create_pos_and_nor(lb, cache->pos_nor_in_order, scene); - } - return cache->pos_nor_in_order; -} - -static GPUIndexBuf *mball_batch_cache_get_edges_adj_lines(Object *ob, MetaBallBatchCache *cache) -{ - if (cache->edges_adj_lines == NULL) { - ListBase *lb = &ob->runtime.curve_cache->disp; - cache->edges_adj_lines = GPU_indexbuf_calloc(); - DRW_displist_indexbuf_create_edges_adjacency_lines( - lb, cache->edges_adj_lines, &cache->is_manifold); - } - return cache->edges_adj_lines; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Public Object/MetaBall API - * \{ */ - -GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob) -{ - if (!BKE_mball_is_basis(ob)) { - return NULL; - } - - MetaBall *mb = ob->data; - MetaBallBatchCache *cache = metaball_batch_cache_get(mb); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const struct Scene *scene = draw_ctx->scene; - - if (cache->batch == NULL) { - ListBase *lb = &ob->runtime.curve_cache->disp; - GPUIndexBuf *ibo = GPU_indexbuf_calloc(); - DRW_displist_indexbuf_create_triangles_in_order(lb, ibo); - cache->batch = GPU_batch_create_ex(GPU_PRIM_TRIS, - mball_batch_cache_get_pos_and_normals(ob, cache, scene), - ibo, - GPU_BATCH_OWNS_INDEX); - } - - return cache->batch; -} - -GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob, - MetaBall *mb, - struct GPUMaterial **UNUSED(gpumat_array), - uint gpumat_array_len) -{ - if (!BKE_mball_is_basis(ob)) { - return NULL; - } - - BLI_assert(gpumat_array_len == DRW_metaball_material_count_get(mb)); - - MetaBallBatchCache *cache = metaball_batch_cache_get(mb); - if (cache->shaded_triangles == NULL) { - cache->mat_len = gpumat_array_len; - cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * cache->mat_len, - __func__); - cache->shaded_triangles[0] = DRW_metaball_batch_cache_get_triangles_with_normals(ob); - for (int i = 1; i < cache->mat_len; i++) { - cache->shaded_triangles[i] = NULL; - } - } - return cache->shaded_triangles; -} - -GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(Object *ob) -{ - if (!BKE_mball_is_basis(ob)) { - return NULL; - } - - MetaBall *mb = ob->data; - MetaBallBatchCache *cache = metaball_batch_cache_get(mb); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const struct Scene *scene = draw_ctx->scene; - - if (cache->face_wire.batch == NULL) { - ListBase *lb = &ob->runtime.curve_cache->disp; - - GPUVertBuf *vbo_wiredata = GPU_vertbuf_calloc(); - DRW_displist_vertbuf_create_wiredata(lb, vbo_wiredata); - - GPUIndexBuf *ibo = GPU_indexbuf_calloc(); - DRW_displist_indexbuf_create_lines_in_order(lb, ibo); - - cache->face_wire.batch = GPU_batch_create_ex( - GPU_PRIM_LINES, - mball_batch_cache_get_pos_and_normals(ob, cache, scene), - ibo, - GPU_BATCH_OWNS_INDEX); - - GPU_batch_vertbuf_add_ex(cache->face_wire.batch, vbo_wiredata, true); - } - - return cache->face_wire.batch; -} - -struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob, - bool *r_is_manifold) -{ - if (!BKE_mball_is_basis(ob)) { - return NULL; - } - - MetaBall *mb = ob->data; - MetaBallBatchCache *cache = metaball_batch_cache_get(mb); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const struct Scene *scene = draw_ctx->scene; - - if (cache->edge_detection == NULL) { - cache->edge_detection = GPU_batch_create( - GPU_PRIM_LINES_ADJ, - mball_batch_cache_get_pos_and_normals(ob, cache, scene), - mball_batch_cache_get_edges_adj_lines(ob, cache)); - } - - if (r_is_manifold) { - *r_is_manifold = cache->is_manifold; - } - - return cache->edge_detection; -} - -struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(Object *ob) -{ - if (!BKE_mball_is_basis(ob)) { - return NULL; - } - - MetaBall *mb = ob->data; - MetaBallBatchCache *cache = metaball_batch_cache_get(mb); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const struct Scene *scene = draw_ctx->scene; - - return mball_batch_cache_get_pos_and_normals(ob, cache, scene); -} - -int DRW_metaball_material_count_get(MetaBall *mb) -{ - return max_ii(1, mb->totcol); -} - -/** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index 075e08eb49f..e86e342fea0 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -724,7 +724,7 @@ static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache *cach if (mr->extract_type == MR_EXTRACT_BMESH) { draw_subdiv_cache_extra_coarse_face_data_bm(cache->bm, mr->efa_act, flags_data); } - else if (mr->extract_type == MR_EXTRACT_MAPPED) { + else if (mr->p_origindex != NULL) { draw_subdiv_cache_extra_coarse_face_data_mapped(mesh, cache->bm, mr, flags_data); } else { diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 0f330dbb519..de56b34df78 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -417,7 +417,6 @@ bool DRW_object_is_flat(Object *ob, int *r_axis) OB_CURVES_LEGACY, OB_SURF, OB_FONT, - OB_MBALL, OB_CURVES, OB_POINTCLOUD, OB_VOLUME)) { diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc index aaf18014143..b9d10302c1e 100644 --- a/source/blender/draw/intern/draw_debug.cc +++ b/source/blender/draw/intern/draw_debug.cc @@ -21,6 +21,13 @@ #include <iomanip> +#ifdef DEBUG +# define DRAW_DEBUG +#else +/* Uncomment to forcibly enable debug draw in release mode. */ +//#define DRAW_DEBUG +#endif + namespace blender::draw { /* -------------------------------------------------------------------- */ @@ -595,7 +602,7 @@ blender::draw::DebugDraw *DRW_debug_get() void drw_debug_draw() { -#ifdef DEBUG +#ifdef DRAW_DEBUG if (!GPU_shader_storage_buffer_objects_support() || DST.debug == nullptr) { return; } @@ -611,7 +618,7 @@ void drw_debug_init() { /* Module should not be used in release builds. */ /* TODO(@fclem): Hide the functions declarations without using `ifdefs` everywhere. */ -#ifdef DEBUG +#ifdef DRAW_DEBUG if (!GPU_shader_storage_buffer_objects_support()) { return; } @@ -659,10 +666,12 @@ void DRW_debug_modelmat_reset() void DRW_debug_modelmat(const float modelmat[4][4]) { +#ifdef DRAW_DEBUG if (!GPU_shader_storage_buffer_objects_support()) { return; } reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->modelmat_set(modelmat); +#endif } void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]) @@ -704,10 +713,12 @@ void DRW_debug_m4_as_bbox(const float m[4][4], bool invert, const float color[4] void DRW_debug_bbox(const BoundBox *bbox, const float color[4]) { +#ifdef DRAW_DEBUG if (!GPU_shader_storage_buffer_objects_support()) { return; } reinterpret_cast<blender::draw::DebugDraw *>(DST.debug)->draw_bbox(*bbox, color); +#endif } void DRW_debug_sphere(const float center[3], float radius, const float color[4]) diff --git a/source/blender/draw/intern/draw_debug.hh b/source/blender/draw/intern/draw_debug.hh index 730b69ed954..c83936bf1af 100644 --- a/source/blender/draw/intern/draw_debug.hh +++ b/source/blender/draw/intern/draw_debug.hh @@ -113,17 +113,17 @@ class DebugDraw { print_no_endl(str, args...); print_newline(); } - template<typename T> void print(const T &&value) + template<typename T> void print(const T &value) { print_value(value); print_newline(); } - template<typename T> void print_hex(const T &&value) + template<typename T> void print_hex(const T &value) { print_value_hex(value); print_newline(); } - template<typename T> void print_binary(const T &&value) + template<typename T> void print_binary(const T &value) { print_value_binary(value); print_newline(); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 4693e5f8e20..3be2ddf5173 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2989,9 +2989,6 @@ void DRW_engines_register(void) /* setup callbacks */ { - BKE_mball_batch_cache_dirty_tag_cb = DRW_mball_batch_cache_dirty_tag; - BKE_mball_batch_cache_free_cb = DRW_mball_batch_cache_free; - BKE_curve_batch_cache_dirty_tag_cb = DRW_curve_batch_cache_dirty_tag; BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 9d4a2c58ab6..913d1b4c3f4 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1188,16 +1188,15 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers DRW_shgroup_uniform_vec3( shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->debug_node_nr++), 1); } + /* DRW_shgroup_call_no_cull reuses matrices calculations for all the drawcalls of this * object. */ DRW_shgroup_call_no_cull(shgrp, geom, scd->ob); } } -static void sculpt_debug_cb(void *user_data, - const float bmin[3], - const float bmax[3], - PBVHNodeFlags flag) +static void sculpt_debug_cb( + PBVHNode *node, void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag) { int *debug_node_nr = (int *)user_data; BoundBox bb; @@ -1212,7 +1211,10 @@ static void sculpt_debug_cb(void *user_data, } #else /* Color coded leaf bounds. */ if (flag & PBVH_Leaf) { - DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*debug_node_nr)++)); + int color = (*debug_node_nr)++; + color += BKE_pbvh_debug_draw_gen_get(node); + + DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR(color)); } #endif } @@ -1305,8 +1307,8 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) DRW_debug_modelmat(scd->ob->obmat); BKE_pbvh_draw_debug_cb( pbvh, - (void (*)( - void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb, + (void (*)(PBVHNode * n, void *d, const float min[3], const float max[3], PBVHNodeFlags f)) + sculpt_debug_cb, &debug_node_nr); } } @@ -2128,6 +2130,14 @@ void DRW_view_update(DRWView *view, draw_frustum_bound_sphere_calc( &view->frustum_corners, viewinv, winmat, wininv, &view->frustum_bsphere); + /* TODO(fclem): Deduplicate. */ + for (int i = 0; i < 8; i++) { + copy_v3_v3(view->storage.frustum_corners[i], view->frustum_corners.vec[i]); + } + for (int i = 0; i < 6; i++) { + copy_v4_v4(view->storage.frustum_planes[i], view->frustum_planes[i]); + } + #ifdef DRW_DEBUG_CULLING if (G.debug_value != 0) { DRW_debug_sphere( diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index 57abf088c16..5d55af904e8 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -29,7 +29,6 @@ struct DRWSubdivCache; enum eMRExtractType { MR_EXTRACT_BMESH, - MR_EXTRACT_MAPPED, MR_EXTRACT_MESH, }; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index 9f82cc56941..fa39957a7fc 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -59,13 +59,11 @@ static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr, void *_data) { MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); - const MPoly *mp = &mr->mpoly[mlt->poly]; - edituv_tri_add(data, - mr->hide_poly && mr->hide_poly[mlt->poly], - (mp->flag & ME_FACE_SEL) != 0, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2]); + const BMFace *efa = bm_original_face_get(mr, mlt->poly); + const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true; + const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; + + edituv_tri_add(data, mp_hidden, mp_select, mlt->tri[0], mlt->tri[1], mlt->tri[2]); } static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), @@ -125,13 +123,12 @@ static void extract_edituv_tris_iter_subdiv_mesh(const DRWSubdivCache *UNUSED(su MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); const uint loop_idx = subdiv_quad_index * 4; - const bool hidden = mr->hide_poly && mr->hide_poly[coarse_quad - mr->mpoly]; + const BMFace *efa = bm_original_face_get(mr, coarse_quad - mr->mpoly); + const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true; + const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; - edituv_tri_add( - data, hidden, (coarse_quad->flag & ME_FACE_SEL) != 0, loop_idx, loop_idx + 1, loop_idx + 2); - - edituv_tri_add( - data, hidden, (coarse_quad->flag & ME_FACE_SEL) != 0, loop_idx, loop_idx + 2, loop_idx + 3); + edituv_tri_add(data, mp_hidden, mp_select, loop_idx, loop_idx + 1, loop_idx + 2); + edituv_tri_add(data, mp_hidden, mp_select, loop_idx, loop_idx + 2, loop_idx + 3); } static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), @@ -208,14 +205,17 @@ static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr), static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, const MPoly *mp, - const int UNUSED(mp_index), + const int mp_index, void *_data) { MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); - const bool hidden = mr->hide_poly && mr->hide_poly[mp - mr->mpoly]; - const MLoop *mloop = mr->mloop; const int ml_index_end = mp->loopstart + mp->totloop; + + const BMFace *efa = bm_original_face_get(mr, mp_index); + const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true; + const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { const MLoop *ml = &mloop[ml_index]; @@ -223,8 +223,7 @@ static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); const bool real_edge = (mr->e_origindex == nullptr || mr->e_origindex[ml->e] != ORIGINDEX_NONE); - edituv_edge_add( - data, hidden || !real_edge, (mp->flag & ME_FACE_SEL) != 0, ml_index, ml_index_next); + edituv_edge_add(data, mp_hidden || !real_edge, mp_select, ml_index, ml_index_next); } } @@ -259,6 +258,9 @@ static void extract_edituv_lines_iter_subdiv_bm(const DRWSubdivCache *subdiv_cac MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + const bool mp_hidden = BM_elem_flag_test_bool(coarse_poly, BM_ELEM_HIDDEN); + const bool mp_select = BM_elem_flag_test_bool(coarse_poly, BM_ELEM_SELECT); + uint start_loop_idx = subdiv_quad_index * 4; uint end_loop_idx = (subdiv_quad_index + 1) * 4; for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) { @@ -267,8 +269,8 @@ static void extract_edituv_lines_iter_subdiv_bm(const DRWSubdivCache *subdiv_cac (mr->e_origindex == nullptr || mr->e_origindex[edge_origindex] != ORIGINDEX_NONE)); edituv_edge_add(data, - BM_elem_flag_test_bool(coarse_poly, BM_ELEM_HIDDEN) != 0 || !real_edge, - BM_elem_flag_test_bool(coarse_poly, BM_ELEM_SELECT) != 0, + mp_hidden || !real_edge, + mp_select, loop_idx, (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1)); } @@ -281,10 +283,12 @@ static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_c const MPoly *coarse_poly) { MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); - const bool hidden = mr->hide_poly && mr->hide_poly[coarse_poly - mr->mpoly]; - int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + const BMFace *efa = bm_original_face_get(mr, coarse_poly - mr->mpoly); + const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true; + const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; + uint start_loop_idx = subdiv_quad_index * 4; uint end_loop_idx = (subdiv_quad_index + 1) * 4; for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) { @@ -293,8 +297,8 @@ static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_c (mr->e_origindex == nullptr || mr->e_origindex[edge_origindex] != ORIGINDEX_NONE)); edituv_edge_add(data, - hidden || !real_edge, - (coarse_poly->flag & ME_FACE_SEL) != 0, + mp_hidden || !real_edge, + mp_select, loop_idx, (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1)); } @@ -373,11 +377,14 @@ static void extract_edituv_points_iter_poly_bm(const MeshRenderData *UNUSED(mr), static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, const MPoly *mp, - const int UNUSED(mp_index), + const int mp_index, void *_data) { MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); - const bool hidden = mr->hide_poly && mr->hide_poly[mp - mr->mpoly]; + + const BMFace *efa = bm_original_face_get(mr, mp_index); + const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true; + const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; const MLoop *mloop = mr->mloop; const int ml_index_end = mp->loopstart + mp->totloop; @@ -385,7 +392,7 @@ static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, const MLoop *ml = &mloop[ml_index]; const bool real_vert = !mr->v_origindex || mr->v_origindex[ml->v] != ORIGINDEX_NONE; - edituv_point_add(data, hidden || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index); + edituv_point_add(data, mp_hidden || !real_vert, mp_select, ml_index); } } @@ -438,16 +445,19 @@ static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_ const MPoly *coarse_quad) { MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); - const bool hidden = mr->hide_poly && mr->hide_poly[coarse_quad - mr->mpoly]; int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + const BMFace *efa = bm_original_face_get(mr, coarse_quad - mr->mpoly); + const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true; + const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; + uint start_loop_idx = subdiv_quad_index * 4; uint end_loop_idx = (subdiv_quad_index + 1) * 4; for (uint i = start_loop_idx; i < end_loop_idx; i++) { const int vert_origindex = subdiv_loop_vert_index[i]; const bool real_vert = !mr->v_origindex || (vert_origindex != -1 && mr->v_origindex[vert_origindex] != ORIGINDEX_NONE); - edituv_point_add(data, hidden || !real_vert, (coarse_quad->flag & ME_FACE_SEL) != 0, i); + edituv_point_add(data, mp_hidden || !real_vert, mp_select, i); } } @@ -527,7 +537,10 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, void *_data) { MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); - const bool hidden = mr->hide_poly && mr->hide_poly[mp - mr->mpoly]; + + const BMFace *efa = bm_original_face_get(mr, mp_index); + const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true; + const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; if (mr->use_subsurf_fdots) { const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags; @@ -539,13 +552,12 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, const bool real_fdot = !mr->p_origindex || (mr->p_origindex[mp_index] != ORIGINDEX_NONE); const bool subd_fdot = BLI_BITMAP_TEST(facedot_tags, ml->v); - edituv_facedot_add( - data, hidden || !real_fdot || !subd_fdot, (mp->flag & ME_FACE_SEL) != 0, mp_index); + edituv_facedot_add(data, mp_hidden || !real_fdot || !subd_fdot, mp_select, mp_index); } } else { const bool real_fdot = !mr->p_origindex || (mr->p_origindex[mp_index] != ORIGINDEX_NONE); - edituv_facedot_add(data, hidden || !real_fdot, (mp->flag & ME_FACE_SEL) != 0, mp_index); + edituv_facedot_add(data, mp_hidden || !real_fdot, mp_select, mp_index); } } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc index fe883fb0c96..9c564c2cdda 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -58,14 +58,13 @@ static void extract_lines_iter_poly_mesh(const MeshRenderData *mr, GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data); /* Using poly & loop iterator would complicate accessing the adjacent loop. */ const MLoop *mloop = mr->mloop; - if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != nullptr)) { + if (mr->use_hide || (mr->e_origindex != nullptr)) { const int ml_index_last = mp->loopstart + (mp->totloop - 1); int ml_index = ml_index_last, ml_index_next = mp->loopstart; do { const MLoop *ml = &mloop[ml_index]; if (!((mr->use_hide && mr->hide_edge && mr->hide_edge[ml->e]) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) { + ((mr->e_origindex) && (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) { GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); } else { @@ -110,8 +109,7 @@ static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr, const int l_index_offset = mr->edge_len + ledge_index; const int e_index = mr->ledges[ledge_index]; if (!((mr->use_hide && mr->hide_edge && mr->hide_edge[med - mr->medge]) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { + ((mr->e_origindex) && (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { const int l_index = mr->loop_len + ledge_index * 2; GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); } @@ -183,40 +181,41 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, switch (mr->extract_type) { case MR_EXTRACT_MESH: { - const bool *hide_vert = mr->hide_vert; - if (hide_vert) { - for (DRWSubdivLooseEdge edge : loose_edges) { - *flags_data++ = hide_vert[edge.coarse_edge_index]; + if (mr->e_origindex == nullptr) { + const bool *hide_edge = mr->hide_edge; + if (hide_edge) { + for (DRWSubdivLooseEdge edge : loose_edges) { + *flags_data++ = hide_edge[edge.coarse_edge_index]; + } } - } - else { - MutableSpan<uint>(flags_data, loose_edges.size()).fill(0); - } - break; - } - case MR_EXTRACT_MAPPED: { - if (mr->bm) { - for (DRWSubdivLooseEdge edge : loose_edges) { - const BMEdge *bm_edge = bm_original_edge_get(mr, edge.coarse_edge_index); - *flags_data++ = BM_elem_flag_test_bool(bm_edge, BM_ELEM_HIDDEN) != 0; + else { + MutableSpan<uint>(flags_data, loose_edges.size()).fill(0); } } else { - const bool *hide_vert = mr->hide_vert; - if (hide_vert) { + if (mr->bm) { for (DRWSubdivLooseEdge edge : loose_edges) { - int e = edge.coarse_edge_index; - - if (mr->e_origindex && mr->e_origindex[e] != ORIGINDEX_NONE) { - *flags_data++ = hide_vert[edge.coarse_edge_index]; - } - else { - *flags_data++ = false; - } + const BMEdge *bm_edge = bm_original_edge_get(mr, edge.coarse_edge_index); + *flags_data++ = BM_elem_flag_test_bool(bm_edge, BM_ELEM_HIDDEN) != 0; } } else { - MutableSpan<uint>(flags_data, loose_edges.size()).fill(0); + const bool *hide_edge = mr->hide_edge; + if (hide_edge) { + for (DRWSubdivLooseEdge edge : loose_edges) { + int e = edge.coarse_edge_index; + + if (mr->e_origindex && mr->e_origindex[e] != ORIGINDEX_NONE) { + *flags_data++ = hide_edge[edge.coarse_edge_index]; + } + else { + *flags_data++ = false; + } + } + } + else { + MutableSpan<uint>(flags_data, loose_edges.size()).fill(0); + } } } break; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc index d5f31c08eaf..31e5c515129 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc @@ -48,8 +48,7 @@ static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, const int e_index = ml->e; if (!((mr->use_hide && mr->hide_edge && mr->hide_edge[e_index]) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { + ((mr->e_origindex) && (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { const int ml_index_last = mp->totloop + mp->loopstart - 1; const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); @@ -122,8 +121,7 @@ static void extract_lines_paint_mask_iter_subdiv_mesh(const DRWSubdivCache *subd } else { if (!((mr->use_hide && mr->hide_edge && mr->hide_edge[coarse_edge_index]) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[coarse_edge_index] == ORIGINDEX_NONE)))) { + ((mr->e_origindex) && (mr->e_origindex[coarse_edge_index] == ORIGINDEX_NONE)))) { const uint ml_index_other = (loop_idx == (end_loop_idx - 1)) ? start_loop_idx : loop_idx + 1; if (coarse_quad->flag & ME_FACE_SEL) { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc index ca46a38823d..48eeb86e5ee 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc @@ -45,8 +45,7 @@ BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb, { const bool hidden = mr->use_hide && mr->hide_vert && mr->hide_vert[v_index]; - if (!(hidden || ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[v_index] == ORIGINDEX_NONE)))) { + if (!(hidden || ((mr->v_origindex) && (mr->v_origindex[v_index] == ORIGINDEX_NONE)))) { GPU_indexbuf_set_point_vert(elb, v_index, l_index); } else { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc index 969ff9f6f09..e4714aabf34 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc @@ -97,7 +97,7 @@ static void extract_edituv_stretch_angle_init(const MeshRenderData *mr, data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); } else { - BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); + BLI_assert(mr->extract_type == MR_EXTRACT_MESH); data->luv = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); } } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index 2bb786303c4..febddf61e1f 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -72,7 +72,7 @@ static void compute_area_ratio(const MeshRenderData *mr, } } else { - BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); + BLI_assert(mr->extract_type == MR_EXTRACT_MESH); const MLoopUV *uv_data = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); const MPoly *mp = mr->mpoly; for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { @@ -117,7 +117,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, } } else { - BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); + BLI_assert(mr->extract_type == MR_EXTRACT_MESH); const MPoly *mp = mr->mpoly; for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { for (int i = 0; i < mp->totloop; i++, l_index++) { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc index c2af7f2c9bd..c47cde63630 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc @@ -48,8 +48,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, for (int f = 0; f < mr->poly_len; f++) { efa = BM_face_at_index(mr->bm, f); const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { + if (is_face_hidden || (mr->p_origindex && mr->p_origindex[f] == ORIGINDEX_NONE)) { nor[f] = GPU_normal_convert_i10_v3(invalid_normal); nor[f].w = NOR_AND_FLAG_HIDDEN; } @@ -66,8 +65,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, for (int f = 0; f < mr->poly_len; f++) { efa = bm_original_face_get(mr, f); const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { + if (is_face_hidden || (mr->p_origindex && mr->p_origindex[f] == ORIGINDEX_NONE)) { nor[f] = GPU_normal_convert_i10_v3(invalid_normal); nor[f].w = NOR_AND_FLAG_HIDDEN; } @@ -130,8 +128,7 @@ static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, for (int f = 0; f < mr->poly_len; f++) { efa = BM_face_at_index(mr->bm, f); const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { + if (is_face_hidden || (mr->p_origindex && mr->p_origindex[f] == ORIGINDEX_NONE)) { normal_float_to_short_v3(&nor[f * 4], invalid_normal); nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN; } @@ -148,8 +145,7 @@ static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, for (int f = 0; f < mr->poly_len; f++) { efa = bm_original_face_get(mr, f); const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { + if (is_face_hidden || (mr->p_origindex && mr->p_origindex[f] == ORIGINDEX_NONE)) { normal_float_to_short_v3(&nor[f * 4], invalid_normal); nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc index ef67e1b540d..01d07fa5f83 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -80,10 +80,10 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, } /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * Only use origindex in edit mode where it is used to display the edge-normals. * In paint mode it will use the un-mapped data to draw the wire-frame. */ - if (hidden || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + if (hidden || + (mr->edit_bmesh && (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { lnor_data->w = -1; } else if (mp->flag & ME_FACE_SEL) { @@ -205,10 +205,10 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, } /* Flag for paint mode overlay. - * Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * Only use origindex in edit mode where it is used to display the edge-normals. * In paint mode it will use the un-mapped data to draw the wire-frame. */ - if (hidden || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + if (hidden || + (mr->edit_bmesh && (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { lnor_data->w = -1; } else if (mp->flag & ME_FACE_SEL) { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc index 313838be9e8..a822845c688 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc @@ -101,8 +101,7 @@ static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, vert->nor = data->normals[ml->v].low; /* Flag for paint mode overlay. */ if (poly_hidden || vert_hidden || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { + ((mr->v_origindex) && (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { vert->nor.w = -1; } else if (mv->flag & SELECT) { @@ -449,8 +448,7 @@ static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr, /* Flag for paint mode overlay. */ if (poly_hidden || vert_hidden || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { + ((mr->v_origindex) && (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { vert->nor[3] = -1; } else if (mv->flag & SELECT) { diff --git a/source/blender/draw/intern/shaders/common_aabb_lib.glsl b/source/blender/draw/intern/shaders/common_aabb_lib.glsl new file mode 100644 index 00000000000..b5f664a6779 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_aabb_lib.glsl @@ -0,0 +1,59 @@ + +#pragma BLENDER_REQUIRE(common_shape_lib.glsl) + +/* ---------------------------------------------------------------------- */ +/** \name Axis Aligned Bound Box + * \{ */ + +struct AABB { + vec3 min, max; +}; + +AABB aabb_init_min_max() +{ + AABB aabb; + aabb.min = vec3(1.0e30); + aabb.max = vec3(-1.0e30); + return aabb; +} + +void aabb_merge(inout AABB aabb, vec3 v) +{ + aabb.min = min(aabb.min, v); + aabb.max = max(aabb.max, v); +} + +/** + * Return true if there is any intersection. + */ +bool aabb_intersect(AABB a, AABB b) +{ + return all(greaterThanEqual(min(a.max, b.max), max(a.min, b.min))); +} + +/** + * Compute intersect intersection volume of \a a and \a b. + * Return true if the resulting volume is not empty. + */ +bool aabb_clip(AABB a, AABB b, out AABB c) +{ + c.min = max(a.min, b.min); + c.max = min(a.max, b.max); + return all(greaterThanEqual(c.max, c.min)); +} + +Box aabb_to_box(AABB aabb) +{ + Box box; + box.corners[0] = aabb.min; + box.corners[1] = vec3(aabb.max.x, aabb.min.y, aabb.min.z); + box.corners[2] = vec3(aabb.max.x, aabb.max.y, aabb.min.z); + box.corners[3] = vec3(aabb.min.x, aabb.max.y, aabb.min.z); + box.corners[4] = vec3(aabb.min.x, aabb.min.y, aabb.max.z); + box.corners[5] = vec3(aabb.max.x, aabb.min.y, aabb.max.z); + box.corners[6] = aabb.max; + box.corners[7] = vec3(aabb.min.x, aabb.max.y, aabb.max.z); + return box; +} + +/** \} */ diff --git a/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl b/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl index 7a79f957462..5f795d3abdb 100644 --- a/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl +++ b/source/blender/draw/intern/shaders/common_debug_draw_lib.glsl @@ -11,7 +11,7 @@ bool drw_debug_draw_enable = true; const vec4 drw_debug_default_color = vec4(1.0, 0.0, 0.0, 1.0); /* -------------------------------------------------------------------- */ -/** \name Interals +/** \name Internals * \{ */ uint drw_debug_start_draw(uint v_needed) @@ -148,14 +148,14 @@ void drw_debug_sphere(vec3 p, float radius, vec4 color) for (int axis = 0; axis < 3; axis++) { for (int edge = 0; edge < circle_resolution; edge++) { float angle1 = (2.0 * 3.141592) * float(edge + 0) / float(circle_resolution); - vec3 p1 = vec3(cos(angle1), sin(angle1), 0.0); + vec3 p1 = vec3(cos(angle1), sin(angle1), 0.0) * radius; p1 = vec3(p1[(0 + axis) % 3], p1[(1 + axis) % 3], p1[(2 + axis) % 3]); float angle2 = (2.0 * 3.141592) * float(edge + 1) / float(circle_resolution); - vec3 p2 = vec3(cos(angle2), sin(angle2), 0.0); + vec3 p2 = vec3(cos(angle2), sin(angle2), 0.0) * radius; p2 = vec3(p2[(0 + axis) % 3], p2[(1 + axis) % 3], p2[(2 + axis) % 3]); - drw_debug_line(vertid, p1, p2, pcolor); + drw_debug_line(vertid, p + p1, p + p2, pcolor); } } } diff --git a/source/blender/draw/intern/shaders/common_debug_shape_lib.glsl b/source/blender/draw/intern/shaders/common_debug_shape_lib.glsl new file mode 100644 index 00000000000..538c55ce544 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_debug_shape_lib.glsl @@ -0,0 +1,57 @@ + +/** + * Debug drawing of shapes. + */ + +#pragma BLENDER_REQUIRE(common_debug_draw_lib.glsl) +#pragma BLENDER_REQUIRE(common_shape_lib.glsl) + +void drw_debug(Box shape, vec4 color) +{ + drw_debug_quad(shape.corners[0], shape.corners[1], shape.corners[2], shape.corners[3], color); + drw_debug_line(shape.corners[0], shape.corners[4], color); + drw_debug_line(shape.corners[1], shape.corners[5], color); + drw_debug_line(shape.corners[2], shape.corners[6], color); + drw_debug_line(shape.corners[3], shape.corners[7], color); + drw_debug_quad(shape.corners[4], shape.corners[5], shape.corners[6], shape.corners[7], color); +} +void drw_debug(Box shape) +{ + drw_debug(shape, drw_debug_default_color); +} + +void drw_debug(Frustum shape, vec4 color) +{ + drw_debug_quad(shape.corners[0], shape.corners[1], shape.corners[2], shape.corners[3], color); + drw_debug_line(shape.corners[0], shape.corners[4], color); + drw_debug_line(shape.corners[1], shape.corners[5], color); + drw_debug_line(shape.corners[2], shape.corners[6], color); + drw_debug_line(shape.corners[3], shape.corners[7], color); + drw_debug_quad(shape.corners[4], shape.corners[5], shape.corners[6], shape.corners[7], color); +} +void drw_debug(Frustum shape) +{ + drw_debug(shape, drw_debug_default_color); +} + +void drw_debug(Pyramid shape, vec4 color) +{ + drw_debug_line(shape.corners[0], shape.corners[1], color); + drw_debug_line(shape.corners[0], shape.corners[2], color); + drw_debug_line(shape.corners[0], shape.corners[3], color); + drw_debug_line(shape.corners[0], shape.corners[4], color); + drw_debug_quad(shape.corners[1], shape.corners[2], shape.corners[3], shape.corners[4], color); +} +void drw_debug(Pyramid shape) +{ + drw_debug(shape, drw_debug_default_color); +} + +void drw_debug(Sphere shape, vec4 color) +{ + drw_debug_sphere(shape.center, shape.radius, color); +} +void drw_debug(Sphere shape) +{ + drw_debug(shape, drw_debug_default_color); +} diff --git a/source/blender/draw/intern/shaders/common_intersect_lib.glsl b/source/blender/draw/intern/shaders/common_intersect_lib.glsl new file mode 100644 index 00000000000..33378588553 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_intersect_lib.glsl @@ -0,0 +1,398 @@ + +/** + * Intersection library used for culling. + * Results are meant to be conservative. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(common_shape_lib.glsl) + +/* ---------------------------------------------------------------------- */ +/** \name Plane extraction functions. + * \{ */ + +/** \a v1 and \a v2 are vectors on the plane. \a p is a point on the plane. */ +vec4 isect_plane_setup(vec3 p, vec3 v1, vec3 v2) +{ + vec3 normal_to_plane = normalize(cross(v1, v2)); + return vec4(normal_to_plane, -dot(normal_to_plane, p)); +} + +struct IsectPyramid { + vec3 corners[5]; + vec4 planes[5]; +}; + +IsectPyramid isect_data_setup(Pyramid shape) +{ + vec3 A1 = shape.corners[1] - shape.corners[0]; + vec3 A2 = shape.corners[2] - shape.corners[0]; + vec3 A3 = shape.corners[3] - shape.corners[0]; + vec3 A4 = shape.corners[4] - shape.corners[0]; + vec3 S4 = shape.corners[4] - shape.corners[1]; + vec3 S2 = shape.corners[2] - shape.corners[1]; + + IsectPyramid data; + data.planes[0] = isect_plane_setup(shape.corners[0], A2, A1); + data.planes[1] = isect_plane_setup(shape.corners[0], A3, A2); + data.planes[2] = isect_plane_setup(shape.corners[0], A4, A3); + data.planes[3] = isect_plane_setup(shape.corners[0], A1, A4); + data.planes[4] = isect_plane_setup(shape.corners[1], S2, S4); + for (int i = 0; i < 5; i++) { + data.corners[i] = shape.corners[i]; + } + return data; +} + +struct IsectBox { + vec3 corners[8]; + vec4 planes[6]; +}; + +IsectBox isect_data_setup(Box shape) +{ + vec3 A1 = shape.corners[1] - shape.corners[0]; + vec3 A3 = shape.corners[3] - shape.corners[0]; + vec3 A4 = shape.corners[4] - shape.corners[0]; + + IsectBox data; + data.planes[0] = isect_plane_setup(shape.corners[0], A3, A1); + data.planes[1] = isect_plane_setup(shape.corners[0], A4, A3); + data.planes[2] = isect_plane_setup(shape.corners[0], A1, A4); + /* Assumes that the box is actually a box! */ + data.planes[3] = vec4(-data.planes[0].xyz, -dot(-data.planes[0].xyz, shape.corners[6])); + data.planes[4] = vec4(-data.planes[1].xyz, -dot(-data.planes[1].xyz, shape.corners[6])); + data.planes[5] = vec4(-data.planes[2].xyz, -dot(-data.planes[2].xyz, shape.corners[6])); + for (int i = 0; i < 8; i++) { + data.corners[i] = shape.corners[i]; + } + return data; +} + +struct IsectFrustum { + vec3 corners[8]; + vec4 planes[6]; +}; + +IsectFrustum isect_data_setup(Frustum shape) +{ + vec3 A1 = shape.corners[1] - shape.corners[0]; + vec3 A3 = shape.corners[3] - shape.corners[0]; + vec3 A4 = shape.corners[4] - shape.corners[0]; + vec3 B5 = shape.corners[5] - shape.corners[6]; + vec3 B7 = shape.corners[7] - shape.corners[6]; + vec3 B2 = shape.corners[2] - shape.corners[6]; + + IsectFrustum data; + data.planes[0] = isect_plane_setup(shape.corners[0], A3, A1); + data.planes[1] = isect_plane_setup(shape.corners[0], A4, A3); + data.planes[2] = isect_plane_setup(shape.corners[0], A1, A4); + data.planes[3] = isect_plane_setup(shape.corners[6], B7, B5); + data.planes[4] = isect_plane_setup(shape.corners[6], B5, B2); + data.planes[5] = isect_plane_setup(shape.corners[6], B2, B7); + for (int i = 0; i < 8; i++) { + data.corners[i] = shape.corners[i]; + } + return data; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name View Intersection functions. + * \{ */ + +bool intersect_view(Pyramid pyramid) +{ + bool intersects = true; + + /* Do Pyramid vertices vs Frustum planes. */ + for (int p = 0; p < 6; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 5; ++v) { + float test = dot(drw_view.frustum_planes[p], vec4(pyramid.corners[v], 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + + if (!intersects) { + return intersects; + } + + /* Now do Frustum vertices vs Pyramid planes. */ + IsectPyramid i_pyramid = isect_data_setup(pyramid); + for (int p = 0; p < 5; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8; ++v) { + float test = dot(i_pyramid.planes[p], vec4(drw_view.frustum_corners[v].xyz, 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + return intersects; +} + +bool intersect_view(Box box) +{ + bool intersects = true; + + /* Do Box vertices vs Frustum planes. */ + for (int p = 0; p < 6; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8; ++v) { + float test = dot(drw_view.frustum_planes[p], vec4(box.corners[v], 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + + if (!intersects) { + return intersects; + } + + /* Now do Frustum vertices vs Box planes. */ + IsectBox i_box = isect_data_setup(box); + for (int p = 0; p < 6; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8; ++v) { + float test = dot(i_box.planes[p], vec4(drw_view.frustum_corners[v].xyz, 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + + return intersects; +} + +bool intersect_view(Sphere sphere) +{ + bool intersects = true; + + for (int p = 0; p < 6 && intersects; ++p) { + float dist_to_plane = dot(drw_view.frustum_planes[p], vec4(sphere.center, 1.0)); + if (dist_to_plane < -sphere.radius) { + intersects = false; + } + } + /* TODO reject false positive. */ + return intersects; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Shape vs. Shape Intersection functions. + * \{ */ + +bool intersect(IsectPyramid i_pyramid, Box box) +{ + bool intersects = true; + + /* Do Box vertices vs Pyramid planes. */ + for (int p = 0; p < 5; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8; ++v) { + float test = dot(i_pyramid.planes[p], vec4(box.corners[v], 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + + if (!intersects) { + return intersects; + } + + /* Now do Pyramid vertices vs Box planes. */ + IsectBox i_box = isect_data_setup(box); + for (int p = 0; p < 6; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 5; ++v) { + float test = dot(i_box.planes[p], vec4(i_pyramid.corners[v], 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + return intersects; +} + +bool intersect(IsectFrustum i_frustum, Pyramid pyramid) +{ + bool intersects = true; + + /* Do Pyramid vertices vs Frustum planes. */ + for (int p = 0; p < 6; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 5; ++v) { + float test = dot(i_frustum.planes[p], vec4(pyramid.corners[v], 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + + if (!intersects) { + return intersects; + } + + /* Now do Frustum vertices vs Pyramid planes. */ + IsectPyramid i_pyramid = isect_data_setup(pyramid); + for (int p = 0; p < 5; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8; ++v) { + float test = dot(i_pyramid.planes[p], vec4(i_frustum.corners[v].xyz, 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + return intersects; +} + +bool intersect(IsectFrustum i_frustum, Box box) +{ + bool intersects = true; + + /* Do Box vertices vs Frustum planes. */ + for (int p = 0; p < 6; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8; ++v) { + float test = dot(i_frustum.planes[p], vec4(box.corners[v], 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + + if (!intersects) { + return intersects; + } + + /* Now do Frustum vertices vs Box planes. */ + IsectBox i_box = isect_data_setup(box); + for (int p = 0; p < 6; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8; ++v) { + float test = dot(i_box.planes[p], vec4(i_frustum.corners[v].xyz, 1.0)); + if (test > 0.0) { + is_any_vertex_on_positive_side = true; + break; + } + } + bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side; + if (all_vertex_on_negative_side) { + intersects = false; + break; + } + } + + return intersects; +} + +bool intersect(IsectFrustum i_frustum, Sphere sphere) +{ + bool intersects = true; + for (int p = 0; p < 6; ++p) { + float dist_to_plane = dot(i_frustum.planes[p], vec4(sphere.center, 1.0)); + if (dist_to_plane < -sphere.radius) { + intersects = false; + break; + } + } + return intersects; +} + +bool intersect(Cone cone, Sphere sphere) +{ + /** + * Following "Improve Tile-based Light Culling with Spherical-sliced Cone" + * by Eric Zhang + * https://lxjk.github.io/2018/03/25/Improve-Tile-based-Light-Culling-with-Spherical-sliced-Cone.html + */ + float sphere_distance = length(sphere.center); + float sphere_distance_rcp = safe_rcp(sphere_distance); + float sphere_sin = saturate(sphere.radius * sphere_distance_rcp); + float sphere_cos = sqrt(1.0 - sphere_sin * sphere_sin); + float cone_aperture_sin = sqrt(1.0 - cone.angle_cos * cone.angle_cos); + + float cone_sphere_center_cos = dot(sphere.center * sphere_distance_rcp, cone.direction); + /* cos(A+B) = cos(A) * cos(B) - sin(A) * sin(B). */ + float cone_sphere_angle_sum_cos = (sphere.radius > sphere_distance) ? + -1.0 : + (cone.angle_cos * sphere_cos - + cone_aperture_sin * sphere_sin); + /* Comparing cosines instead of angles since we are interested + * only in the monotonic region [0 .. M_PI / 2]. This saves costly acos() calls. */ + bool intersects = (cone_sphere_center_cos >= cone_sphere_angle_sum_cos); + + return intersects; +} + +bool intersect(Circle circle_a, Circle circle_b) +{ + return distance_squared(circle_a.center, circle_b.center) < + sqr(circle_a.radius + circle_b.radius); +} + +/** \} */ 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 cb2da9d35bf..71460c39285 100644 --- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl @@ -5,6 +5,18 @@ /** \name Math intersection & projection functions. * \{ */ +vec4 plane_from_quad(vec3 v0, vec3 v1, vec3 v2, vec3 v3) +{ + vec3 nor = normalize(cross(v2 - v1, v0 - v1) + cross(v0 - v3, v2 - v3)); + return vec4(nor, -dot(nor, v2)); +} + +vec4 plane_from_tri(vec3 v0, vec3 v1, vec3 v2) +{ + vec3 nor = normalize(cross(v2 - v1, v0 - v1)); + return vec4(nor, -dot(nor, v2)); +} + float point_plane_projection_dist(vec3 line_origin, vec3 plane_origin, vec3 plane_normal) { return dot(plane_normal, plane_origin - line_origin); diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index e081a0243ca..e3734939b3f 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -130,12 +130,17 @@ void set_flag_from_test(inout int value, bool test, int flag) { if (test) { valu #define in_texture_range(texel, tex) \ (all(greaterThanEqual(texel, ivec2(0))) && all(lessThan(texel, textureSize(tex, 0).xy))) -uint divide_ceil_u(uint visible_count, uint divisor) +uint divide_ceil(uint visible_count, uint divisor) { return (visible_count + (divisor - 1u)) / divisor; } -int divide_ceil_i(int visible_count, int divisor) +int divide_ceil(int visible_count, int divisor) +{ + return (visible_count + (divisor - 1)) / divisor; +} + +ivec2 divide_ceil(ivec2 visible_count, ivec2 divisor) { return (visible_count + (divisor - 1)) / divisor; } diff --git a/source/blender/draw/intern/shaders/common_shape_lib.glsl b/source/blender/draw/intern/shaders/common_shape_lib.glsl new file mode 100644 index 00000000000..f2c8bf0faaf --- /dev/null +++ b/source/blender/draw/intern/shaders/common_shape_lib.glsl @@ -0,0 +1,202 @@ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) + +/** + * Geometric shape structures. + * Some constructors might seems redundant but are here to make the API cleaner and + * allow for more than one constructor per type. + */ + +/* ---------------------------------------------------------------------- */ +/** \name Circle + * \{ */ + +struct Circle { + vec2 center; + float radius; +}; + +Circle shape_circle(vec2 center, float radius) +{ + return Circle(center, radius); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Sphere + * \{ */ + +struct Sphere { + vec3 center; + float radius; +}; + +Sphere shape_sphere(vec3 center, float radius) +{ + return Sphere(center, radius); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Box + * \{ */ + +struct Box { + vec3 corners[8]; +}; + +/* Construct box from 4 basis points. */ +Box shape_box(vec3 v000, vec3 v100, vec3 v010, vec3 v001) +{ + v100 -= v000; + v010 -= v000; + v001 -= v000; + Box box; + box.corners[0] = v000; + box.corners[1] = v000 + v100; + box.corners[2] = v000 + v010 + v100; + box.corners[3] = v000 + v010; + box.corners[4] = box.corners[0] + v001; + box.corners[5] = box.corners[1] + v001; + box.corners[6] = box.corners[2] + v001; + box.corners[7] = box.corners[3] + v001; + return box; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Square Pyramid + * \{ */ + +struct Pyramid { + /* Apex is the first. Base vertices are in clockwise order from front view. */ + vec3 corners[5]; +}; + +/** + * Regular Square Pyramid (can be oblique). + * Use this corner order. + * (Top-Down View of the pyramid) + * <pre> + * + * Y + * | + * | + * .-----X + * + * 4-----------3 + * | \ / | + * | \ / | + * | 0 | + * | / \ | + * | / \ | + * 1-----------2 + * </pre> + * base_corner_00 is vertex 1 + * base_corner_01 is vertex 2 + * base_corner_10 is vertex 4 + */ +Pyramid shape_pyramid(vec3 apex, vec3 base_corner_00, vec3 base_corner_01, vec3 base_corner_10) +{ + Pyramid pyramid; + pyramid.corners[0] = apex; + pyramid.corners[1] = base_corner_00; + pyramid.corners[2] = base_corner_01; + pyramid.corners[3] = base_corner_10 + (base_corner_01 - base_corner_00); + pyramid.corners[4] = base_corner_10; + return pyramid; +} + +/** + * Regular Square Pyramid. + * <pre> + * + * Y + * | + * | + * .-----X + * + * 4-----Y-----3 + * | \ | / | + * | \ | / | + * | 0-----X + * | / \ | + * | / \ | + * 1-----------2 + * </pre> + * base_center_pos_x is vector from base center to X + * base_center_pos_y is vector from base center to Y + */ +Pyramid shape_pyramid_non_oblique(vec3 apex, + vec3 base_center, + vec3 base_center_pos_x, + vec3 base_center_pos_y) +{ + Pyramid pyramid; + pyramid.corners[0] = apex; + pyramid.corners[1] = base_center - base_center_pos_x - base_center_pos_y; + pyramid.corners[2] = base_center + base_center_pos_x - base_center_pos_y; + pyramid.corners[3] = base_center + base_center_pos_x + base_center_pos_y; + pyramid.corners[4] = base_center - base_center_pos_x + base_center_pos_y; + return pyramid; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Frustum + * \{ */ + +struct Frustum { + vec3 corners[8]; +}; + +/** + * Use this corner order. + * <pre> + * + * Z Y + * | / + * |/ + * .-----X + * 2----------6 + * /| /| + * / | / | + * 1----------5 | + * | | | | + * | 3-------|--7 + * | / | / + * |/ |/ + * 0----------4 + * </pre> + */ +Frustum shape_frustum(vec3 corners[8]) +{ + Frustum frustum; + for (int i = 0; i < 8; i++) { + frustum.corners[i] = corners[i]; + } + return frustum; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Cone + * \{ */ + +/* Cone at orign with no height. */ +struct Cone { + vec3 direction; + float angle_cos; +}; + +Cone shape_cone(vec3 direction, float angle_cosine) +{ + return Cone(direction, angle_cosine); +} + +/** \} */ diff --git a/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl b/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl index 92c546aa203..ab76df819d5 100644 --- a/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl +++ b/source/blender/draw/intern/shaders/draw_debug_draw_display_vert.glsl @@ -8,7 +8,7 @@ void main() /* Skip the first vertex containing header data. */ DRWDebugVert vert = drw_debug_verts_buf[gl_VertexID + 1]; vec3 pos = uintBitsToFloat(uvec3(vert.pos0, vert.pos1, vert.pos2)); - vec4 col = vec4((uvec4(vert.color) >> uvec4(0, 8, 16, 24)) & 0xFFu); + vec4 col = vec4((uvec4(vert.color) >> uvec4(0, 8, 16, 24)) & 0xFFu) / 255.0; interp.color = col; gl_Position = persmat * vec4(pos, 1.0); diff --git a/source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl b/source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl index fe608816109..4e0d980637f 100644 --- a/source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl +++ b/source/blender/draw/intern/shaders/draw_debug_print_display_frag.glsl @@ -130,4 +130,4 @@ void main() /* Transparent Background for ease of read. */ out_color = vec4(0, 0, 0, 0.2); } -}
\ No newline at end of file +} diff --git a/source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl b/source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl index c8fc3815436..f67e9d3f9e0 100644 --- a/source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl +++ b/source/blender/draw/intern/shaders/draw_debug_print_display_vert.glsl @@ -26,4 +26,4 @@ void main() gl_Position = vec4( pos_on_screen * drw_view.viewport_size_inverse * vec2(2.0, -2.0) - vec2(1.0, -1.0), 0, 1); gl_PointSize = char_size; -}
\ No newline at end of file +} diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index 6adfab6e921..a72b2874f95 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -12,7 +12,6 @@ set(INC ../../sequencer ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index d9eeed94868..8c5662be2be 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -3406,9 +3406,8 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data) GSet *gs; size_t items = 0; - /* build new hashtable to efficiently store and retrieve which entries have been - * encountered already while searching - */ + /* Build new hash-table to efficiently store and retrieve which entries have been + * encountered already while searching. */ gs = BLI_gset_ptr_new(__func__); /* loop through items, removing them from the list if a similar item occurs already */ diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 12f83343299..acf53541843 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1081,10 +1081,7 @@ static float *visualkey_get_values( } if (strstr(identifier, "rotation_quaternion")) { - float mat3[3][3]; - - copy_m3_m4(mat3, tmat); - mat3_to_quat_is_ok(buffer, mat3); + mat4_to_quat(buffer, tmat); *r_count = 4; return buffer; diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 3ce5b70918d..243b2950e2e 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -14,7 +14,6 @@ set(INC ../../windowmanager ../../../../intern/clog ../../../../intern/eigen - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index ae15bc39ec8..479a2245b30 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -339,12 +339,7 @@ static void *ed_armature_pick_bone_impl( Base **bases; if (vc.obedit != NULL) { - bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer, - vc.v3d, - &bases_len, - { - .object_mode = OB_MODE_EDIT, - }); + bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); } else { bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len); diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt index 791e28de694..0cedc05981b 100644 --- a/source/blender/editors/curve/CMakeLists.txt +++ b/source/blender/editors/curve/CMakeLists.txt @@ -11,7 +11,6 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../../../extern/curve_fit_nd # RNA_prototypes.h diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt index 0484c47f081..84181b5f95d 100644 --- a/source/blender/editors/gizmo_library/CMakeLists.txt +++ b/source/blender/editors/gizmo_library/CMakeLists.txt @@ -13,7 +13,6 @@ set(INC ../../windowmanager ../../../../intern/clog ../../../../intern/eigen - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 9cb9e7ca1af..866df16f3d6 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -12,7 +12,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../bmesh # RNA_prototypes.h diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index ce38c261c1f..00066d5f2b8 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -823,6 +823,8 @@ static const ColorTemplate gp_monkey_pct_pupils = { void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4]) { + /* Original model created by Matias Mendiola. */ + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index 4687f9188fd..8522c81cb39 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -192,6 +192,8 @@ static const ColorTemplate gp_stroke_material_grey = { void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4]) { + /* Original design created by Daniel M. Lara and Matias Mendiola. */ + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index c05ab8c6b28..537696a606e 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3960,6 +3960,269 @@ static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } +/* -------------------------------------------------------------------- */ +/** \name Stroke Perimeter from View Operator + * \{ */ + +enum { + GP_PERIMETER_VIEW = 0, + GP_PERIMETER_FRONT = 1, + GP_PERIMETER_SIDE = 2, + GP_PERIMETER_TOP = 3, + GP_PERIMETER_CAMERA = 4, +}; + +enum { + GP_STROKE_USE_ACTIVE_MATERIAL = 0, + GP_STROKE_USE_CURRENT_MATERIAL = 1, + GP_STROKE_USE_NEW_MATERIAL = 2, +}; + +static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = (bGPdata *)ob->data; + const int subdivisions = RNA_int_get(op->ptr, "subdivisions"); + const float length = RNA_float_get(op->ptr, "length"); + + const int view_mode = RNA_enum_get(op->ptr, "view_mode"); + const int mode = RNA_enum_get(op->ptr, "mode"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + + /* sanity checks */ + if (ELEM(NULL, gpd)) { + return OPERATOR_CANCELLED; + } + + bool changed = false; + + float viewmat[4][4], viewinv[4][4]; + copy_m4_m4(viewmat, rv3d->viewmat); + copy_m4_m4(viewinv, rv3d->viewinv); + + switch (view_mode) { + case GP_PERIMETER_FRONT: + unit_m4(rv3d->viewmat); + rv3d->viewmat[1][1] = 0.0f; + rv3d->viewmat[1][2] = -1.0f; + + rv3d->viewmat[2][1] = 1.0f; + rv3d->viewmat[2][2] = 0.0f; + + rv3d->viewmat[3][2] = -10.0f; + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + break; + case GP_PERIMETER_SIDE: + zero_m4(rv3d->viewmat); + rv3d->viewmat[0][2] = 1.0f; + rv3d->viewmat[1][0] = 1.0f; + rv3d->viewmat[2][1] = 1.0f; + rv3d->viewmat[3][3] = 1.0f; + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + break; + case GP_PERIMETER_TOP: + unit_m4(rv3d->viewmat); + unit_m4(rv3d->viewinv); + break; + case GP_PERIMETER_CAMERA: { + Scene *scene = CTX_data_scene(C); + Object *cam_ob = scene->camera; + if (cam_ob != NULL) { + invert_m4_m4(rv3d->viewmat, cam_ob->obmat); + copy_m4_m4(rv3d->viewinv, cam_ob->obmat); + } + break; + } + default: + break; + } + + /* Untag strokes to be sure nothing is pending. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->flag &= ~GP_STROKE_TAG; + } + } + } + /* Create a new material. */ + int mat_idx = 0; + if (mode == GP_STROKE_USE_NEW_MATERIAL) { + Material *ma = BKE_gpencil_object_material_new(bmain, ob, "Material", NULL); + MaterialGPencilStyle *gp_style = ma->gp_style; + + gp_style->flag |= GP_MATERIAL_FILL_SHOW; + mat_idx = ob->totcol - 1; + } + + /* loop all selected strokes */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + /* Prepare transform matrix. */ + float diff_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); + + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + if ((gps->flag & GP_STROKE_SELECT) == 0) { + continue; + } + if (gps->totpoints == 0) { + continue; + } + if (!ED_gpencil_stroke_material_visible(ob, gps)) { + continue; + } + + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0); + + if (!is_stroke) { + continue; + } + + /* Duplicate the stroke to apply any layer thickness change. */ + bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false); + + /* Apply layer thickness change. */ + gps_duplicate->thickness += gpl->line_change; + /* Apply object scale to thickness. */ + gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + CLAMP_MIN(gps_duplicate->thickness, 1.0f); + + /* Stroke. */ + bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view( + rv3d, gpd, gpl, gps_duplicate, subdivisions, diff_mat); + gps_perimeter->flag &= ~GP_STROKE_SELECT; + /* Assign material. */ + switch (mode) { + case GP_STROKE_USE_ACTIVE_MATERIAL: { + if (ob->actcol - 1 < 0) { + gps_perimeter->mat_nr = 0; + } + else { + gps_perimeter->mat_nr = ob->actcol - 1; + } + break; + } + case GP_STROKE_USE_CURRENT_MATERIAL: + gps_perimeter->mat_nr = gps->mat_nr; + break; + case GP_STROKE_USE_NEW_MATERIAL: + gps_perimeter->mat_nr = mat_idx; + break; + default: + break; + } + + /* Sample stroke. */ + if (length > 0.0f) { + BKE_gpencil_stroke_sample(gpd, gps_perimeter, length, false, 0); + } + + /* Set pressure constant. */ + bGPDspoint *pt; + for (int i = 0; i < gps_perimeter->totpoints; i++) { + pt = &gps_perimeter->points[i]; + pt->pressure = 1.0f; + } + + /* Add perimeter stroke to frame. */ + BLI_insertlinkafter(&gpf->strokes, gps, gps_perimeter); + + /* Tag original stroke to be removed. */ + gps->flag |= GP_STROKE_TAG; + + /* Free Temp stroke. */ + BKE_gpencil_free_stroke(gps_duplicate); + changed = true; + } + + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; + } + } + } + } + /* Free old strokes. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_TAG) { + BLI_remlink(&gpf->strokes, gps); + BKE_gpencil_free_stroke(gps); + } + } + } + } + + /* Back to view matrix. */ + copy_m4_m4(rv3d->viewmat, viewmat); + copy_m4_m4(rv3d->viewinv, viewinv); + + if (changed) { + /* notifiers */ + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_outline(wmOperatorType *ot) +{ + static const EnumPropertyItem view_mode[] = { + {GP_PERIMETER_VIEW, "VIEW", 0, "View", ""}, + {GP_PERIMETER_FRONT, "FRONT", 0, "Front", ""}, + {GP_PERIMETER_SIDE, "SIDE", 0, "Side", ""}, + {GP_PERIMETER_TOP, "TOP", 0, "Top", ""}, + {GP_PERIMETER_CAMERA, "CAMERA", 0, "Camera", ""}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem material_mode[] = { + {GP_STROKE_USE_ACTIVE_MATERIAL, "ACTIVE", 0, "Active Material", ""}, + {GP_STROKE_USE_CURRENT_MATERIAL, "KEEP", 0, "Keep Material", "Keep current stroke material"}, + {GP_STROKE_USE_NEW_MATERIAL, "NEW", 0, "New Material", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Convert Stroke to Outline"; + ot->idname = "GPENCIL_OT_stroke_outline"; + ot->description = "Convert stroke to perimeter"; + + /* api callbacks */ + ot->exec = gpencil_stroke_outline_exec; + ot->poll = gpencil_stroke_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "view_mode", view_mode, GP_PERIMETER_VIEW, "View", ""); + RNA_def_enum( + ot->srna, "mode", material_mode, GP_STROKE_USE_ACTIVE_MATERIAL, "Material Mode", ""); + + RNA_def_int(ot->srna, "subdivisions", 3, 0, 10, "Subdivisions", "", 0, 10); + + RNA_def_float(ot->srna, "length", 0.0f, 0.0f, 100.0f, "Sample Length", "", 0.0f, 100.0f); +} + +/** \} */ + void GPENCIL_OT_recalc_geometry(wmOperatorType *ot) { /* identifiers */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index d656241c463..3cb3a50e702 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -608,6 +608,7 @@ void GPENCIL_OT_stroke_merge_by_distance(struct wmOperatorType *ot); void GPENCIL_OT_stroke_merge_material(struct wmOperatorType *ot); void GPENCIL_OT_stroke_reset_vertex_color(struct wmOperatorType *ot); void GPENCIL_OT_stroke_normalize(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_outline(struct wmOperatorType *ot); void GPENCIL_OT_material_to_vertex_color(struct wmOperatorType *ot); void GPENCIL_OT_extract_palette_vertex(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index e7a4f2fe2dc..bf6616638c4 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -1483,7 +1483,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) */ static const EnumPropertyItem gpencil_interpolation_type_items[] = { /* Interpolation. */ - RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Interpolation"), + N_("Standard transitions between keyframes")), {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, @@ -1496,9 +1497,9 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) "Custom interpolation defined using a curve map"}, /* Easing. */ - RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"), - "Predefined inertial transitions, useful for motion graphics " - "(from least to most \"dramatic\")"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Easing (by strength)"), + N_("Predefined inertial transitions, useful for motion graphics " + "(from least to most \"dramatic\")")), {GP_IPO_SINE, "SINE", ICON_IPO_SINE, @@ -1515,7 +1516,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) "Circular", "Circular easing (strongest and most dynamic)"}, - RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Dynamic Effects"), + N_("Simple physics-inspired easing effects")), {GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"}, {GP_IPO_BOUNCE, "BOUNCE", diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 99e28270c3e..3d92fbabfc4 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -635,6 +635,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_stroke_merge_material); WM_operatortype_append(GPENCIL_OT_stroke_reset_vertex_color); WM_operatortype_append(GPENCIL_OT_stroke_normalize); + WM_operatortype_append(GPENCIL_OT_stroke_outline); WM_operatortype_append(GPENCIL_OT_material_to_vertex_color); WM_operatortype_append(GPENCIL_OT_extract_palette_vertex); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 13ea5179b23..50651e1919a 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3658,9 +3658,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } } - /* Exit painting mode (and/or end current stroke). - * - */ + /* Exit painting mode (and/or end current stroke). */ if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, EVT_ESCKEY, EVT_SPACEKEY)) { p->status = GP_STATUS_DONE; diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 70f12151fdd..4a4fffc9638 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1024,8 +1024,10 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false); /* add small offset to keep stroke over the surface */ - if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) { - depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f)); + if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) { + if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) { + depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f)); + } } /* convert screen-coordinates to 3D coordinates */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index b6488d6da56..bf021d68cec 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -403,12 +403,11 @@ void ED_gpencil_stroke_init_data(struct bGPDstroke *gps, */ void ED_gpencil_create_blank(struct bContext *C, struct Object *ob, float mat[4][4]); /** - * Add a 2D Suzanne (original model created by Matias Mendiola). + * Add a 2D Suzanne. */ void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]); /** - * Add a Simple stroke with colors - * (original design created by Daniel M. Lara and Matias Mendiola). + * Add a Simple stroke with colors. */ void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]); /** diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 71ddffca8a9..b6a652bd3ab 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -141,11 +141,13 @@ struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, bool use_winding, bool do_islands); 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(const struct UvElementMap *map, + const struct BMFace *efa, + const struct BMLoop *l); struct UvElement *BM_uv_element_get_head(struct UvElementMap *map, struct UvElement *child); +struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *element_map); + /** * Can we edit UV's for this mesh? */ @@ -181,9 +183,13 @@ void EDBM_project_snap_verts(struct bContext *C, /* editmesh_automerge.c */ -void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist); -void EDBM_automerge_and_split( - struct Object *ob, bool split_edges, bool split_faces, bool update, char hflag, float dist); +void EDBM_automerge(struct Object *obedit, bool update, char hflag, float dist); +void EDBM_automerge_and_split(struct Object *obedit, + bool split_edges, + bool split_faces, + bool update, + char hflag, + float dist); /* editmesh_undo.c */ @@ -448,7 +454,7 @@ void ED_mesh_mirrtopo_init(struct BMEditMesh *em, bool skip_em_vert_array_init); void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store); -/* object_vgroup.c */ +/* object_vgroup.cc */ #define WEIGHT_REPLACE 1 #define WEIGHT_ADD 2 diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 550040d2bc6..1e220d33ff4 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -20,6 +20,7 @@ struct rcti; struct wmMsgSubscribeKey; struct wmMsgSubscribeValue; struct wmRegionMessageSubscribeParams; +struct wmOperator; /* sculpt.c */ @@ -33,7 +34,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, /* sculpt_transform.c */ void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob); -void ED_sculpt_init_transform(struct bContext *C, struct Object *ob); +void ED_sculpt_init_transform(struct bContext *C, struct Object *ob, const char *undo_name); void ED_sculpt_end_transform(struct bContext *C, struct Object *ob); /* sculpt_undo.c */ @@ -41,7 +42,13 @@ void ED_sculpt_end_transform(struct bContext *C, struct Object *ob); /** Export for ED_undo_sys. */ void ED_sculpt_undosys_type(struct UndoType *ut); -void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name); +/** + * Pushes an undo step using the operator name. This is necessary for + * redo panels to work; operators that do not support that may use + * #ED_sculpt_undo_geometry_begin_ex instead if so desired. + */ +void ED_sculpt_undo_geometry_begin(struct Object *ob, const struct wmOperator *op); +void ED_sculpt_undo_geometry_begin_ex(struct Object *ob, const char *name); void ED_sculpt_undo_geometry_end(struct Object *ob); /* Face sets. */ diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 24d6819536d..38e542fc0ca 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -107,7 +107,7 @@ bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_l * Changes selection state of a single UV Face. */ void uvedit_face_select_set(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *em, struct BMFace *efa, bool select, bool do_history, @@ -118,7 +118,7 @@ void uvedit_face_select_set(const struct Scene *scene, * Changes selection state of a single UV Edge. */ void uvedit_edge_select_set(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *em, struct BMLoop *l, bool select, bool do_history, @@ -129,7 +129,7 @@ void uvedit_edge_select_set(const struct Scene *scene, * Changes selection state of a single UV vertex. */ void uvedit_uv_select_set(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *em, struct BMLoop *l, bool select, bool do_history, @@ -139,30 +139,30 @@ void uvedit_uv_select_set(const struct Scene *scene, * use. */ void uvedit_face_select_enable(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *bm, struct BMFace *efa, bool do_history, int cd_loop_uv_offset); void uvedit_face_select_disable(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *bm, struct BMFace *efa, int cd_loop_uv_offset); void uvedit_edge_select_enable(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *bm, struct BMLoop *l, bool do_history, int cd_loop_uv_offset); void uvedit_edge_select_disable(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *bm, struct BMLoop *l, int cd_loop_uv_offset); void uvedit_uv_select_enable(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *bm, struct BMLoop *l, bool do_history, int cd_loop_uv_offset); void uvedit_uv_select_disable(const struct Scene *scene, - struct BMEditMesh *em, + struct BMesh *bm, struct BMLoop *l, int cd_loop_uv_offset); @@ -179,13 +179,13 @@ void uvedit_edge_select_set_with_sticky(const struct Scene *scene, struct BMLoop *l, bool select, bool do_history, - uint cd_loop_uv_offset); + int cd_loop_uv_offset); void uvedit_uv_select_set_with_sticky(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, bool select, bool do_history, - uint cd_loop_uv_offset); + int cd_loop_uv_offset); /* Low level functions for sticky element selection (sticky mode independent). Type of sticky * selection is specified explicitly (using sticky_flag, except for face selection). */ @@ -315,7 +315,7 @@ struct FaceIsland { * \note While this is duplicate information, * it allows islands from multiple meshes to be stored in the same list. */ - uint cd_loop_uv_offset; + int cd_loop_uv_offset; float aspect_y; }; @@ -326,7 +326,7 @@ int bm_mesh_calc_uv_islands(const Scene *scene, const bool only_selected_uvs, const bool use_seams, const float aspect_y, - const uint cd_loop_uv_offset); + const int cd_loop_uv_offset); struct UVMapUDIM_Params { const struct Image *image; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index bb95ea97c1c..c72f3121217 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -711,7 +711,7 @@ bool ED_view3d_win_to_segment_clipped(const struct Depsgraph *depsgraph, float r_ray_start[3], float r_ray_end[3], bool do_clip_planes); -void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, +void ED_view3d_ob_project_mat_get(const struct RegionView3D *rv3d, const struct Object *ob, float r_pmat[4][4]); void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, @@ -950,7 +950,7 @@ int view3d_opengl_select_with_id_filter(struct ViewContext *vc, eV3DSelectObjectFilter select_filter, uint select_id); -/* view3d_select.c */ +/* view3d_select.cc */ float ED_view3d_select_dist_px(void); void ED_view3d_viewcontext_init(struct bContext *C, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index e4a973a375e..6a531c88762 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -19,7 +19,6 @@ set(INC ../../python ../../render ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../bmesh # RNA_prototypes.h diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 518fe65ee09..7ed9488950e 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -952,6 +952,12 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev uiItemS(layout); } + MenuType *mt_idtemplate_liboverride = WM_menutype_find("UI_MT_idtemplate_liboverride", true); + if (mt_idtemplate_liboverride && mt_idtemplate_liboverride->poll(C, mt_idtemplate_liboverride)) { + uiItemM_ptr(layout, mt_idtemplate_liboverride, IFACE_("Library Override"), ICON_NONE); + uiItemS(layout); + } + /* Pointer properties and string properties with * prop_search support jumping to target object/bone. */ if (but->rnapoin.data && but->rnaprop) { @@ -1224,7 +1230,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev } } - MenuType *mt = WM_menutype_find("WM_MT_button_context", true); + MenuType *mt = WM_menutype_find("UI_MT_button_context_menu", true); if (mt) { UI_menutype_draw(C, mt, uiLayoutColumn(layout, false)); } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index d75d86c2665..0c842084de6 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -25,6 +25,7 @@ struct CurveMapping; struct CurveProfile; struct ID; struct ImBuf; +struct Main; struct Scene; struct bContext; struct bContextStore; @@ -1543,6 +1544,12 @@ uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block( struct uiListType *UI_UL_cache_file_layers(void); +struct ID *ui_template_id_liboverride_hierarchy_make(struct bContext *C, + struct Main *bmain, + struct ID *owner_id, + struct ID *id, + const char **r_undo_push_label); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 3465373c85d..94d17ed3c88 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -3028,7 +3028,14 @@ void uiItemMContents(uiLayout *layout, const char *menuname) if (WM_menutype_poll(C, mt) == false) { return; } + + bContextStore *previous_ctx = CTX_store_get(C); UI_menutype_draw(C, mt, layout); + + /* Restore context that was cleared by `UI_menutype_draw`. */ + if (layout->context) { + CTX_store_set(C, previous_ctx); + } } void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index) diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index 2533a5454a5..dbedbe550ba 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -21,6 +21,7 @@ #include "BLF_api.h" #include "BLT_lang.h" +#include "BLT_translation.h" #include "BKE_context.h" #include "BKE_global.h" @@ -28,6 +29,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" +#include "BKE_lib_remap.h" #include "BKE_material.h" #include "BKE_node.h" #include "BKE_report.h" @@ -747,6 +749,284 @@ static void UI_OT_override_remove_button(wmOperatorType *ot) ot->srna, "all", true, "All", "Reset to default values all elements of the array"); } +static void override_idtemplate_ids_get( + bContext *C, ID **r_owner_id, ID **r_id, PointerRNA *r_owner_ptr, PropertyRNA **r_prop) +{ + PointerRNA owner_ptr; + PropertyRNA *prop; + UI_context_active_but_prop_get_templateID(C, &owner_ptr, &prop); + + if (owner_ptr.data == NULL || prop == NULL) { + *r_owner_id = *r_id = NULL; + if (r_owner_ptr != NULL) { + *r_owner_ptr = PointerRNA_NULL; + } + if (r_prop != NULL) { + *r_prop = NULL; + } + return; + } + + *r_owner_id = owner_ptr.owner_id; + PointerRNA idptr = RNA_property_pointer_get(&owner_ptr, prop); + *r_id = static_cast<ID *>(idptr.data); + if (r_owner_ptr != NULL) { + *r_owner_ptr = owner_ptr; + } + if (r_prop != NULL) { + *r_prop = prop; + } +} + +static bool override_idtemplate_poll(bContext *C, const bool is_create_op) +{ + ID *owner_id, *id; + override_idtemplate_ids_get(C, &owner_id, &id, NULL, NULL); + + if (owner_id == NULL || id == NULL) { + return false; + } + + if (is_create_op) { + if (!ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + return false; + } + return true; + } + + /* Reset/Clear operations. */ + if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + return false; + } + return true; +} + +static bool override_idtemplate_make_poll(bContext *C) +{ + return override_idtemplate_poll(C, true); +} + +static int override_idtemplate_make_exec(bContext *C, wmOperator *UNUSED(op)) +{ + ID *owner_id, *id; + PointerRNA owner_ptr; + PropertyRNA *prop; + override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop); + if (ELEM(NULL, owner_id, id)) { + return OPERATOR_CANCELLED; + } + + ID *id_override = ui_template_id_liboverride_hierarchy_make( + C, CTX_data_main(C), owner_id, id, NULL); + + if (id_override == NULL) { + return OPERATOR_CANCELLED; + } + + PointerRNA idptr; + /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it + * to ensure remapping of the owner property from the linked data to the newly created + * liboverride (note that in theory this remapping has already been done by code above), but + * only in case owner ID was already local ID (override or pure local data). + * + * Otherwise, owner ID will also have been overridden, and remapped already to use it's + * override of the data too. */ + if (!ID_IS_LINKED(owner_id)) { + RNA_id_pointer_create(id_override, &idptr); + RNA_property_pointer_set(&owner_ptr, prop, idptr, NULL); + } + RNA_property_update(C, &owner_ptr, prop); + + /* 'Security' extra tagging, since this process may also affect the owner ID and not only the + * used ID, relying on the property update code only is not always enough. */ + DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + return OPERATOR_FINISHED; +} + +static void UI_OT_override_idtemplate_make(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Make Library Override"; + ot->idname = "UI_OT_override_idtemplate_make"; + ot->description = + "Create a local override of the selected linked data-block, and its hierarchy of " + "dependencies"; + + /* callbacks */ + ot->poll = override_idtemplate_make_poll; + ot->exec = override_idtemplate_make_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + +static bool override_idtemplate_reset_poll(bContext *C) +{ + return override_idtemplate_poll(C, false); +} + +static int override_idtemplate_reset_exec(bContext *C, wmOperator *UNUSED(op)) +{ + ID *owner_id, *id; + PointerRNA owner_ptr; + PropertyRNA *prop; + override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop); + if (ELEM(NULL, owner_id, id)) { + return OPERATOR_CANCELLED; + } + + if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + return OPERATOR_CANCELLED; + } + + BKE_lib_override_library_id_reset(CTX_data_main(C), id, false); + + PointerRNA idptr; + /* `idptr` is re-assigned to owner property to ensure proper updates etc. */ + RNA_id_pointer_create(id, &idptr); + RNA_property_pointer_set(&owner_ptr, prop, idptr, NULL); + RNA_property_update(C, &owner_ptr, prop); + + /* No need for 'security' extra tagging here, since this process will never affect the owner ID. + */ + + return OPERATOR_FINISHED; +} + +static void UI_OT_override_idtemplate_reset(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Reset Library Override"; + ot->idname = "UI_OT_override_idtemplate_reset"; + ot->description = "Reset the selected local override to its linked reference values"; + + /* callbacks */ + ot->poll = override_idtemplate_reset_poll; + ot->exec = override_idtemplate_reset_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + +static bool override_idtemplate_clear_poll(bContext *C) +{ + return override_idtemplate_poll(C, false); +} + +static int override_idtemplate_clear_exec(bContext *C, wmOperator *UNUSED(op)) +{ + ID *owner_id, *id; + PointerRNA owner_ptr; + PropertyRNA *prop; + override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop); + if (ELEM(NULL, owner_id, id)) { + return OPERATOR_CANCELLED; + } + + if (ID_IS_LINKED(id)) { + return OPERATOR_CANCELLED; + } + + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + ID *id_new = id; + + if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) { + id_new = id->override_library->reference; + bool do_remap_active = false; + if (OBACT(view_layer) == (Object *)id) { + BLI_assert(GS(id->name) == ID_OB); + BLI_assert(GS(id_new->name) == ID_OB); + do_remap_active = true; + } + BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE); + if (do_remap_active) { + Object *ref_object = (Object *)id_new; + Base *basact = BKE_view_layer_base_find(view_layer, ref_object); + if (basact != NULL) { + view_layer->basact = basact; + } + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + } + BKE_id_delete(bmain, id); + } + else { + BKE_lib_override_library_id_reset(bmain, id, true); + } + + /* Here the affected ID may remain the same, or be replaced by its linked reference. In either + * case, the owner ID remains unchanged, and remapping is already handled by internal code, so + * calling `RNA_property_update` on it is enough to ensure proper notifiers are sent. */ + RNA_property_update(C, &owner_ptr, prop); + + /* 'Security' extra tagging, since this process may also affect the owner ID and not only the + * used ID, relying on the property update code only is not always enough. */ + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + return OPERATOR_FINISHED; +} + +static void UI_OT_override_idtemplate_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Library Override"; + ot->idname = "UI_OT_override_idtemplate_clear"; + ot->description = + "Delete the selected local override and relink its usages to the linked data-block if " + "possible, else reset it and mark it as non editable"; + + /* callbacks */ + ot->poll = override_idtemplate_clear_poll; + ot->exec = override_idtemplate_clear_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + +static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType *UNUSED(mt)) +{ + bContext *C = (bContext *)C_const; + ID *owner_id, *id; + override_idtemplate_ids_get(C, &owner_id, &id, NULL, NULL); + + if (owner_id == NULL || id == NULL) { + return false; + } + + if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY_REAL(id))) { + return false; + } + return true; +} + +static void override_idtemplate_menu_draw(const bContext *UNUSED(C), Menu *menu) +{ + uiLayout *layout = menu->layout; + uiItemO(layout, IFACE_("Make"), ICON_NONE, "UI_OT_override_idtemplate_make"); + uiItemO(layout, IFACE_("Reset"), ICON_NONE, "UI_OT_override_idtemplate_reset"); + uiItemO(layout, IFACE_("Clear"), ICON_NONE, "UI_OT_override_idtemplate_clear"); +} + +static void override_idtemplate_menu(void) +{ + MenuType *mt; + + mt = MEM_cnew<MenuType>(__func__); + strcpy(mt->idname, "UI_MT_idtemplate_liboverride"); + strcpy(mt->label, N_("Library Override")); + mt->poll = override_idtemplate_menu_poll; + mt->draw = override_idtemplate_menu_draw; + WM_menutype_add(mt); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -2232,8 +2512,6 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_reset_default_button); WM_operatortype_append(UI_OT_assign_default_button); WM_operatortype_append(UI_OT_unset_property_button); - WM_operatortype_append(UI_OT_override_type_set_button); - WM_operatortype_append(UI_OT_override_remove_button); WM_operatortype_append(UI_OT_copy_to_selected_button); WM_operatortype_append(UI_OT_jump_to_target_button); WM_operatortype_append(UI_OT_drop_color); @@ -2252,6 +2530,13 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_view_drop); WM_operatortype_append(UI_OT_view_item_rename); + WM_operatortype_append(UI_OT_override_type_set_button); + WM_operatortype_append(UI_OT_override_remove_button); + WM_operatortype_append(UI_OT_override_idtemplate_make); + WM_operatortype_append(UI_OT_override_idtemplate_reset); + WM_operatortype_append(UI_OT_override_idtemplate_clear); + override_idtemplate_menu(); + /* external */ WM_operatortype_append(UI_OT_eyedropper_color); WM_operatortype_append(UI_OT_eyedropper_colorramp); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 5813f1d090c..86857d784dc 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -571,8 +571,11 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem) /** \name ID Template * \{ */ -/* This is for browsing and editing the ID-blocks used */ +static void template_id_cb(bContext *C, void *arg_litem, void *arg_event); +/** + * This is for browsing and editing the ID-blocks used. + */ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop) @@ -582,7 +585,7 @@ void UI_context_active_but_prop_get_templateID(bContext *C, memset(r_ptr, 0, sizeof(*r_ptr)); *r_prop = NULL; - if (but && but->func_argN) { + if (but && (but->funcN == template_id_cb) && but->func_argN) { TemplateID *template_ui = but->func_argN; *r_ptr = template_ui->ptr; *r_prop = template_ui->prop; @@ -650,14 +653,13 @@ static void template_id_liboverride_hierarchy_collections_tag_recursive( } } -static void template_id_liboverride_hierarchy_create(bContext *C, - Main *bmain, - TemplateID *template_ui, - PointerRNA *idptr, - const char **r_undo_push_label) +ID *ui_template_id_liboverride_hierarchy_make( + bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label) { - ID *id = idptr->data; - ID *owner_id = template_ui->ptr.owner_id; + const char *undo_push_label; + if (r_undo_push_label == NULL) { + r_undo_push_label = &undo_push_label; + } /* If this is called on an already local override, 'toggle' between user-editable state, and * system override with reset. */ @@ -677,14 +679,15 @@ static void template_id_liboverride_hierarchy_create(bContext *C, WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL); WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); - return; + return id; } /* Attempt to perform a hierarchy override, based on contextual data available. * NOTE: do not attempt to perform such hierarchy override at all cost, if there is not enough * context, better to abort than create random overrides all over the place. */ if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id)) { - return; + RNA_warning("The data-block %s is not overridable", id->name); + return NULL; } Object *object_active = CTX_data_active_object(C); @@ -762,15 +765,8 @@ static void template_id_liboverride_hierarchy_create(bContext *C, if (object_active != NULL) { object_active->id.tag |= LIB_TAG_DOIT; } - BKE_lib_override_library_create(bmain, - scene, - view_layer, - NULL, - id, - &collection_active->id, - NULL, - &id_override, - U.experimental.use_override_new_fully_editable); + BKE_lib_override_library_create( + bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false); } else if (object_active != NULL && !ID_IS_LINKED(object_active) && &object_active->instance_collection->id == id) { @@ -783,7 +779,7 @@ static void template_id_liboverride_hierarchy_create(bContext *C, &object_active->id, &object_active->id, &id_override, - U.experimental.use_override_new_fully_editable); + false); } break; case ID_OB: @@ -793,15 +789,17 @@ static void template_id_liboverride_hierarchy_create(bContext *C, if (object_active != NULL) { object_active->id.tag |= LIB_TAG_DOIT; } - BKE_lib_override_library_create(bmain, - scene, - view_layer, - NULL, - id, - &collection_active->id, - NULL, - &id_override, - U.experimental.use_override_new_fully_editable); + BKE_lib_override_library_create( + bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false); + } + else { + if (object_active != NULL) { + object_active->id.tag |= LIB_TAG_DOIT; + } + BKE_lib_override_library_create( + bmain, scene, view_layer, NULL, id, NULL, NULL, &id_override, false); + BKE_scene_collections_object_remove(bmain, scene, (Object *)id, true); + WM_event_add_notifier(C, NC_ID | NA_REMOVED, NULL); } break; case ID_ME: @@ -816,7 +814,8 @@ static void template_id_liboverride_hierarchy_create(bContext *C, case ID_CV: case ID_PT: case ID_VO: - if (object_active != NULL && object_active->data == id) { + case ID_NT: /* Essentially geometry nodes from modifier currently. */ + if (object_active != NULL) { if (collection_active != NULL && BKE_collection_has_object_recursive(collection_active, object_active)) { template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, id, true); @@ -831,42 +830,74 @@ static void template_id_liboverride_hierarchy_create(bContext *C, &collection_active->id, NULL, &id_override, - U.experimental.use_override_new_fully_editable); + false); } else { object_active->id.tag |= LIB_TAG_DOIT; - BKE_lib_override_library_create(bmain, - scene, - view_layer, - NULL, - id, - &object_active->id, - NULL, - &id_override, - U.experimental.use_override_new_fully_editable); + BKE_lib_override_library_create( + bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override, false); } } break; case ID_MA: case ID_TE: case ID_IM: + RNA_warning("The type of data-block %s could not yet implemented", id->name); break; case ID_WO: + RNA_warning("The type of data-block %s could not yet implemented", id->name); break; case ID_PA: + RNA_warning("The type of data-block %s could not yet implemented", id->name); break; default: + RNA_warning("The type of data-block %s could not yet implemented", id->name); break; } if (id_override != NULL) { id_override->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED; *r_undo_push_label = "Make Library Override Hierarchy"; - /* Given `idptr` is re-assigned to owner property by caller to ensure proper updates etc. Here - * we also use it to ensure remapping of the owner property from the linked data to the newly - * created liboverride (note that in theory this remapping has already been done by code - * above). */ - RNA_id_pointer_create(id_override, idptr); + /* In theory we could rely on setting/updating the RNA ID pointer property (as done by calling + * code) to be enough. + * + * However, some rare ID pointers properties (like the 'active object in viewlayer' one used + * for the Object templateID in the Object properties) use notifiers that do not enforce a + * rebuild of outliner trees, leading to crashes. + * + * So for now, add some extra notifiers here. */ + WM_event_add_notifier(C, NC_ID | NA_ADDED, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + } + return id_override; +} + +static void template_id_liboverride_hierarchy_make(bContext *C, + Main *bmain, + TemplateID *template_ui, + PointerRNA *idptr, + const char **r_undo_push_label) +{ + ID *id = idptr->data; + ID *owner_id = template_ui->ptr.owner_id; + + ID *id_override = ui_template_id_liboverride_hierarchy_make( + C, bmain, owner_id, id, r_undo_push_label); + + if (id_override != NULL) { + /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it + * to ensure remapping of the owner property from the linked data to the newly created + * liboverride (note that in theory this remapping has already been done by code above), but + * only in case owner ID was already local ID (override or pure local data). + * + * Otherwise, owner ID will also have been overridden, and remapped already to use it's + * override of the data too. */ + if (!ID_IS_LINKED(owner_id)) { + RNA_id_pointer_create(id_override, idptr); + } + } + else { + RNA_warning("The data-block %s could not be overridden", id->name); } } @@ -919,8 +950,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) if (id) { Main *bmain = CTX_data_main(C); if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { - template_id_liboverride_hierarchy_create( - C, bmain, template_ui, &idptr, &undo_push_label); + template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label); } else { if (BKE_lib_id_make_local(bmain, id, 0)) { @@ -941,8 +971,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) if (id && ID_IS_OVERRIDE_LIBRARY(id)) { Main *bmain = CTX_data_main(C); if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { - template_id_liboverride_hierarchy_create( - C, bmain, template_ui, &idptr, &undo_push_label); + template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label); } else { BKE_lib_override_library_make_local(id); @@ -6458,13 +6487,13 @@ bool uiTemplateEventFromKeymapItem(struct uiLayout *layout, for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) { uiItemL(layout, "", icon_mod[j]); } - uiItemL(layout, TIP_(text), icon); + uiItemL(layout, CTX_TIP_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, text), icon); ok = true; } else if (text_fallback) { const char *event_text = WM_key_event_string(kmi->type, true); uiItemL(layout, event_text, ICON_NONE); - uiItemL(layout, TIP_(text), ICON_NONE); + uiItemL(layout, CTX_TIP_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, text), ICON_NONE); ok = true; } return ok; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 855e72788d2..94e9e98c685 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1524,11 +1524,6 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle, const size_t max_len, const char rpart_sep) { - /* Add some epsilon to OK width, avoids 'ellipsing' text that nearly fits! - * Better to have a small piece of the last char cut out, - * than two remaining chars replaced by an ellipsis... */ - okwidth += 1.0f + UI_DPI_FAC; - BLI_assert(str[0]); /* need to set this first */ @@ -1627,7 +1622,7 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle, strwidth = BLF_width(fstyle->uifont_id, str, max_len); } - BLI_assert(strwidth <= okwidth); + BLI_assert((strwidth <= okwidth) || (okwidth <= 0.0f)); return strwidth; } diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 0068586730f..a7e906b8109 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -651,16 +651,16 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) ED_object_mode_set(C, OB_MODE_OBJECT); } - bool ok = ABC_import(C, - filename, - scale, - is_sequence, - set_frame_range, - sequence_len, - offset, - validate_meshes, - always_add_cache_reader, - as_background_job); + struct AlembicImportParams params = {0}; + params.global_scale = scale; + params.sequence_len = sequence_len; + params.sequence_offset = offset; + params.is_sequence = is_sequence; + params.set_frame_range = set_frame_range; + params.validate_meshes = validate_meshes; + params.always_add_cache_reader = always_add_cache_reader; + + bool ok = ABC_import(C, filename, ¶ms, as_background_job); return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } diff --git a/source/blender/editors/mask/CMakeLists.txt b/source/blender/editors/mask/CMakeLists.txt index fdb0d13f364..593eeb6c69d 100644 --- a/source/blender/editors/mask/CMakeLists.txt +++ b/source/blender/editors/mask/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 28ac913a3e3..218564eaf30 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -17,7 +17,6 @@ set(INC ../../render ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 0d988b9551f..c55d96bac55 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -530,15 +530,13 @@ bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags) bke::AttributeAccessor attributes = bke::mesh_attributes(*me); const VArray<bool> hide_vert = attributes.lookup_or_default<bool>( ".hide_vert", ATTR_DOMAIN_POINT, false); - const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( - ".hide_poly", ATTR_DOMAIN_FACE, false); if (action == SEL_TOGGLE) { action = SEL_SELECT; for (int i = 0; i < me->totvert; i++) { MVert *mvert = &me->mvert[i]; - if (!hide_poly[i] && mvert->flag & SELECT) { + if (!hide_vert[i] && mvert->flag & SELECT) { action = SEL_DESELECT; break; } @@ -603,13 +601,13 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags) } bke::AttributeAccessor attributes = bke::mesh_attributes(*me); - const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( - ".hide_poly", ATTR_DOMAIN_FACE, false); + const VArray<bool> hide_vert = attributes.lookup_or_default<bool>( + ".hide_vert", ATTR_DOMAIN_POINT, false); for (int i = 0; i < me->totvert; i++) { MVert *mv = &me->mvert[i]; MDeformVert *dv = &me->dvert[i]; - if (!hide_poly[i]) { + if (!hide_vert[i]) { if (dv->dw == nullptr) { /* if null weight then not grouped */ mv->flag |= SELECT; diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index 7634ce6af9e..6a080e78086 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -486,7 +486,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op) Mesh *new_mesh = (Mesh *)BKE_id_copy(bmain, &mesh->id); if (ob->mode == OB_MODE_SCULPT) { - ED_sculpt_undo_geometry_begin(ob, "mask slice"); + ED_sculpt_undo_geometry_begin(ob, op); } BMesh *bm; diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index c931cb4948b..51c5c21ecf8 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -12,6 +12,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_deform.h" diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index e931dd02a9e..a6a6b095c31 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -593,10 +593,10 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v) return vmap->vert[v]; } -static void bm_uv_ensure_head_table(UvElementMap *element_map) +struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *element_map) { if (element_map->head_table) { - return; + return element_map->head_table; } /* For each UvElement, locate the "separate" UvElement that precedes it in the linked list. */ @@ -616,6 +616,7 @@ static void bm_uv_ensure_head_table(UvElementMap *element_map) } } } + return element_map->head_table; } #define INVALID_ISLAND ((unsigned int)-1) @@ -643,9 +644,9 @@ static int bm_uv_edge_select_build_islands(UvElementMap *element_map, UvElement *islandbuf, uint *map, bool uv_selected, - int cd_loop_uv_offset) + const int cd_loop_uv_offset) { - bm_uv_ensure_head_table(element_map); + BM_uv_element_map_ensure_head_table(element_map); int total_uvs = element_map->total_uvs; @@ -1070,7 +1071,7 @@ void BM_uv_element_map_free(UvElementMap *element_map) } } -UvElement *BM_uv_element_get(UvElementMap *element_map, BMFace *efa, BMLoop *l) +UvElement *BM_uv_element_get(const UvElementMap *element_map, const BMFace *efa, const BMLoop *l) { UvElement *element = element_map->vertex[BM_elem_index_get(l->v)]; while (element) { diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index b5240eac53e..97671ee5513 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -208,7 +208,7 @@ void ED_mesh_uv_loop_reset_ex(Mesh *me, const int layernum) BMFace *efa; BMIter iter; - BLI_assert(cd_loop_uv_offset != -1); + BLI_assert(cd_loop_uv_offset >= 0); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index a2f993c92b9..17365cc5488 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -21,7 +21,6 @@ set(INC ../../shader_fx ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc # dna_type_offsets.h in BLO_read_write.h @@ -53,7 +52,7 @@ set(SRC object_shapekey.c object_transform.cc object_utils.c - object_vgroup.c + object_vgroup.cc object_volume.c object_warp.c diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index acd7a8e3c13..7aa340408e1 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -657,8 +657,7 @@ Object *ED_object_add_type_with_obdata(bContext *C, WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); ED_outliner_select_sync_from_object_tag(C); @@ -2771,25 +2770,6 @@ static const EnumPropertyItem convert_target_items[] = { {0, nullptr, 0, nullptr, nullptr}, }; -static void object_data_convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - if (ob->runtime.curve_cache == nullptr) { - /* Force creation. This is normally not needed but on operator - * redo we might end up with an object which isn't evaluated yet. - * Also happens in case we are working on a copy of the object - * (all its caches have been nuked then). - */ - if (ELEM(ob->type, OB_SURF, OB_CURVES_LEGACY, OB_FONT)) { - /* We need 'for render' ON here, to enable computing bevel #DispList if needed. - * Also makes sense anyway, we would not want e.g. to lose hidden parts etc. */ - BKE_displist_make_curveTypes(depsgraph, scene, ob, true); - } - else if (ob->type == OB_MBALL) { - BKE_displist_make_mball(depsgraph, scene, ob); - } - } -} - static void object_data_convert_curve_to_mesh(Main *bmain, Depsgraph *depsgraph, Object *ob) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); @@ -2908,7 +2888,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) const bool use_faces = RNA_boolean_get(op->ptr, "faces"); const float offset = RNA_float_get(op->ptr, "offset"); - int a, mballConverted = 0; + int mballConverted = 0; bool gpencilConverted = false; bool gpencilCurveConverted = false; @@ -3256,7 +3236,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) /* No assumption should be made that the resulting objects is a mesh, as conversion can * fail. */ object_data_convert_curve_to_mesh(bmain, depsgraph, newob); - /* meshes doesn't use displist */ + /* Meshes doesn't use the "curve cache". */ BKE_object_free_curve_cache(newob); } else if (target == OB_GPENCIL) { @@ -3291,7 +3271,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) /* No assumption should be made that the resulting objects is a mesh, as conversion can * fail. */ object_data_convert_curve_to_mesh(bmain, depsgraph, newob); - /* meshes doesn't use displist */ + /* Meshes don't use the "curve cache". */ BKE_object_free_curve_cache(newob); } else if (target == OB_GPENCIL) { @@ -3332,21 +3312,13 @@ static int object_convert_exec(bContext *C, wmOperator *op) MetaBall *mb = static_cast<MetaBall *>(newob->data); id_us_min(&mb->id); - newob->data = BKE_mesh_add(bmain, "Mesh"); - newob->type = OB_MESH; - - Mesh *me = static_cast<Mesh *>(newob->data); - me->totcol = mb->totcol; - if (newob->totcol) { - me->mat = static_cast<Material **>(MEM_dupallocN(mb->mat)); - for (a = 0; a < newob->totcol; a++) { - id_us_plus((ID *)me->mat[a]); - } - } + /* Find the evaluated mesh of the basis metaball object. */ + Object *object_eval = DEG_get_evaluated_object(depsgraph, baseob); + Mesh *mesh = BKE_mesh_new_from_object_to_bmain(bmain, depsgraph, object_eval, true); - object_data_convert_ensure_curve_cache(depsgraph, scene, baseob); - BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp, - static_cast<Mesh *>(newob->data)); + id_us_plus(&mesh->id); + newob->data = mesh; + newob->type = OB_MESH; if (obact->type == OB_MBALL) { basact = basen; diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 4837b538bf6..78b059d5514 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -45,7 +45,7 @@ * Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */ /* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */ static const EnumPropertyItem DT_layer_items[] = { - RNA_ENUM_ITEM_HEADING("Vertex Data", NULL), + RNA_ENUM_ITEM_HEADING(N_("Vertex Data"), NULL), {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, @@ -61,7 +61,7 @@ static const EnumPropertyItem DT_layer_items[] = { #endif {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"}, - RNA_ENUM_ITEM_HEADING("Edge Data", NULL), + RNA_ENUM_ITEM_HEADING(N_("Edge Data"), NULL), {DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"}, {DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"}, {DT_TYPE_CREASE, "CREASE", 0, "Subdivision Crease", "Transfer crease values"}, @@ -72,12 +72,12 @@ static const EnumPropertyItem DT_layer_items[] = { "Freestyle Mark", "Transfer Freestyle edge mark"}, - RNA_ENUM_ITEM_HEADING("Face Corner Data", NULL), + RNA_ENUM_ITEM_HEADING(N_("Face Corner Data"), NULL), {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"}, {DT_TYPE_MPROPCOL_LOOP | DT_TYPE_MLOOPCOL_LOOP, "VCOL", 0, "Colors", "Color Attributes"}, {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, - RNA_ENUM_ITEM_HEADING("Face Data", NULL), + RNA_ENUM_ITEM_HEADING(N_("Face Data"), NULL), {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"}, {DT_TYPE_FREESTYLE_FACE, "FREESTYLE_FACE", diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 4896ddb5258..f36181ad96d 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -194,13 +194,13 @@ Object **ED_object_array_in_mode_or_selected(bContext *C, /* When in a mode that supports multiple active objects, use "objects in mode" * instead of the object's selection. */ if (use_objects_in_mode) { - objects = BKE_view_layer_array_from_objects_in_mode(view_layer, - v3d, - r_objects_len, - {.object_mode = ob_active->mode, - .no_dup_data = true, - .filter_fn = filter_fn, - .filter_userdata = filter_user_data}); + struct ObjectsInModeParams params = {0}; + params.object_mode = ob_active->mode; + params.no_dup_data = true; + params.filter_fn = filter_fn; + params.filter_userdata = filter_user_data; + objects = BKE_view_layer_array_from_objects_in_mode_params( + view_layer, v3d, r_objects_len, ¶ms); } else { objects = BKE_view_layer_array_selected_objects( diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index b5862d4d957..63f010cd526 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -49,10 +49,14 @@ void OBJECT_OT_vertex_parent_set(struct wmOperatorType *ot); void OBJECT_OT_track_set(struct wmOperatorType *ot); void OBJECT_OT_track_clear(struct wmOperatorType *ot); void OBJECT_OT_make_local(struct wmOperatorType *ot); -void OBJECT_OT_make_override_library(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); + +void OBJECT_OT_make_override_library(struct wmOperatorType *ot); +void OBJECT_OT_reset_override_library(struct wmOperatorType *ot); +void OBJECT_OT_clear_override_library(struct wmOperatorType *ot); + /** * Used for drop-box. * Assigns to object under cursor, only first material slot. @@ -259,7 +263,7 @@ void CONSTRAINT_OT_objectsolver_set_inverse(struct wmOperatorType *ot); void CONSTRAINT_OT_objectsolver_clear_inverse(struct wmOperatorType *ot); void CONSTRAINT_OT_followpath_path_animate(struct wmOperatorType *ot); -/* object_vgroup.c */ +/* object_vgroup.cc */ void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_remove(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index e7cfcf48fd3..75f9fdd485e 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -50,6 +50,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_mball.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" @@ -111,7 +112,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object * BKE_lattice_modifiers_calc(depsgraph, scene_eval, ob_eval); } else if (ob->type == OB_MBALL) { - BKE_displist_make_mball(depsgraph, scene_eval, ob_eval); + BKE_mball_data_update(depsgraph, scene_eval, ob_eval); } else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false); @@ -486,6 +487,9 @@ bool ED_object_modifier_move_to_index(ReportList *reports, } } + /* NOTE: Dependency graph only uses modifier nodes for visibility updates, and exact order of + * modifier nodes in the graph does not matter. */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob); @@ -1668,6 +1672,7 @@ static int modifier_copy_exec(bContext *C, wmOperator *op) } DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 8a0d380ff2f..24a4556b075 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -58,11 +58,14 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_track_set); WM_operatortype_append(OBJECT_OT_track_clear); WM_operatortype_append(OBJECT_OT_make_local); - WM_operatortype_append(OBJECT_OT_make_override_library); WM_operatortype_append(OBJECT_OT_make_single_user); WM_operatortype_append(OBJECT_OT_make_links_scene); WM_operatortype_append(OBJECT_OT_make_links_data); + WM_operatortype_append(OBJECT_OT_make_override_library); + WM_operatortype_append(OBJECT_OT_reset_override_library); + WM_operatortype_append(OBJECT_OT_clear_override_library); + WM_operatortype_append(OBJECT_OT_select_random); WM_operatortype_append(OBJECT_OT_select_all); WM_operatortype_append(OBJECT_OT_select_same_collection); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index f136d3302df..8f563fa388a 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2280,12 +2280,6 @@ static int make_override_library_exec(bContext *C, wmOperator *op) ID *id_root = NULL; bool is_override_instancing_object = false; - const bool do_fully_editable = U.experimental.use_override_new_fully_editable; - - GSet *user_overrides_objects_uids = do_fully_editable ? NULL : - BLI_gset_new(BLI_ghashutil_inthash_p, - BLI_ghashutil_intcmp, - __func__); bool user_overrides_from_selected_objects = false; if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && @@ -2325,6 +2319,21 @@ static int make_override_library_exec(bContext *C, wmOperator *op) user_overrides_from_selected_objects = true; } + const bool do_fully_editable = !user_overrides_from_selected_objects; + + GSet *user_overrides_objects_uids = do_fully_editable ? NULL : + BLI_gset_new(BLI_ghashutil_inthash_p, + BLI_ghashutil_intcmp, + __func__); + + /* Make already existing selected liboverrides editable. */ + FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(ob_iter) && !ID_IS_LINKED(ob_iter)) { + ob_iter->id.override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED; + } + } + FOREACH_SELECTED_OBJECT_END; + if (do_fully_editable) { /* Pass. */ } @@ -2411,6 +2420,8 @@ static int make_override_library_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } @@ -2435,6 +2446,9 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve } if (!ID_IS_LINKED(obact)) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(obact)) { + return make_override_library_exec(C, op); + } BKE_report(op->reports, RPT_ERROR, "Cannot make library override from a local object"); return OPERATOR_CANCELLED; } @@ -2473,17 +2487,20 @@ static bool make_override_library_poll(bContext *C) Object *obact = CTX_data_active_object(C); /* Object must be directly linked to be overridable. */ - return (ED_operator_objectmode(C) && obact != NULL && - (ID_IS_LINKED(obact) || (obact->instance_collection != NULL && - ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) && - !ID_IS_OVERRIDE_LIBRARY(obact)))); + return ( + ED_operator_objectmode(C) && obact != NULL && + (ID_IS_LINKED(obact) || ID_IS_OVERRIDE_LIBRARY(obact) || + (obact->instance_collection != NULL && + ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) && !ID_IS_OVERRIDE_LIBRARY(obact)))); } void OBJECT_OT_make_override_library(wmOperatorType *ot) { /* identifiers */ ot->name = "Make Library Override"; - ot->description = "Make a local override of this library linked data-block"; + ot->description = + "Create a local override of the selected linked objects, and their hierarchy of " + "dependencies"; ot->idname = "OBJECT_OT_make_override_library"; /* api callbacks */ @@ -2513,6 +2530,129 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot) /** \} */ /* ------------------------------------------------------------------- */ +/** \name Reset Library Override Operator + * \{ */ + +static bool reset_clear_override_library_poll(bContext *C) +{ + Object *obact = CTX_data_active_object(C); + + /* Object must be local and an override. */ + return (ED_operator_objectmode(C) && obact != NULL && !ID_IS_LINKED(obact) && + ID_IS_OVERRIDE_LIBRARY(obact)); +} + +static int reset_override_library_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + + /* Make already existing selected liboverrides editable. */ + FOREACH_SELECTED_OBJECT_BEGIN (CTX_data_view_layer(C), CTX_wm_view3d(C), ob_iter) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(ob_iter) && !ID_IS_LINKED(ob_iter)) { + BKE_lib_override_library_id_reset(bmain, &ob_iter->id, false); + } + } + FOREACH_SELECTED_OBJECT_END; + + WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_reset_override_library(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Reset Library Override"; + ot->description = "Reset the selected local overrides to their linked references values"; + ot->idname = "OBJECT_OT_reset_override_library"; + + /* api callbacks */ + ot->exec = reset_override_library_exec; + ot->poll = reset_clear_override_library_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* ------------------------------------------------------------------- */ +/** \name Clear Library Override Operator + * \{ */ + +static int clear_override_library_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + LinkNode *todo_objects = NULL, *todo_object_iter; + + /* Make already existing selected liboverrides editable. */ + FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) { + if (ID_IS_LINKED(ob_iter)) { + continue; + } + BLI_linklist_prepend_alloca(&todo_objects, ob_iter); + } + FOREACH_SELECTED_OBJECT_END; + + for (todo_object_iter = todo_objects; todo_object_iter != NULL; + todo_object_iter = todo_object_iter->next) { + Object *ob_iter = todo_object_iter->link; + if (BKE_lib_override_library_is_hierarchy_leaf(bmain, &ob_iter->id)) { + bool do_remap_active = false; + if (OBACT(view_layer) == ob_iter) { + do_remap_active = true; + } + BKE_libblock_remap(bmain, + &ob_iter->id, + ob_iter->id.override_library->reference, + ID_REMAP_SKIP_INDIRECT_USAGE); + if (do_remap_active) { + Object *ref_object = (Object *)ob_iter->id.override_library->reference; + Base *basact = BKE_view_layer_base_find(view_layer, ref_object); + if (basact != NULL) { + view_layer->basact = basact; + } + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + } + BKE_id_delete(bmain, &ob_iter->id); + } + else { + BKE_lib_override_library_id_reset(bmain, &ob_iter->id, true); + } + } + + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_clear_override_library(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Library Override"; + ot->description = + "Delete the selected local overrides and relink their usages to the linked data-blocks if " + "possible, else reset them and mark them as non editable"; + ot->idname = "OBJECT_OT_clear_override_library"; + + /* api callbacks */ + ot->exec = clear_override_library_exec; + ot->poll = reset_clear_override_library_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* ------------------------------------------------------------------- */ /** \name Make Single User Operator * \{ */ diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index ac4fb40d832..812d9bbbc08 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -144,7 +144,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) } if (ob->mode == OB_MODE_SCULPT) { - ED_sculpt_undo_geometry_begin(ob, op->type->name); + ED_sculpt_undo_geometry_begin(ob, op); } if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) { @@ -654,6 +654,7 @@ struct QuadriFlowJob { short *stop, *do_update; float *progress; + const struct wmOperator *op; Scene *scene; int target_faces; int seed; @@ -891,7 +892,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes); if (ob->mode == OB_MODE_SCULPT) { - ED_sculpt_undo_geometry_begin(ob, "QuadriFlow Remesh"); + ED_sculpt_undo_geometry_begin(ob, qj->op); } if (qj->preserve_paint_mask) { @@ -949,6 +950,7 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op) { QuadriFlowJob *job = (QuadriFlowJob *)MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob"); + job->op = op; job->owner = CTX_data_active_object(C); job->scene = CTX_data_scene(C); diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index c612a84a631..e4f96d95173 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -1033,7 +1033,9 @@ static int apply_objects_internal(bContext *C, zero_v3(ob->rot); zero_v3(ob->drot); unit_qt(ob->quat); + unit_qt(ob->dquat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); + unit_axis_angle(ob->drotAxis, &ob->drotAngle); } } diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.cc index eb5aaf7ef61..0e0f5bd94cc 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.cc @@ -5,9 +5,9 @@ * \ingroup edobj */ -#include <math.h> -#include <stddef.h> -#include <string.h> +#include <cmath> +#include <cstddef> +#include <cstring> #include "MEM_guardedalloc.h" @@ -21,14 +21,15 @@ #include "DNA_scene_types.h" #include "DNA_workspace_types.h" -#include "BLI_alloca.h" #include "BLI_array.h" +#include "BLI_array.hh" #include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_utildefines_stack.h" +#include "BLI_vector.hh" #include "BKE_context.h" #include "BKE_customdata.h" @@ -74,7 +75,7 @@ static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob); static bool object_array_for_wpaint_filter(const Object *ob, void *user_data) { - bContext *C = user_data; + bContext *C = static_cast<bContext *>(user_data); if (vertex_group_supported_poll_ex(C, ob)) { return true; } @@ -100,7 +101,7 @@ static bool vertex_group_use_vert_sel(Object *ob) static Lattice *vgroup_edit_lattice(Object *ob) { - Lattice *lt = ob->data; + Lattice *lt = static_cast<Lattice *>(ob->data); BLI_assert(ob->type == OB_LATTICE); return (lt->editlatt) ? lt->editlatt->latt : lt; } @@ -115,7 +116,7 @@ bool ED_vgroup_sync_from_pose(Object *ob) { Object *armobj = BKE_object_pose_armature_get(ob); if (armobj && (armobj->mode & OB_MODE_POSE)) { - struct bArmature *arm = armobj->data; + bArmature *arm = static_cast<bArmature *>(armobj->data); if (arm->act_bone) { int def_num = BKE_object_defgroup_name_index(ob, arm->act_bone->name); if (def_num != -1) { @@ -151,7 +152,7 @@ bool ED_vgroup_parray_alloc(ID *id, const bool use_vert_sel) { *dvert_tot = 0; - *dvert_arr = NULL; + *dvert_arr = nullptr; if (id) { switch (GS(id->name)) { @@ -172,21 +173,23 @@ bool ED_vgroup_parray_alloc(ID *id, i = em->bm->totvert; - *dvert_arr = MEM_mallocN(sizeof(void *) * i, "vgroup parray from me"); + *dvert_arr = static_cast<MDeformVert **>(MEM_mallocN(sizeof(void *) * i, __func__)); *dvert_tot = i; i = 0; if (use_vert_sel) { BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ? - BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset) : - NULL; + static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)) : + nullptr; i++; } } else { BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - (*dvert_arr)[i] = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + (*dvert_arr)[i] = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); i++; } } @@ -198,11 +201,12 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert *dvert = me->dvert; *dvert_tot = me->totvert; - *dvert_arr = MEM_mallocN(sizeof(void *) * me->totvert, "vgroup parray from me"); + *dvert_arr = static_cast<MDeformVert **>( + MEM_mallocN(sizeof(void *) * me->totvert, __func__)); if (use_vert_sel) { for (int i = 0; i < me->totvert; i++) { - (*dvert_arr)[i] = (mvert[i].flag & SELECT) ? &dvert[i] : NULL; + (*dvert_arr)[i] = (mvert[i].flag & SELECT) ? &dvert[i] : nullptr; } } else { @@ -222,11 +226,12 @@ bool ED_vgroup_parray_alloc(ID *id, if (lt->dvert) { BPoint *def = lt->def; *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw; - *dvert_arr = MEM_mallocN(sizeof(void *) * (*dvert_tot), "vgroup parray from me"); + *dvert_arr = static_cast<MDeformVert **>( + MEM_mallocN(sizeof(void *) * (*dvert_tot), __func__)); if (use_vert_sel) { for (int i = 0; i < *dvert_tot; i++) { - (*dvert_arr)[i] = (def->f1 & SELECT) ? <->dvert[i] : NULL; + (*dvert_arr)[i] = (def->f1 & SELECT) ? <->dvert[i] : nullptr; } } else { @@ -255,11 +260,12 @@ void ED_vgroup_parray_mirror_sync(Object *ob, const int vgroup_tot) { BMEditMesh *em = BKE_editmesh_from_object(ob); - MDeformVert **dvert_array_all = NULL; + MDeformVert **dvert_array_all = nullptr; int dvert_tot_all; /* get an array of all verts, not only selected */ - if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { + if (ED_vgroup_parray_alloc( + static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) == false) { BLI_assert(0); return; } @@ -271,10 +277,10 @@ void ED_vgroup_parray_mirror_sync(Object *ob, const int *flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, true); for (int i_src = 0; i_src < dvert_tot; i_src++) { - if (dvert_array[i_src] != NULL) { + if (dvert_array[i_src] != nullptr) { /* its selected, check if its mirror exists */ int i_dst = ED_mesh_mirror_get_vert(ob, i_src); - if (i_dst != -1 && dvert_array_all[i_dst] != NULL) { + if (i_dst != -1 && dvert_array_all[i_dst] != nullptr) { /* we found a match! */ const MDeformVert *dv_src = dvert_array[i_src]; MDeformVert *dv_dst = dvert_array_all[i_dst]; @@ -294,11 +300,12 @@ void ED_vgroup_parray_mirror_sync(Object *ob, void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot) { BMEditMesh *em = BKE_editmesh_from_object(ob); - MDeformVert **dvert_array_all = NULL; + MDeformVert **dvert_array_all = nullptr; int dvert_tot_all; /* get an array of all verts, not only selected */ - if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { + if (ED_vgroup_parray_alloc( + static_cast<ID *>(ob->data), &dvert_array_all, &dvert_tot_all, false) == false) { BLI_assert(0); return; } @@ -308,7 +315,7 @@ void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const } for (int i = 0; i < dvert_tot; i++) { - if (dvert_array[i] == NULL) { + if (dvert_array[i] == nullptr) { /* its unselected, check if its mirror is */ int i_sel = ED_mesh_mirror_get_vert(ob, i); if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) { @@ -357,8 +364,8 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, bool ED_vgroup_array_copy(Object *ob, Object *ob_from) { - MDeformVert **dvert_array_from = NULL, **dvf; - MDeformVert **dvert_array = NULL, **dv; + MDeformVert **dvert_array_from = nullptr, **dvf; + MDeformVert **dvert_array = nullptr, **dv; int dvert_tot_from; int dvert_tot; int i; @@ -378,17 +385,18 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) /* In case we copy vgroup between two objects using same data, * we only have to care about object side of things. */ if (ob->data != ob_from->data) { - ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false); - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + ED_vgroup_parray_alloc( + static_cast<ID *>(ob_from->data), &dvert_array_from, &dvert_tot_from, false); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false); - if ((dvert_array == NULL) && (dvert_array_from != NULL) && - BKE_object_defgroup_data_create(ob->data)) { - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + if ((dvert_array == nullptr) && (dvert_array_from != nullptr) && + BKE_object_defgroup_data_create(static_cast<ID *>(ob->data))) { + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false); new_vgroup = true; } - if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || - dvert_array == NULL) { + if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == nullptr || + dvert_array == nullptr) { if (dvert_array) { MEM_freeN(dvert_array); } @@ -413,7 +421,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) if (defbase_tot_from < defbase_tot) { /* correct vgroup indices because the number of vgroups is being reduced. */ - int *remap = MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__); + blender::Array<int> remap(defbase_tot + 1); for (i = 0; i <= defbase_tot_from; i++) { remap[i] = i; } @@ -421,11 +429,10 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) remap[i] = 0; /* can't use these, so disable */ } - BKE_object_defgroup_remap_update_users(ob, remap); - MEM_freeN(remap); + BKE_object_defgroup_remap_update_users(ob, remap.data()); } - if (dvert_array_from != NULL && dvert_array != NULL) { + if (dvert_array_from != nullptr && dvert_array != nullptr) { dvf = dvert_array_from; dv = dvert_array; @@ -434,7 +441,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) *(*dv) = *(*dvf); if ((*dv)->dw) { - (*dv)->dw = MEM_dupallocN((*dv)->dw); + (*dv)->dw = static_cast<MDeformWeight *>(MEM_dupallocN((*dv)->dw)); } } @@ -513,7 +520,7 @@ static void mesh_defvert_mirror_update_internal(Object *ob, static void ED_mesh_defvert_mirror_update_em( Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); BMEditMesh *em = me->edit_mesh; BMVert *eve_mirr; bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; @@ -521,8 +528,10 @@ static void ED_mesh_defvert_mirror_update_em( eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx, use_topology); if (eve_mirr && eve_mirr != eve) { - MDeformVert *dvert_src = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); + MDeformVert *dvert_src = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); + MDeformVert *dvert_dst = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)); mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr); } } @@ -530,14 +539,14 @@ static void ED_mesh_defvert_mirror_update_em( static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx) { int vidx_mirr; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; if (vidx == -1) { return; } - vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology); + vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology); if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) { MDeformVert *dvert_src = &me->dvert[vidx]; @@ -548,7 +557,7 @@ static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx) void ED_vgroup_vert_active_mirror(Object *ob, int def_nr) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); BMEditMesh *em = me->edit_mesh; MDeformVert *dvert_act; @@ -584,7 +593,7 @@ static void vgroup_remove_weight(Object *ob, const int def_nr) static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); BMEditMesh *em = me->edit_mesh; BMVert *eve_act; int v_act; @@ -599,7 +608,7 @@ static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); } - if (dvert_act == NULL) { + if (dvert_act == nullptr) { return false; } @@ -623,7 +632,7 @@ static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); BMEditMesh *em = me->edit_mesh; MDeformVert *dvert_act; int i, vgroup_tot, subset_count; @@ -639,7 +648,8 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type) if (dvert_act) { BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + MDeformVert *dv = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); BKE_defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot); if (me->symmetry & ME_SYMMETRY_X) { ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); @@ -688,7 +698,7 @@ static const EnumPropertyItem WT_vertex_group_select_item[] = { "Deform Pose Bones", "All Vertex Groups assigned to Deform Bones"}, {WT_VGROUP_ALL, "ALL", 0, "All Groups", "All Vertex Groups"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *C, @@ -698,10 +708,10 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext * const uint selection_mask) { Object *ob; - EnumPropertyItem *item = NULL; + EnumPropertyItem *item = nullptr; int totitem = 0; - if (C == NULL) { + if (C == nullptr) { /* needed for docs and i18n tools */ return WT_vertex_group_select_item; } @@ -797,13 +807,13 @@ static void ED_vgroup_nr_vert_add( Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode) { /* Add the vert to the deform group with the specified number. */ - MDeformVert *dvert = NULL; + MDeformVert *dvert = nullptr; int tot; /* Get the vert. */ - BKE_object_defgroup_array_get(ob->data, &dvert, &tot); + BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot); - if (dvert == NULL) { + if (dvert == nullptr) { return; } @@ -865,7 +875,7 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, const ListBase *defbase = BKE_object_defgroup_list(ob); const int def_nr = BLI_findindex(defbase, dg); - MDeformVert *dv = NULL; + MDeformVert *dv = nullptr; int tot; /* get the deform group number, exit if @@ -875,8 +885,8 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, /* if there's no deform verts then create some, */ - if (BKE_object_defgroup_array_get(ob->data, &dv, &tot) && dv == NULL) { - BKE_object_defgroup_data_create(ob->data); + if (BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dv, &tot) && dv == nullptr) { + BKE_object_defgroup_data_create(static_cast<ID *>(ob->data)); } /* call another function to do the work @@ -897,31 +907,31 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) const int def_nr = BLI_findindex(defbase, dg); if (def_nr != -1) { - MDeformVert *dvert = NULL; + MDeformVert *dvert = nullptr; int tot; /* get the deform vertices corresponding to the * vertnum */ - BKE_object_defgroup_array_get(ob->data, &dvert, &tot); + BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &tot); if (dvert) { MDeformVert *dv = &dvert[vertnum]; MDeformWeight *dw; dw = BKE_defvert_find_index(dv, def_nr); - BKE_defvert_remove_group(dv, dw); /* dw can be NULL */ + BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */ } } } static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) { - MDeformVert *dv = NULL; + MDeformVert *dv = nullptr; /* get the deform vertices corresponding to the vertnum */ if (ob->type == OB_MESH) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); if (me->edit_mesh) { BMEditMesh *em = me->edit_mesh; @@ -932,7 +942,7 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) BMVert *eve; BM_mesh_elem_table_ensure(em->bm, BM_VERT); eve = BM_vert_at_index(em->bm, vertnum); - dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + dv = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); } else { return 0.0f; @@ -1004,7 +1014,7 @@ static void vgroup_select_verts(Object *ob, int select) } if (ob->type == OB_MESH) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); if (me->edit_mesh) { BMEditMesh *em = me->edit_mesh; @@ -1016,7 +1026,8 @@ static void vgroup_select_verts(Object *ob, int select) BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + MDeformVert *dv = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); if (BKE_defvert_find_index(dv, def_nr)) { BM_vert_select_set(em->bm, eve, select); } @@ -1034,7 +1045,8 @@ static void vgroup_select_verts(Object *ob, int select) } else { if (me->dvert) { - const bool *hide_vert = CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert"); + const bool *hide_vert = (const bool *)CustomData_get_layer_named( + &me->vdata, CD_PROP_BOOL, ".hide_vert"); MVert *mv; MDeformVert *dv; int i; @@ -1043,7 +1055,7 @@ static void vgroup_select_verts(Object *ob, int select) dv = me->dvert; for (i = 0; i < me->totvert; i++, mv++, dv++) { - if (hide_vert != NULL && !hide_vert[i]) { + if (hide_vert != nullptr && !hide_vert[i]) { if (BKE_defvert_find_index(dv, def_nr)) { if (select) { mv->flag |= SELECT; @@ -1092,12 +1104,13 @@ static void vgroup_duplicate(Object *ob) bDeformGroup *dg, *cdg; char name[sizeof(dg->name)]; MDeformWeight *dw_org, *dw_cpy; - MDeformVert **dvert_array = NULL; + MDeformVert **dvert_array = nullptr; int i, idg, icdg, dvert_tot = 0; ListBase *defbase = BKE_object_defgroup_list_mutable(ob); - dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); + dg = static_cast<bDeformGroup *>( + BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1)); if (!dg) { return; } @@ -1120,7 +1133,7 @@ static void vgroup_duplicate(Object *ob) icdg = BKE_object_defgroup_active_index_get(ob) - 1; /* TODO(@campbellbarton): we might want to allow only copy selected verts here? */ - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false); if (dvert_array) { for (i = 0; i < dvert_tot; i++) { @@ -1141,7 +1154,7 @@ static void vgroup_duplicate(Object *ob) static bool vgroup_normalize(Object *ob) { MDeformWeight *dw; - MDeformVert *dv, **dvert_array = NULL; + MDeformVert *dv, **dvert_array = nullptr; int dvert_tot = 0; const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; @@ -1152,7 +1165,7 @@ static bool vgroup_normalize(Object *ob) return false; } - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { float weight_max = 0.0f; @@ -1199,17 +1212,13 @@ static bool vgroup_normalize(Object *ob) /* This finds all of the vertices face-connected to vert by an edge and returns a * MEM_allocated array of indices of size count. * count is an int passed by reference so it can be assigned the value of the length here. */ -static int *getSurroundingVerts(Mesh *me, int vert, int *count) +static blender::Vector<int> getSurroundingVerts(Mesh *me, int vert) { MPoly *mp = me->mpoly; int i = me->totpoly; - /* Instead of looping twice on all polys and loops, and use a temp array, let's rather - * use a BLI_array, with a reasonable starting/reserved size (typically, there are not - * many vertices face-linked to another one, even 8 might be too high...). */ - int *verts = NULL; - BLI_array_declare(verts); - BLI_array_reserve(verts, 8); + blender::Vector<int> verts; + while (i--) { int j = mp->totloop; int first_l = mp->totloop - 1; @@ -1235,7 +1244,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) } /* Append a and b verts to array, if not yet present. */ - k = BLI_array_len(verts); + k = verts.size(); /* XXX Maybe a == b is enough? */ while (k-- && !(a == b && a == -1)) { if (verts[k] == a) { @@ -1246,10 +1255,10 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) } } if (a != -1) { - BLI_array_append(verts, a); + verts.append(a); } if (b != -1) { - BLI_array_append(verts, b); + verts.append(b); } /* Vert found in this poly, we can go to next one! */ @@ -1260,8 +1269,6 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) mp++; } - /* Do not free the array! */ - *count = BLI_array_len(verts); return verts; } @@ -1312,14 +1319,15 @@ static void getVerticalAndHorizontalChange(const float norm[3], changes[index][1] = len_v3v3(projA, projB); } -/* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to - * distToBe distance away from the provided plane strength can change distToBe so that it moves - * towards distToBe by that percentage cp changes how much the weights are adjusted +/** + * By changing nonzero weights, try to move a vertex in `me->mverts` with index 'index' to + * `distToBe` distance away from the provided plane strength can change `distToBe` so that it moves + * towards `distToBe` by that percentage `cp` changes how much the weights are adjusted * to check the distance * - * index is the index of the vertex being moved - * norm and d are the plane's properties for the equation: ax + by + cz + d = 0 - * coord is a point on the plane + * `index` is the index of the vertex being moved. + * `norm` and `d` are the plane's properties for the equation: `ax + by + cz + d = 0`. + * `coord` is a point on the plane. */ static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph, Scene *UNUSED(scene), @@ -1347,13 +1355,14 @@ static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph, float oldPos[3] = {0}; float vc, hc, dist = 0.0f; int i, k; - float(*changes)[2] = MEM_mallocN(sizeof(float[2]) * totweight, "vertHorzChange"); - float *dists = MEM_mallocN(sizeof(float) * totweight, "distance"); + float(*changes)[2] = static_cast<float(*)[2]>( + MEM_mallocN(sizeof(float[2]) * totweight, "vertHorzChange")); + float *dists = static_cast<float *>(MEM_mallocN(sizeof(float) * totweight, "distance")); /* track if up or down moved it closer for each bone */ - bool *upDown = MEM_callocN(sizeof(bool) * totweight, "upDownTracker"); + bool *upDown = static_cast<bool *>(MEM_callocN(sizeof(bool) * totweight, "upDownTracker")); - int *dwIndices = MEM_callocN(sizeof(int) * totweight, "dwIndexTracker"); + int *dwIndices = static_cast<int *>(MEM_callocN(sizeof(int) * totweight, "dwIndexTracker")); float distToStart; int bestIndex = 0; bool wasChange; @@ -1509,18 +1518,18 @@ static void vgroup_fix( Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); int i; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); MVert *mvert = me->mvert; - int *verts = NULL; if (!(me->editflag & ME_EDIT_PAINT_VERT_SEL)) { return; } for (i = 0; i < me->totvert && mvert; i++, mvert++) { if (mvert->flag & SELECT) { - int count = 0; - if ((verts = getSurroundingVerts(me, i, &count))) { + blender::Vector<int> verts = getSurroundingVerts(me, i); + const int count = verts.size(); + if (!verts.is_empty()) { MVert m; - MVert *p = MEM_callocN(sizeof(MVert) * (count), "deformedPoints"); + MVert *p = static_cast<MVert *>(MEM_callocN(sizeof(MVert) * (count), "deformedPoints")); int k; Mesh *me_deform = mesh_get_eval_deform( @@ -1546,7 +1555,6 @@ static void vgroup_fix( } } - MEM_freeN(verts); MEM_freeN(p); } } @@ -1561,7 +1569,7 @@ static void vgroup_levels_subset(Object *ob, const float gain) { MDeformWeight *dw; - MDeformVert *dv, **dvert_array = NULL; + MDeformVert *dv, **dvert_array = nullptr; int dvert_tot = 0; const bool use_vert_sel = vertex_group_use_vert_sel(ob); @@ -1569,7 +1577,7 @@ static void vgroup_levels_subset(Object *ob, (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 : false; - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { @@ -1607,7 +1615,7 @@ static bool vgroup_normalize_all(Object *ob, const bool lock_active, ReportList *reports) { - MDeformVert *dv, **dvert_array = NULL; + MDeformVert *dv, **dvert_array = nullptr; int i, dvert_tot = 0; const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; @@ -1618,7 +1626,7 @@ static bool vgroup_normalize_all(Object *ob, return false; } - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { const ListBase *defbase = BKE_object_defgroup_list(ob); @@ -1626,7 +1634,7 @@ static bool vgroup_normalize_all(Object *ob, bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot); bool changed = false; - if ((lock_active == true) && (lock_flags != NULL) && (def_nr < defbase_tot)) { + if ((lock_active == true) && (lock_flags != nullptr) && (def_nr < defbase_tot)) { lock_flags[def_nr] = true; } @@ -1689,7 +1697,7 @@ static const EnumPropertyItem vgroup_lock_actions[] = { {VGROUP_LOCK, "LOCK", 0, "Lock", "Lock all vertex groups"}, {VGROUP_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock all vertex groups"}, {VGROUP_INVERT, "INVERT", 0, "Invert", "Invert the lock state of all vertex groups"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; enum { @@ -1708,7 +1716,7 @@ static const EnumPropertyItem vgroup_lock_mask[] = { 0, "Invert Unselected", "Apply the opposite of Lock/Unlock to unselected vertex groups"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static bool *vgroup_selected_get(Object *ob) @@ -1727,7 +1735,7 @@ static bool *vgroup_selected_get(Object *ob) } } else { - mask = MEM_callocN(defbase_tot * sizeof(bool), __func__); + mask = static_cast<bool *>(MEM_callocN(defbase_tot * sizeof(bool), __func__)); } const int actdef = BKE_object_defgroup_active_index_get(ob); @@ -1741,7 +1749,7 @@ static bool *vgroup_selected_get(Object *ob) static void vgroup_lock_all(Object *ob, int action, int mask) { bDeformGroup *dg; - bool *selected = NULL; + bool *selected = nullptr; int i; if (mask != VGROUP_MASK_ALL) { @@ -1752,7 +1760,7 @@ static void vgroup_lock_all(Object *ob, int action, int mask) if (action == VGROUP_TOGGLE) { action = VGROUP_LOCK; - for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { + for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) { switch (mask) { case VGROUP_MASK_INVERT_UNSELECTED: case VGROUP_MASK_SELECTED: @@ -1775,7 +1783,7 @@ static void vgroup_lock_all(Object *ob, int action, int mask) } } - for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { + for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) { switch (mask) { case VGROUP_MASK_SELECTED: if (!selected[i]) { @@ -1820,14 +1828,14 @@ static void vgroup_invert_subset(Object *ob, const bool auto_remove) { MDeformWeight *dw; - MDeformVert *dv, **dvert_array = NULL; + MDeformVert *dv, **dvert_array = nullptr; int dvert_tot = 0; const bool use_vert_sel = vertex_group_use_vert_sel(ob); const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 : false; - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { for (int i = 0; i < dvert_tot; i++) { @@ -1877,10 +1885,10 @@ static void vgroup_smooth_subset(Object *ob, const float fac_expand) { const float ifac = 1.0f - fac; - MDeformVert **dvert_array = NULL; + MDeformVert **dvert_array = nullptr; int dvert_tot = 0; - int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count); - float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count); + blender::Array<int, 32> vgroup_subset_map(subset_count); + blender::Array<float, 32> vgroup_subset_weights(subset_count); const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 : false; @@ -1892,8 +1900,8 @@ static void vgroup_smooth_subset(Object *ob, const float iexpand = 1.0f - expand; BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em ? em->bm : NULL; - Mesh *me = em ? NULL : ob->data; + BMesh *bm = em ? em->bm : nullptr; + Mesh *me = em ? nullptr : static_cast<Mesh *>(ob->data); MeshElemMap *emap; int *emap_mem; @@ -1907,25 +1915,27 @@ static void vgroup_smooth_subset(Object *ob, uint *verts_used; STACK_DECLARE(verts_used); - BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map); - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - memset(vgroup_subset_weights, 0, sizeof(*vgroup_subset_weights) * subset_count); + BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map.data()); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, false); + vgroup_subset_weights.fill(0.0f); if (bm) { BM_mesh_elem_table_ensure(bm, BM_VERT); BM_mesh_elem_index_ensure(bm, BM_VERT); - emap = NULL; - emap_mem = NULL; + emap = nullptr; + emap_mem = nullptr; } else { BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge); } - weight_accum_prev = MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__); - weight_accum_curr = MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__); + weight_accum_prev = static_cast<float *>( + MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__)); + weight_accum_curr = static_cast<float *>( + MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__)); - verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__); + verts_used = static_cast<uint *>(MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__)); STACK_INIT(verts_used, dvert_tot); #define IS_BM_VERT_READ(v) (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true) @@ -1933,7 +1943,7 @@ static void vgroup_smooth_subset(Object *ob, const bool *hide_vert = me ? (const bool *)CustomData_get_layer_named( &me->vdata, CD_PROP_BOOL, ".hide_vert") : - NULL; + nullptr; #define IS_ME_VERT_READ(v) (use_hide ? (hide_vert && hide_vert[v]) : true) #define IS_ME_VERT_WRITE(v) (use_select ? (((v)->flag & SELECT) != 0) : true) @@ -2081,9 +2091,9 @@ static void vgroup_smooth_subset(Object *ob, MEM_freeN(dvert_array); } - /* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */ + /* not so efficient to get 'dvert_array' again just so unselected verts are nullptr'd */ if (use_mirror) { - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, true); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, true); ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot); if (dvert_array) { MEM_freeN(dvert_array); @@ -2099,7 +2109,8 @@ static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2) * less than, equal to, or greater than zero corresponding to whether its first argument is * considered less than, equal to, or greater than its second argument. * This does the opposite. */ - const struct MDeformWeight *dw1 = a1, *dw2 = a2; + const MDeformWeight *dw1 = static_cast<const MDeformWeight *>(a1); + const MDeformWeight *dw2 = static_cast<const MDeformWeight *>(a2); if (dw1->weight < dw2->weight) { return 1; @@ -2123,12 +2134,12 @@ static int vgroup_limit_total_subset(Object *ob, const int subset_count, const int max_weights) { - MDeformVert *dv, **dvert_array = NULL; + MDeformVert *dv, **dvert_array = nullptr; int i, dvert_tot = 0; const bool use_vert_sel = vertex_group_use_vert_sel(ob); int remove_tot = 0; - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { int num_to_drop = 0; @@ -2150,7 +2161,8 @@ static int vgroup_limit_total_subset(Object *ob, if (num_to_drop > 0) { /* re-pack dw array so that non-bone weights are first, bone-weighted verts at end * sort the tail, then copy only the truncated array back to dv->dw */ - dw_temp = MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__); + dw_temp = static_cast<MDeformWeight *>( + MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__)); bone_count = 0; non_bone_count = 0; for (j = 0; j < dv->totweight; j++) { @@ -2173,7 +2185,8 @@ static int vgroup_limit_total_subset(Object *ob, dv->totweight -= num_to_drop; /* Do we want to clean/normalize here? */ MEM_freeN(dv->dw); - dv->dw = MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight); + dv->dw = static_cast<MDeformWeight *>( + MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight)); remove_tot += num_to_drop; } else { @@ -2194,14 +2207,14 @@ static void vgroup_clean_subset(Object *ob, const float epsilon, const bool keep_single) { - MDeformVert **dvert_array = NULL; + MDeformVert **dvert_array = nullptr; int dvert_tot = 0; const bool use_vert_sel = vertex_group_use_vert_sel(ob); const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 : false; - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { if (use_mirror && use_vert_sel) { @@ -2224,13 +2237,13 @@ static void vgroup_quantize_subset(Object *ob, const int UNUSED(subset_count), const int steps) { - MDeformVert **dvert_array = NULL; + MDeformVert **dvert_array = nullptr; int dvert_tot = 0; const bool use_vert_sel = vertex_group_use_vert_sel(ob); const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X) != 0 : false; - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { const float steps_fl = steps; @@ -2353,7 +2366,7 @@ void ED_vgroup_mirror(Object *ob, BMVert *eve, *eve_mirr; MDeformVert *dvert, *dvert_mirr; char sel, sel_mirr; - int *flip_map = NULL, flip_map_len; + int *flip_map = nullptr, flip_map_len; const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; int totmirr = 0, totfail = 0; @@ -2362,7 +2375,7 @@ void ED_vgroup_mirror(Object *ob, const ListBase *defbase = BKE_object_defgroup_list(ob); if ((mirror_weights == false && flip_vgroups == false) || - (BLI_findlink(defbase, def_nr) == NULL)) { + (BLI_findlink(defbase, def_nr) == nullptr)) { return; } @@ -2370,21 +2383,21 @@ void ED_vgroup_mirror(Object *ob, flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, &flip_map_len, false) : BKE_object_defgroup_flip_map_single(ob, &flip_map_len, false, def_nr); - BLI_assert(flip_map != NULL); + BLI_assert(flip_map != nullptr); - if (flip_map == NULL) { + if (flip_map == nullptr) { /* something went wrong!, possibly no groups */ return; } } else { - flip_map = NULL; + flip_map = nullptr; flip_map_len = 0; } /* only the active group */ if (ob->type == OB_MESH) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); BMEditMesh *em = me->edit_mesh; if (em) { @@ -2409,8 +2422,9 @@ void ED_vgroup_mirror(Object *ob, sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); if ((sel || sel_mirr) && (eve != eve_mirr)) { - dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); + dvert = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); + dvert_mirr = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)); VGROUP_MIRR_OP; totmirr++; @@ -2435,7 +2449,7 @@ void ED_vgroup_mirror(Object *ob, int vidx, vidx_mirr; const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - if (me->dvert == NULL) { + if (me->dvert == nullptr) { goto cleanup; } @@ -2447,7 +2461,7 @@ void ED_vgroup_mirror(Object *ob, for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) { if (!BLI_BITMAP_TEST(vert_tag, vidx)) { - if ((vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology)) != -1) { + if ((vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology)) != -1) { if (vidx != vidx_mirr) { mv_mirr = &me->mvert[vidx_mirr]; if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) { @@ -2486,7 +2500,7 @@ void ED_vgroup_mirror(Object *ob, int pntsu_half; /* half but found up odd value */ - if (lt->pntsu == 1 || lt->dvert == NULL) { + if (lt->pntsu == 1 || lt->dvert == nullptr) { goto cleanup; } @@ -2546,7 +2560,8 @@ cleanup: static void vgroup_delete_active(Object *ob) { const ListBase *defbase = BKE_object_defgroup_list(ob); - bDeformGroup *dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); + bDeformGroup *dg = static_cast<bDeformGroup *>( + BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1)); if (!dg) { return; } @@ -2565,7 +2580,7 @@ static void vgroup_assign_verts(Object *ob, const float weight) } if (ob->type == OB_MESH) { - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); if (me->edit_mesh) { BMEditMesh *em = me->edit_mesh; @@ -2585,7 +2600,8 @@ static void vgroup_assign_verts(Object *ob, const float weight) if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { MDeformVert *dv; MDeformWeight *dw; - dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); /* can be NULL */ + dv = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); /* can be nullptr */ dw = BKE_defvert_ensure_index(dv, def_nr); if (dw) { dw->weight = weight; @@ -2618,7 +2634,7 @@ static void vgroup_assign_verts(Object *ob, const float weight) BPoint *bp; int a, tot; - if (lt->dvert == NULL) { + if (lt->dvert == nullptr) { BKE_object_defgroup_data_create(<->id); } @@ -2657,8 +2673,8 @@ static bool vertex_group_supported_poll_ex(bContext *C, const Object *ob) } /* Data checks. */ - const ID *data = ob->data; - if (data == NULL || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) { + const ID *data = static_cast<const ID *>(ob->data); + if (data == nullptr || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) { CTX_wm_operator_poll_msg_set(C, "Object type \"%s\" does not have editable data"); return false; } @@ -2714,8 +2730,8 @@ static bool vertex_group_mesh_with_dvert_poll(bContext *C) return false; } - Mesh *me = ob->data; - if (me->dvert == NULL) { + Mesh *me = static_cast<Mesh *>(ob->data); + if (me->dvert == nullptr) { CTX_wm_operator_poll_msg_set(C, "The active mesh object has no vertex group data"); return false; } @@ -2805,7 +2821,7 @@ static bool vertex_group_vert_select_unlocked_poll(bContext *C) const int def_nr = BKE_object_defgroup_active_index_get(ob); if (def_nr != 0) { const ListBase *defbase = BKE_object_defgroup_list(ob); - const bDeformGroup *dg = BLI_findlink(defbase, def_nr - 1); + const bDeformGroup *dg = static_cast<const bDeformGroup *>(BLI_findlink(defbase, def_nr - 1)); if (dg) { return !(dg->flag & DG_LOCK_WEIGHT); } @@ -3007,8 +3023,9 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op) } else { const ListBase *defbase = BKE_object_defgroup_list(ob); - bDeformGroup *dg = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); - if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) { + bDeformGroup *dg = static_cast<bDeformGroup *>( + BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1)); + if ((dg == nullptr) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) { return OPERATOR_CANCELLED; } } @@ -3059,7 +3076,7 @@ static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) } vgroup_select_verts(ob, 1); - DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); return OPERATOR_FINISHED; @@ -3091,7 +3108,7 @@ static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_context(C); vgroup_select_verts(ob, 0); - DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); return OPERATOR_FINISHED; @@ -3158,7 +3175,8 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op) float offset = RNA_float_get(op->ptr, "offset"); float gain = RNA_float_get(op->ptr, "gain"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + eVGroupSelect subset_type = static_cast<eVGroupSelect>( + RNA_enum_get(op->ptr, "group_select_mode")); int subset_count, vgroup_tot; @@ -3245,7 +3263,8 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); bool lock_active = RNA_boolean_get(op->ptr, "lock_active"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + eVGroupSelect subset_type = static_cast<eVGroupSelect>( + RNA_enum_get(op->ptr, "group_select_mode")); bool changed; int subset_count, vgroup_tot; const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( @@ -3305,7 +3324,7 @@ static int vertex_group_fix_exec(bContext *C, wmOperator *op) float distToBe = RNA_float_get(op->ptr, "dist"); float strength = RNA_float_get(op->ptr, "strength"); float cp = RNA_float_get(op->ptr, "accuracy"); - ModifierData *md = ob->modifiers.first; + ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first); while (md) { if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) { @@ -3394,9 +3413,9 @@ static int vertex_group_lock_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static char *vertex_group_lock_description(struct bContext *UNUSED(C), - struct wmOperatorType *UNUSED(op), - struct PointerRNA *params) +static char *vertex_group_lock_description(bContext *UNUSED(C), + wmOperatorType *UNUSED(op), + PointerRNA *params) { int action = RNA_enum_get(params, "action"); int mask = RNA_enum_get(params, "mask"); @@ -3417,7 +3436,7 @@ static char *vertex_group_lock_description(struct bContext *UNUSED(C), action_str = TIP_("Invert locks of"); break; default: - return NULL; + return nullptr; } switch (mask) { @@ -3446,7 +3465,7 @@ static char *vertex_group_lock_description(struct bContext *UNUSED(C), } break; default: - return NULL; + return nullptr; } return BLI_sprintfN(TIP_("%s %s vertex groups of the active object"), action_str, target_str); @@ -3494,7 +3513,8 @@ static int vertex_group_invert_exec(bContext *C, wmOperator *op) bool auto_assign = RNA_boolean_get(op->ptr, "auto_assign"); bool auto_remove = RNA_boolean_get(op->ptr, "auto_remove"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + eVGroupSelect subset_type = static_cast<eVGroupSelect>( + RNA_enum_get(op->ptr, "group_select_mode")); int subset_count, vgroup_tot; @@ -3547,7 +3567,8 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) { const float fac = RNA_float_get(op->ptr, "factor"); const int repeat = RNA_int_get(op->ptr, "repeat"); - const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + const eVGroupSelect subset_type = static_cast<eVGroupSelect>( + RNA_enum_get(op->ptr, "group_select_mode")); const float fac_expand = RNA_float_get(op->ptr, "expand"); uint objects_len; @@ -3612,7 +3633,8 @@ static int vertex_group_clean_exec(bContext *C, wmOperator *op) { const float limit = RNA_float_get(op->ptr, "limit"); const bool keep_single = RNA_boolean_get(op->ptr, "keep_single"); - const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + const eVGroupSelect subset_type = static_cast<eVGroupSelect>( + RNA_enum_get(op->ptr, "group_select_mode")); uint objects_len; Object **objects = object_array_for_wpaint(C, &objects_len); @@ -3679,7 +3701,8 @@ static int vertex_group_quantize_exec(bContext *C, wmOperator *op) Object *ob = ED_object_context(C); const int steps = RNA_int_get(op->ptr, "steps"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + eVGroupSelect subset_type = static_cast<eVGroupSelect>( + RNA_enum_get(op->ptr, "group_select_mode")); int subset_count, vgroup_tot; @@ -3722,7 +3745,8 @@ void OBJECT_OT_vertex_group_quantize(wmOperatorType *ot) static int vertex_group_limit_total_exec(bContext *C, wmOperator *op) { const int limit = RNA_int_get(op->ptr, "limit"); - const eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + const eVGroupSelect subset_type = static_cast<eVGroupSelect>( + RNA_enum_get(op->ptr, "group_select_mode")); int remove_multi_count = 0; uint objects_len; @@ -3917,13 +3941,13 @@ static const EnumPropertyItem *vgroup_itemf(bContext *C, PropertyRNA *UNUSED(prop), bool *r_free) { - if (C == NULL) { + if (C == nullptr) { return DummyRNA_NULL_items; } Object *ob = ED_object_context(C); EnumPropertyItem tmp = {0, "", 0, "", ""}; - EnumPropertyItem *item = NULL; + EnumPropertyItem *item = nullptr; bDeformGroup *def; int a, totitem = 0; @@ -3932,7 +3956,7 @@ static const EnumPropertyItem *vgroup_itemf(bContext *C, } const ListBase *defbase = BKE_object_defgroup_list(ob); - for (a = 0, def = defbase->first; def; def = def->next, a++) { + for (a = 0, def = static_cast<bDeformGroup *>(defbase->first); def; def = def->next, a++) { tmp.value = a; tmp.icon = ICON_GROUP_VERTEX; tmp.identifier = def->name; @@ -3983,11 +4007,13 @@ static char *vgroup_init_remap(Object *ob) { const ListBase *defbase = BKE_object_defgroup_list(ob); int defbase_tot = BLI_listbase_count(defbase); - char *name_array = MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"); + char *name_array = static_cast<char *>( + MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups")); char *name; name = name_array; - for (const bDeformGroup *def = defbase->first; def; def = def->next) { + for (const bDeformGroup *def = static_cast<const bDeformGroup *>(defbase->first); def; + def = def->next) { BLI_strncpy(name, def->name, MAX_VGROUP_NAME); name += MAX_VGROUP_NAME; } @@ -3997,20 +4023,21 @@ static char *vgroup_init_remap(Object *ob) static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) { - MDeformVert *dvert = NULL; + MDeformVert *dvert = nullptr; const bDeformGroup *def; const ListBase *defbase = BKE_object_defgroup_list(ob); int defbase_tot = BLI_listbase_count(defbase); /* Needs a dummy index at the start. */ - int *sort_map_update = MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups"); + int *sort_map_update = static_cast<int *>( + MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__)); int *sort_map = sort_map_update + 1; const char *name; int i; name = name_array; - for (def = defbase->first, i = 0; def; def = def->next, i++) { + for (def = static_cast<const bDeformGroup *>(defbase->first), i = 0; def; def = def->next, i++) { sort_map[i] = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name)); name += MAX_VGROUP_NAME; @@ -4027,7 +4054,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) BMVert *eve; BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + dvert = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); if (dvert->totweight) { BKE_defvert_remap(dvert, sort_map, defbase_tot); } @@ -4045,7 +4072,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) /* Grease pencil stores vertex groups separately for each stroke, * so remap each stroke's weights separately. */ if (ob->type == OB_GPENCIL) { - bGPdata *gpd = ob->data; + bGPdata *gpd = static_cast<bGPdata *>(ob->data); LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { @@ -4064,7 +4091,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) } } else { - BKE_object_defgroup_array_get(ob->data, &dvert, &dvert_tot); + BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert, &dvert_tot); /* Create as necessary. */ if (dvert) { @@ -4097,8 +4124,8 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) { - const bDeformGroup *def_a = def_a_ptr; - const bDeformGroup *def_b = def_b_ptr; + const bDeformGroup *def_a = static_cast<const bDeformGroup *>(def_a_ptr); + const bDeformGroup *def_b = static_cast<const bDeformGroup *>(def_b_ptr); return BLI_strcasecmp_natural(def_a->name, def_b->name); } @@ -4109,22 +4136,22 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) */ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) { - if (bonebase == NULL) { + if (bonebase == nullptr) { Object *armobj = BKE_modifiers_is_deformed_by_armature(ob); - if (armobj != NULL) { - bArmature *armature = armobj->data; + if (armobj != nullptr) { + bArmature *armature = static_cast<bArmature *>(armobj->data); bonebase = &armature->bonebase; } } ListBase *defbase = BKE_object_defgroup_list_mutable(ob); - if (bonebase != NULL) { + if (bonebase != nullptr) { Bone *bone; - for (bone = bonebase->last; bone; bone = bone->prev) { + for (bone = static_cast<Bone *>(bonebase->last); bone; bone = bone->prev) { bDeformGroup *dg = BKE_object_defgroup_find_name(ob, bone->name); vgroup_sort_bone_hierarchy(ob, &bone->childbase); - if (dg != NULL) { + if (dg != nullptr) { BLI_remlink(defbase, dg); BLI_addhead(defbase, dg); } @@ -4155,7 +4182,7 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op) BLI_listbase_sort(defbase, vgroup_sort_name); break; case SORT_TYPE_BONEHIERARCHY: - vgroup_sort_bone_hierarchy(ob, NULL); + vgroup_sort_bone_hierarchy(ob, nullptr); break; } @@ -4179,7 +4206,7 @@ void OBJECT_OT_vertex_group_sort(wmOperatorType *ot) static const EnumPropertyItem vgroup_sort_type[] = { {SORT_TYPE_NAME, "NAME", 0, "Name", ""}, {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; ot->name = "Sort Vertex Groups"; @@ -4212,7 +4239,8 @@ static int vgroup_move_exec(bContext *C, wmOperator *op) ListBase *defbase = BKE_object_defgroup_list_mutable(ob); - def = BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1); + def = static_cast<bDeformGroup *>( + BLI_findlink(defbase, BKE_object_defgroup_active_index_get(ob) - 1)); if (!def) { return OPERATOR_CANCELLED; } @@ -4240,7 +4268,7 @@ void OBJECT_OT_vertex_group_move(wmOperatorType *ot) static const EnumPropertyItem vgroup_slot_move[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -4273,7 +4301,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) { MDeformVert *dvert_act; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); BMEditMesh *em = me->edit_mesh; int i; @@ -4283,13 +4311,14 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) BMVert *eve, *eve_act; dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); - if (dvert_act == NULL) { + if (dvert_act == nullptr) { return; } BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) { - MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + MDeformVert *dvert_dst = static_cast<MDeformVert *>( + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr); @@ -4308,7 +4337,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) int v_act; dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); - if (dvert_act == NULL) { + if (dvert_act == nullptr) { return; } @@ -4333,7 +4362,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr) { const ListBase *defbase = BKE_object_defgroup_list(ob); - bDeformGroup *dg = BLI_findlink(defbase, def_nr); + bDeformGroup *dg = static_cast<bDeformGroup *>(BLI_findlink(defbase, def_nr)); if (!dg) { BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index"); @@ -4390,7 +4419,7 @@ void OBJECT_OT_vertex_weight_paste(wmOperatorType *ot) "Index of source weight in active vertex group", -1, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN)); } /** \} */ @@ -4440,7 +4469,7 @@ void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot) "Index of source weight in active vertex group", -1, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN)); } /** \} */ @@ -4487,7 +4516,7 @@ void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot) "Index of source weight in active vertex group", -1, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN)); } /** \} */ @@ -4500,7 +4529,7 @@ static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *U { Object *ob = ED_object_context(C); ToolSettings *ts = CTX_data_tool_settings(C); - eVGroupSelect subset_type = ts->vgroupsubset; + eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset); bool changed; changed = vgroup_normalize_active_vertex(ob, subset_type); @@ -4539,7 +4568,7 @@ static int vertex_weight_copy_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); ToolSettings *ts = CTX_data_tool_settings(C); - eVGroupSelect subset_type = ts->vgroupsubset; + eVGroupSelect subset_type = static_cast<eVGroupSelect>(ts->vgroupsubset); vgroup_copy_active_to_sel(ob, subset_type); diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt index ee59efbc925..e56d58c2135 100644 --- a/source/blender/editors/physics/CMakeLists.txt +++ b/source/blender/editors/physics/CMakeLists.txt @@ -11,7 +11,6 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../../../intern/mantaflow/extern # RNA_prototypes.h diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 80de8fae072..1d3cf7c36af 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -502,6 +502,7 @@ static void fluid_free_startjob(void *customdata, short *stop, short *do_update, BKE_fluid_cache_free(fds, job->ob, cache_map); #else UNUSED_VARS(fds); + UNUSED_VARS(cache_map); #endif *do_update = true; diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 66ae2d323fd..b7c82c18433 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -88,7 +88,7 @@ bool ED_rigidbody_constraint_add( /* create constraint group if it doesn't already exits */ if (rbw->constraints == NULL) { rbw->constraints = BKE_collection_add(bmain, NULL, "RigidBodyConstraints"); - id_fake_user_set(&rbw->constraints->id); + id_us_plus(&rbw->constraints->id); } /* make rigidbody constraint settings */ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type); diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 4b644ae826f..a91a63201c4 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -17,7 +17,6 @@ set(INC ../../render ../../sequencer ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index da2290f7372..f784346ec8f 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -934,7 +934,7 @@ static int view_layer_add_exec(bContext *C, wmOperator *op) WM_window_set_active_view_layer(win, view_layer_new); } - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1039,7 +1039,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op)) ntreeCompositUpdateRLayers(scene->nodetree); } - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1091,7 +1091,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) ntreeCompositUpdateRLayers(scene->nodetree); } - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1143,7 +1143,7 @@ static int view_layer_add_lightgroup_exec(bContext *C, wmOperator *op) ntreeCompositUpdateRLayers(scene->nodetree); } - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1193,7 +1193,7 @@ static int view_layer_remove_lightgroup_exec(bContext *C, wmOperator *UNUSED(op) ntreeCompositUpdateRLayers(scene->nodetree); } - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1257,7 +1257,7 @@ static int view_layer_add_used_lightgroups_exec(bContext *C, wmOperator *UNUSED( ntreeCompositUpdateRLayers(scene->nodetree); } - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1301,7 +1301,7 @@ static int view_layer_remove_unused_lightgroups_exec(bContext *C, wmOperator *UN ntreeCompositUpdateRLayers(scene->nodetree); } - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -1692,7 +1692,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op)) BKE_freestyle_module_delete(&view_layer->freestyle_config, module); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); return OPERATOR_FINISHED; @@ -1722,7 +1722,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op) int dir = RNA_enum_get(op->ptr, "direction"); if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) { - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); } @@ -1778,7 +1778,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op)) BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); return OPERATOR_FINISHED; @@ -1852,7 +1852,7 @@ static int freestyle_lineset_paste_exec(bContext *C, wmOperator *UNUSED(op)) FRS_paste_active_lineset(&view_layer->freestyle_config); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); return OPERATOR_FINISHED; @@ -1886,7 +1886,7 @@ static int freestyle_lineset_remove_exec(bContext *C, wmOperator *UNUSED(op)) FRS_delete_active_lineset(&view_layer->freestyle_config); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); return OPERATOR_FINISHED; @@ -1920,7 +1920,7 @@ static int freestyle_lineset_move_exec(bContext *C, wmOperator *op) int dir = RNA_enum_get(op->ptr, "direction"); if (FRS_move_active_lineset(&view_layer->freestyle_config, dir)) { - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); } diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index 57a9e6be917..07a93d3907a 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -229,7 +229,7 @@ bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, Rep BKE_view_layer_free(layer); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER | NA_REMOVED, scene); diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index f9b1e2b5d4c..119758f3335 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -15,7 +15,6 @@ set(INC ../../makesrna ../../sequencer ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 8a84f4cf079..cb3510615cc 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -77,9 +77,10 @@ void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, * filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR), * so always use mipmaps when filtering. */ const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h)); - const int mips = use_mipmap ? 9999 : 1; + const int mip_len = use_mipmap ? 9999 : 1; - GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, mips, gpu_format, NULL); + GPUTexture *tex = GPU_texture_create_2d( + "immDrawPixels", img_w, img_h, mip_len, gpu_format, NULL); const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F); eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE; diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 5464d0a347d..38a9d8ba7ab 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -54,13 +54,12 @@ static int screenshot_data_create(bContext *C, wmOperator *op, ScrArea *area) { int dumprect_size[2]; - wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); /* do redraw so we don't show popups/menus */ WM_redraw_windows(C); - uint *dumprect = WM_window_pixels_read(wm, win, dumprect_size); + uint *dumprect = WM_window_pixels_read_offscreen(C, win, dumprect_size); if (dumprect) { ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot"); diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index fc3ac53ef0b..9a6bdc98d76 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -359,6 +359,12 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op) BLO_LIBLINK_APPEND_RECURSIVE); if (appended_workspace) { + if (BLT_translate_new_dataname()) { + /* Translate workspace name */ + BKE_libblock_rename( + bmain, &appended_workspace->id, CTX_DATA_(BLT_I18NCONTEXT_ID_WORKSPACE, idname)); + } + /* Set defaults. */ BLO_update_defaults_workspace(appended_workspace, NULL); @@ -441,8 +447,14 @@ static void workspace_append_button(uiLayout *layout, BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate")); PointerRNA opptr; - uiItemFullO_ptr( - layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); + uiItemFullO_ptr(layout, + ot_append, + CTX_DATA_(BLT_I18NCONTEXT_ID_WORKSPACE, workspace->id.name + 2), + ICON_NONE, + NULL, + WM_OP_EXEC_DEFAULT, + 0, + &opptr); RNA_string_set(&opptr, "idname", id->name + 2); RNA_string_set(&opptr, "filepath", filepath); } @@ -495,7 +507,8 @@ static void workspace_add_menu(bContext *UNUSED(C), uiLayout *layout, void *temp static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - uiPopupMenu *pup = UI_popup_menu_begin(C, op->type->name, ICON_ADD); + uiPopupMenu *pup = UI_popup_menu_begin( + C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, op->type->name), ICON_ADD); uiLayout *layout = UI_popup_menu_layout(pup); uiItemMenuF(layout, IFACE_("General"), ICON_NONE, workspace_add_menu, NULL); @@ -507,7 +520,7 @@ static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS char *template = link->data; char display_name[FILE_MAX]; - BLI_path_to_display_name(display_name, sizeof(display_name), template); + BLI_path_to_display_name(display_name, sizeof(display_name), IFACE_(template)); /* Steals ownership of link data string. */ uiItemMenuFN(layout, display_name, ICON_NONE, workspace_add_menu, template); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index b170280ccf3..f4d3002219d 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -21,7 +21,6 @@ set(INC ../../../../intern/atomic ../../../../intern/clog ../../../../intern/eigen - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index c904d533db8..a7aa29853e6 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -351,10 +351,10 @@ static int hide_show_exec(bContext *C, wmOperator *op) /* Start undo. */ switch (action) { case PARTIALVIS_HIDE: - SCULPT_undo_push_begin(ob, "Hide area"); + SCULPT_undo_push_begin_ex(ob, "Hide area"); break; case PARTIALVIS_SHOW: - SCULPT_undo_push_begin(ob, "Show area"); + SCULPT_undo_push_begin_ex(ob, "Show area"); break; } diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc index 24290fed323..5a6ac9463e2 100644 --- a/source/blender/editors/sculpt_paint/paint_image.cc +++ b/source/blender/editors/sculpt_paint/paint_image.cc @@ -158,6 +158,16 @@ void imapaint_image_update( imapaintpartial.dirty_region.xmax, imapaintpartial.dirty_region.ymax); + /* When buffer is partial updated the planes should be set to a larger value than 8. This will + * make sure that partial updating is working but uses more GPU memory as the gpu texture will + * have 4 channels. When so the whole texture needs to be reuploaded to the GPU using the new + * texture format.*/ + if (ibuf != nullptr && ibuf->planes == 8) { + ibuf->planes = 32; + BKE_image_partial_update_mark_full_update(image); + return; + } + /* TODO: should set_tpage create ->rect? */ if (texpaint || (sima && sima->lock)) { const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 2e57886fd95..dcc6e734cf4 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -152,7 +152,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); - SCULPT_undo_push_begin(ob, "Mask flood fill"); + SCULPT_undo_push_begin(ob, op); MaskTaskData data = { .ob = ob, @@ -687,10 +687,10 @@ static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, P return false; } -static void sculpt_gesture_apply(bContext *C, SculptGestureContext *sgcontext) +static void sculpt_gesture_apply(bContext *C, SculptGestureContext *sgcontext, wmOperator *op) { SculptGestureOperation *operation = sgcontext->operation; - SCULPT_undo_push_begin(CTX_data_active_object(C), "Sculpt Gesture Apply"); + SCULPT_undo_push_begin(CTX_data_active_object(C), op); operation->sculpt_gesture_begin(C, sgcontext); @@ -1502,7 +1502,7 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } sculpt_gesture_init_mask_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } @@ -1514,7 +1514,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } sculpt_gesture_init_mask_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } @@ -1526,7 +1526,7 @@ static int paint_mask_gesture_line_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } sculpt_gesture_init_mask_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } @@ -1538,7 +1538,7 @@ static int face_set_gesture_box_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } sculpt_gesture_init_face_set_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } @@ -1550,7 +1550,7 @@ static int face_set_gesture_lasso_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } sculpt_gesture_init_face_set_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } @@ -1575,7 +1575,7 @@ static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op) } sculpt_gesture_init_trim_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } @@ -1616,7 +1616,7 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } sculpt_gesture_init_trim_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } @@ -1645,7 +1645,7 @@ static int project_gesture_line_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } sculpt_gesture_init_project_properties(sgcontext, op); - sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_apply(C, sgcontext, op); sculpt_gesture_context_free(sgcontext); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index 6dc8375bb0d..ccaf8b1ba37 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -3957,7 +3957,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) BKE_pbvh_ensure_node_loops(ob->sculpt->pbvh); } - SCULPT_undo_push_begin(ob, "Vertex Paint"); + SCULPT_undo_push_begin_ex(ob, "Vertex Paint"); if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { paint_stroke_free(C, op, (PaintStroke *)op->customdata); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index ffa931268fd..a56755edf92 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1406,16 +1406,13 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, switch (data->brush->sculpt_tool) { case SCULPT_TOOL_MASK: type = SCULPT_UNDO_MASK; - BKE_pbvh_node_mark_update_mask(data->nodes[n]); break; case SCULPT_TOOL_PAINT: case SCULPT_TOOL_SMEAR: type = SCULPT_UNDO_COLOR; - BKE_pbvh_node_mark_update_color(data->nodes[n]); break; default: type = SCULPT_UNDO_COORDS; - BKE_pbvh_node_mark_update(data->nodes[n]); break; } @@ -1430,6 +1427,20 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, return; } + switch (type) { + case SCULPT_UNDO_MASK: + BKE_pbvh_node_mark_update_mask(data->nodes[n]); + break; + case SCULPT_UNDO_COLOR: + BKE_pbvh_node_mark_update_color(data->nodes[n]); + break; + case SCULPT_UNDO_COORDS: + BKE_pbvh_node_mark_update(data->nodes[n]); + break; + default: + break; + } + PBVHVertexIter vd; SculptOrigVertData orig_data; @@ -5382,7 +5393,7 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f ED_image_undo_push_begin(op->type->name, PAINT_MODE_SCULPT); } else { - SCULPT_undo_push_begin(ob, sculpt_tool_name(sd)); + SCULPT_undo_push_begin_ex(ob, sculpt_tool_name(sd)); } return true; @@ -5645,6 +5656,10 @@ static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent return paint_stroke_modal(C, op, event, (struct PaintStroke **)&op->customdata); } +static void sculpt_redo_empty_ui(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ +} + void SCULPT_OT_brush_stroke(wmOperatorType *ot) { /* Identifiers. */ @@ -5658,6 +5673,7 @@ void SCULPT_OT_brush_stroke(wmOperatorType *ot) ot->exec = sculpt_brush_stroke_exec; ot->poll = SCULPT_poll; ot->cancel = sculpt_brush_stroke_cancel; + ot->ui = sculpt_redo_empty_ui; /* Flags (sculpt does own undo? (ton)). */ ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index b4b2c4e48c8..691dfa21851 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -1579,7 +1579,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent /* Needs mask data to be available as it is used when solving the constraints. */ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - SCULPT_undo_push_begin(ob, "Cloth filter"); + SCULPT_undo_push_begin(ob, op); SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); ss->filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob); diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index ebbb0fa429e..8f87cd1b6ed 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -76,7 +76,7 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C) /** \name Detail Flood Fill * \{ */ -static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) +static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *op) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Object *ob = CTX_data_active_object(C); @@ -106,7 +106,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat)); BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail); - SCULPT_undo_push_begin(ob, "Dynamic topology flood fill"); + SCULPT_undo_push_begin(ob, op); SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS); while (BKE_pbvh_bmesh_update_topology( diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 40b4b74a441..433823c8373 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -274,7 +274,7 @@ void sculpt_dynamic_topology_disable_with_undo(Main *bmain, /* May be false in background mode. */ const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true; if (use_undo) { - SCULPT_undo_push_begin(ob, "Dynamic topology disable"); + SCULPT_undo_push_begin_ex(ob, "Dynamic topology disable"); SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END); } SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL); @@ -294,7 +294,7 @@ static void sculpt_dynamic_topology_enable_with_undo(Main *bmain, /* May be false in background mode. */ const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true; if (use_undo) { - SCULPT_undo_push_begin(ob, "Dynamic topology enable"); + SCULPT_undo_push_begin_ex(ob, "Dynamic topology enable"); } SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); if (use_undo) { diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index dd1c7a36c16..75cc966c0b2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -2124,7 +2124,7 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even sculpt_expand_ensure_sculptsession_data(ob); /* Initialize undo. */ - SCULPT_undo_push_begin(ob, "expand"); + SCULPT_undo_push_begin(ob, op); sculpt_expand_undo_push(ob, ss->expand_cache); /* Set the initial element for expand from the event position. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index f045ba841f3..a2a34566bb6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -317,7 +317,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - SCULPT_undo_push_begin(ob, "face set change"); + SCULPT_undo_push_begin(ob, op); SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); const int next_face_set = SCULPT_face_set_next_available_get(ss); @@ -707,7 +707,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - SCULPT_undo_push_begin(ob, "face set change"); + SCULPT_undo_push_begin(ob, op); SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); const float threshold = RNA_float_get(op->ptr, "threshold"); @@ -856,7 +856,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) const int mode = RNA_enum_get(op->ptr, "mode"); const int active_face_set = SCULPT_active_face_set_get(ss); - SCULPT_undo_push_begin(ob, "Hide area"); + SCULPT_undo_push_begin(ob, op); PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; @@ -1317,9 +1317,10 @@ static void sculpt_face_set_edit_modify_geometry(bContext *C, Object *ob, const int active_face_set, const eSculptFaceSetEditMode mode, - const bool modify_hidden) + const bool modify_hidden, + wmOperator *op) { - ED_sculpt_undo_geometry_begin(ob, "edit face set delete geometry"); + ED_sculpt_undo_geometry_begin(ob, op); sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden); ED_sculpt_undo_geometry_end(ob); BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); @@ -1349,7 +1350,8 @@ static void face_set_edit_do_post_visibility_updates(Object *ob, PBVHNode **node static void sculpt_face_set_edit_modify_face_sets(Object *ob, const int active_face_set, const eSculptFaceSetEditMode mode, - const bool modify_hidden) + const bool modify_hidden, + wmOperator *op) { PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; @@ -1359,7 +1361,7 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob, if (!nodes) { return; } - SCULPT_undo_push_begin(ob, "face set edit"); + SCULPT_undo_push_begin(ob, op); SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden); SCULPT_undo_push_end(ob); @@ -1370,7 +1372,8 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob, static void sculpt_face_set_edit_modify_coordinates(bContext *C, Object *ob, const int active_face_set, - const eSculptFaceSetEditMode mode) + const eSculptFaceSetEditMode mode, + wmOperator *op) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = ob->sculpt; @@ -1378,7 +1381,7 @@ static void sculpt_face_set_edit_modify_coordinates(bContext *C, PBVHNode **nodes; int totnode; BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); - SCULPT_undo_push_begin(ob, "face set edit"); + SCULPT_undo_push_begin(ob, op); for (int i = 0; i < totnode; i++) { BKE_pbvh_node_mark_update(nodes[i]); SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS); @@ -1421,15 +1424,15 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven switch (mode) { case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY: - sculpt_face_set_edit_modify_geometry(C, ob, active_face_set, mode, modify_hidden); + sculpt_face_set_edit_modify_geometry(C, ob, active_face_set, mode, modify_hidden, op); break; case SCULPT_FACE_SET_EDIT_GROW: case SCULPT_FACE_SET_EDIT_SHRINK: - sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden); + sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden, op); break; case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: - sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode); + sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode, op); break; } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index 7a1e08ea713..161fc563950 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -346,7 +346,7 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED; } - SCULPT_undo_push_begin(ob, "color filter"); + SCULPT_undo_push_begin(ob, op); BKE_sculpt_color_layer_create_if_needed(ob); /* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index fa4fe191273..cba1d3dcdc1 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -193,7 +193,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) int num_verts = SCULPT_vertex_count_get(ss); BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); - SCULPT_undo_push_begin(ob, "Mask Filter"); + SCULPT_undo_push_begin(ob, op); for (int i = 0; i < totnode; i++) { SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); @@ -409,7 +409,7 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) } BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); - SCULPT_undo_push_begin(ob, "Dirty Mask"); + SCULPT_undo_push_begin(ob, op); for (int i = 0; i < totnode; i++) { SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 4f45b7917ec..e576cfda3af 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -694,7 +694,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_boundary_info_ensure(ob); } - SCULPT_undo_push_begin(ob, "Mesh Filter"); + SCULPT_undo_push_begin(ob, op); SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 6a10f7cad18..e4bba135518 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1494,10 +1494,17 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type); SculptUndoNode *SCULPT_undo_get_first_node(void); /** - * NOTE: `name` must match operator name for - * redo panels to work. + * Pushes an undo step using the operator name. This is necessary for + * redo panels to work; operators that do not support that may use + * #SCULPT_undo_push_begin_ex instead if so desired. */ -void SCULPT_undo_push_begin(struct Object *ob, const char *name); +void SCULPT_undo_push_begin(struct Object *ob, const struct wmOperator *op); + +/** + * NOTE: #SCULPT_undo_push_begin is preferred since `name` + * must match operator name for redo panels to work. + */ +void SCULPT_undo_push_begin_ex(struct Object *ob, const char *name); void SCULPT_undo_push_end(struct Object *ob); void SCULPT_undo_push_end_ex(struct Object *ob, const bool use_nested_undo); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 2e661711172..9556d24f12c 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -361,7 +361,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode); - SCULPT_undo_push_begin(ob, "Mask Expand"); + SCULPT_undo_push_begin(ob, op); if (create_face_set) { SCULPT_undo_push_node(ob, ss->filter_cache->nodes[0], SCULPT_UNDO_FACE_SETS); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c index cc27623adb0..b9b889ab2ce 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c @@ -131,7 +131,7 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - SCULPT_undo_push_begin(ob, "init mask"); + SCULPT_undo_push_begin(ob, op); if (mode == SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART) { SCULPT_connected_components_ensure(ob); diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 151eb7744ea..b7b3b32aaf7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -215,7 +215,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) * as deleted, then after symmetrize operation all BMesh elements * are logged as added (as opposed to attempting to store just the * parts that symmetrize modifies). */ - SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize"); + SCULPT_undo_push_begin(ob, op); SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); BM_log_before_all_removed(ss->bm, ss->bm_log); @@ -242,7 +242,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) break; case PBVH_FACES: /* Mesh Symmetrize. */ - ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize"); + ED_sculpt_undo_geometry_begin(ob, op); Mesh *mesh = ob->data; BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist); @@ -394,7 +394,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain, bool has_undo = wm->undo_stack != NULL; /* Undo push is needed to prevent memory leak. */ if (has_undo) { - SCULPT_undo_push_begin(ob, "Dynamic topology enable"); + SCULPT_undo_push_begin_ex(ob, "Dynamic topology enable"); } SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); if (has_undo) { @@ -510,7 +510,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) * while it works it causes lag when undoing the first undo step, see T71564. */ wmWindowManager *wm = CTX_wm_manager(C); if (wm->op_undo_depth <= 1) { - SCULPT_undo_push_begin(ob, op->type->name); + SCULPT_undo_push_begin(ob, op); SCULPT_undo_push_end(ob); } } @@ -921,7 +921,7 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven const float mval_fl[2] = {UNPACK2(event->mval)}; SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); - SCULPT_undo_push_begin(ob, "Mask by color"); + SCULPT_undo_push_begin(ob, op); BKE_sculpt_color_layer_create_if_needed(ob); const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index 7207e6c35d4..dfaa0bd4daa 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -46,7 +46,7 @@ #include <math.h> #include <stdlib.h> -void ED_sculpt_init_transform(struct bContext *C, Object *ob) +void ED_sculpt_init_transform(struct bContext *C, Object *ob, const char *undo_name) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = ob->sculpt; @@ -60,7 +60,7 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob) copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot); copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale); - SCULPT_undo_push_begin(ob, "Transform"); + SCULPT_undo_push_begin_ex(ob, undo_name); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); ss->pivot_rot[3] = 1.0f; @@ -351,11 +351,6 @@ void ED_sculpt_end_transform(struct bContext *C, Object *ob) if (ss->filter_cache) { SCULPT_filter_cache_free(ss); } - /* Force undo push to happen even inside transform operator, since the sculpt - * undo system works separate from regular undo and this is require to properly - * finish an undo step also when canceling. */ - const bool use_nested_undo = true; - SCULPT_undo_push_end_ex(ob, use_nested_undo); SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 04b2b2f04bf..58d62fb2165 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -4,6 +4,29 @@ /** \file * \ingroup edsculpt * Implements the Sculpt Mode tools. + * + * Usage Guide + * =========== + * + * The sculpt undo system is a delta-based system. Each undo step stores + * the difference with the prior one. + * + * To use the sculpt undo system, you must call SCULPT_undo_push_begin + * inside an operator exec or invoke callback (ED_sculpt_undo_geometry_begin + * may be called if you wish to save a non-delta copy of the entire mesh). + * This will initialize the sculpt undo stack and set up an undo step. + * + * At the end of the operator you should call SCULPT_undo_push_end. + * + * SCULPT_undo_push_end and ED_sculpt_undo_geometry_begin both take a + * wmOperatorType as an argument. There are _ex versions that allow a custom + * name; try to avoid using them. These can break the redo panel since it requires + * the undo push have the same name as the calling operator. + * + * Note: Sculpt undo steps are not appended to the global undo stack until + * the operator finishes. We use BKE_undosys_step_push_init_with_type to build + * a tentative undo step with is appended later when the operator ends. + * Operators must have the OPTYPE_UNDO flag set for this to work properly. */ #include <stddef.h> @@ -350,10 +373,11 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode, bool if (unode->maxvert) { for (int i = 0; i < unode->totvert; i++) { - if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != hide_vert[i]) { + const int vert_index = unode->index[i]; + if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != hide_vert[vert_index]) { BLI_BITMAP_FLIP(unode->vert_hidden, i); - hide_vert[unode->index[i]] = !hide_vert[i]; - modified_vertices[unode->index[i]] = true; + hide_vert[vert_index] = !hide_vert[vert_index]; + modified_vertices[vert_index] = true; } } } @@ -879,7 +903,6 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase .modified_hidden_vertices = modified_hidden_vertices, .modified_mask_vertices = modified_mask_vertices, .modified_color_vertices = modified_color_vertices, - }; BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data); BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw); @@ -1142,8 +1165,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt unode->co = MEM_callocN(alloc_size, "SculptUndoNode.co"); usculpt->undo_size += alloc_size; - /* FIXME: Should explain why this is allocated here, to be freed in - * `SCULPT_undo_push_end_ex()`? */ + /* Needed for original data lookup. */ alloc_size = sizeof(*unode->no) * (size_t)allvert; unode->no = MEM_callocN(alloc_size, "SculptUndoNode.no"); usculpt->undo_size += alloc_size; @@ -1546,7 +1568,12 @@ static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr) attr->was_set = true; } -void SCULPT_undo_push_begin(Object *ob, const char *name) +void SCULPT_undo_push_begin(Object *ob, const wmOperator *op) +{ + SCULPT_undo_push_begin_ex(ob, op->type->name); +} + +void SCULPT_undo_push_begin_ex(Object *ob, const char *name) { UndoStack *ustack = ED_undo_stack_get(); @@ -1642,11 +1669,12 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr */ if (!layer) { layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL); - eAttrDomain domain = layer ? BKE_id_attribute_domain(&me->id, layer) : ATTR_DOMAIN_NUM; - - if (layer && ED_geometry_attribute_convert( - me, attr->name, layer->type, domain, attr->type, attr->domain)) { - layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); + if (layer) { + const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); + if (ED_geometry_attribute_convert( + me, attr->name, layer->type, domain, attr->type, attr->domain)) { + layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); + } } } @@ -1834,9 +1862,15 @@ static void sculpt_undosys_step_free(UndoStep *us_p) sculpt_undo_free_list(&us->data.nodes); } -void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name) +void ED_sculpt_undo_geometry_begin(struct Object *ob, const wmOperator *op) +{ + SCULPT_undo_push_begin(ob, op); + SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY); +} + +void ED_sculpt_undo_geometry_begin_ex(struct Object *ob, const char *name) { - SCULPT_undo_push_begin(ob, name); + SCULPT_undo_push_begin_ex(ob, name); SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY); } @@ -1949,7 +1983,7 @@ void ED_sculpt_undo_push_multires_mesh_begin(bContext *C, const char *str) Object *object = CTX_data_active_object(C); - SCULPT_undo_push_begin(object, str); + SCULPT_undo_push_begin_ex(object, str); SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY); geometry_unode->geometry_clear_pbvh = false; diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 14b06f888fe..8b9776cf94d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" #include "BLI_ghash.h" -#include "BLI_math.h" +#include "BLI_math_base_safe.h" #include "BLI_utildefines.h" #include "DNA_brush_types.h" @@ -22,6 +22,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" +#include "BKE_image.h" #include "BKE_mesh_mapping.h" #include "BKE_paint.h" @@ -30,6 +31,7 @@ #include "ED_image.h" #include "ED_mesh.h" #include "ED_screen.h" +#include "ED_uvedit.h" #include "WM_api.h" #include "WM_types.h" @@ -42,6 +44,9 @@ #include "UI_view2d.h" +/* When set, the UV element is on the boundary of the graph. + * i.e. Instead of a 2-dimensional laplace operator, use a 1-dimensional version. + * Visually, UV elements on the graph boundary appear as borders of the UV Island. */ #define MARK_BOUNDARY 1 typedef struct UvAdjacencyElement { @@ -49,16 +54,17 @@ typedef struct UvAdjacencyElement { UvElement *element; /* uv pointer for convenience. Caution, this points to the original UVs! */ float *uv; - /* general use flag (Used to check if Element is boundary here) */ - char flag; + /* Are we on locked in place? */ + bool is_locked; + /* Are we on the boundary? */ + bool is_boundary; } UvAdjacencyElement; typedef struct UvEdge { uint uv1; uint uv2; - /* general use flag - * (Used to check if edge is boundary here, and propagates to adjacency elements) */ - char flag; + /* Are we in the interior? */ + bool is_interior; } UvEdge; typedef struct UVInitialStrokeElement { @@ -90,13 +96,13 @@ typedef struct UvSculptData { * to their coincident UV's */ UvAdjacencyElement *uv; - /* ...Is what it says */ + /* Total number of unique UVs. */ int totalUniqueUvs; /* Edges used for adjacency info, used with laplacian smoothing */ UvEdge *uvedges; - /* need I say more? */ + /* Total number of #UvEdge. */ int totalUvEdges; /* data for initial stroke, used by tools like grab */ @@ -116,8 +122,25 @@ typedef struct UvSculptData { /* store invert flag here */ char invert; + + /* Is constrain to image bounds active? */ + bool constrain_to_bounds; + + /* Base for constrain_to_bounds. */ + float uv_base_offset[2]; } UvSculptData; +static void apply_sculpt_data_constraints(UvSculptData *sculptdata, float uv[2]) +{ + if (!sculptdata->constrain_to_bounds) { + return; + } + float u = sculptdata->uv_base_offset[0]; + float v = sculptdata->uv_base_offset[1]; + uv[0] = clamp_f(uv[0], u, u + 1.0f); + uv[1] = clamp_f(uv[1], v, v + 1.0f); +} + /*********** Improved Laplacian Relaxation Operator ************************/ /* original code by Raul Fernandez Hernandez "farsthary" * * adapted to uv smoothing by Antony Riakiatakis * @@ -170,17 +193,14 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em, } for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - float dist; - /* This is supposed to happen only if "Pin Edges" is on, - * since we have initialization on stroke start. - * If ever uv brushes get their own mode we should check for toolsettings option too. */ - if (sculptdata->uv[i].flag & MARK_BOUNDARY) { + if (sculptdata->uv[i].is_locked) { continue; } sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord); diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { + float dist = dot_v2v2(diff, diff); + if (dist <= radius) { UvElement *element; float strength; strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); @@ -196,6 +216,8 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em, 0.5f * (tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter)); + apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); + for (element = sculptdata->uv[i].element; element; element = element->next) { MLoopUV *luv; BMLoop *l; @@ -214,6 +236,13 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em, MEM_SAFE_FREE(tmp_uvdata); } +/* Legacy version which only does laplacian relaxation. + * Probably a little faster as it caches UvEdges. + * Mostly preserved for comparison with `HC_relaxation_iteration_uv`. + * Once the HC method has been merged into `relaxation_iteration_uv`, + * all the `HC_*` and `laplacian_*` specific functions can probably be removed. + */ + static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, const float mouse_coord[2], @@ -233,11 +262,16 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, /* counting neighbors */ for (i = 0; i < sculptdata->totalUvEdges; i++) { UvEdge *tmpedge = sculptdata->uvedges + i; - tmp_uvdata[tmpedge->uv1].ncounter++; - tmp_uvdata[tmpedge->uv2].ncounter++; - - add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv); - add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv); + bool code1 = sculptdata->uv[sculptdata->uvedges[i].uv1].is_boundary; + bool code2 = sculptdata->uv[sculptdata->uvedges[i].uv2].is_boundary; + if (code1 || (code1 == code2)) { + tmp_uvdata[tmpedge->uv2].ncounter++; + add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv); + } + if (code2 || (code1 == code2)) { + tmp_uvdata[tmpedge->uv1].ncounter++; + add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv); + } } /* Original Laplacian algorithm included removal of normal component of translation. @@ -248,17 +282,14 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, } for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - float dist; - /* This is supposed to happen only if "Pin Edges" is on, - * since we have initialization on stroke start. - * If ever uv brushes get their own mode we should check for toolsettings option too. */ - if (sculptdata->uv[i].flag & MARK_BOUNDARY) { + if (sculptdata->uv[i].is_locked) { continue; } sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord); diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { + float dist = dot_v2v2(diff, diff); + if (dist <= radius) { UvElement *element; float strength; strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); @@ -268,6 +299,8 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * tmp_uvdata[i].p[1]; + apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); + for (element = sculptdata->uv[i].element; element; element = element->next) { MLoopUV *luv; BMLoop *l; @@ -286,6 +319,153 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, MEM_SAFE_FREE(tmp_uvdata); } +static void add_weighted_edge(float (*delta_buf)[3], + const UvElement *storage, + const UvElement *ele_next, + const UvElement *ele_prev, + const MLoopUV *luv_next, + const MLoopUV *luv_prev, + const float weight) +{ + float delta[2]; + sub_v2_v2v2(delta, luv_next->uv, luv_prev->uv); + + bool code1 = (ele_prev->flag & MARK_BOUNDARY); + bool code2 = (ele_next->flag & MARK_BOUNDARY); + if (code1 || (code1 == code2)) { + int index_next = ele_next - storage; + delta_buf[index_next][0] -= delta[0] * weight; + delta_buf[index_next][1] -= delta[1] * weight; + delta_buf[index_next][2] += fabsf(weight); + } + if (code2 || (code1 == code2)) { + int index_prev = ele_prev - storage; + delta_buf[index_prev][0] += delta[0] * weight; + delta_buf[index_prev][1] += delta[1] * weight; + delta_buf[index_prev][2] += fabsf(weight); + } +} + +static float tri_weight_v3(int method, const float *v1, const float *v2, const float *v3) +{ + switch (method) { + case UV_SCULPT_TOOL_RELAX_LAPLACIAN: + case UV_SCULPT_TOOL_RELAX_HC: + return 1.0f; + case UV_SCULPT_TOOL_RELAX_COTAN: + return cotangent_tri_weight_v3(v1, v2, v3); + default: + BLI_assert_unreachable(); + } + return 0.0f; +} + +static void relaxation_iteration_uv(BMEditMesh *em, + UvSculptData *sculptdata, + const float mouse_coord[2], + const float alpha, + const float radius_squared, + const float aspect_ratio, + const int method) +{ + if (method == UV_SCULPT_TOOL_RELAX_HC) { + HC_relaxation_iteration_uv(em, sculptdata, mouse_coord, alpha, radius_squared, aspect_ratio); + return; + } + if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) { + laplacian_relaxation_iteration_uv( + em, sculptdata, mouse_coord, alpha, radius_squared, aspect_ratio); + return; + } + + struct UvElement **head_table = BM_uv_element_map_ensure_head_table(sculptdata->elementMap); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BLI_assert(cd_loop_uv_offset >= 0); + + const int total_uvs = sculptdata->elementMap->total_uvs; + float(*delta_buf)[3] = (float(*)[3])MEM_callocN(total_uvs * sizeof(float[3]), __func__); + + const UvElement *storage = sculptdata->elementMap->storage; + for (int j = 0; j < total_uvs; j++) { + const UvElement *ele_curr = storage + j; + const BMFace *efa = ele_curr->l->f; + const UvElement *ele_next = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->next); + const UvElement *ele_prev = BM_uv_element_get(sculptdata->elementMap, efa, ele_curr->l->prev); + + const float *v_curr_co = ele_curr->l->v->co; + const float *v_prev_co = ele_prev->l->v->co; + const float *v_next_co = ele_next->l->v->co; + + const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(ele_curr->l, cd_loop_uv_offset); + const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(ele_next->l, cd_loop_uv_offset); + const MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(ele_prev->l, cd_loop_uv_offset); + + const UvElement *head_curr = head_table[ele_curr - sculptdata->elementMap->storage]; + const UvElement *head_next = head_table[ele_next - sculptdata->elementMap->storage]; + const UvElement *head_prev = head_table[ele_prev - sculptdata->elementMap->storage]; + + /* If the mesh is triangulated with no boundaries, only one edge is required. */ + const float weight_curr = tri_weight_v3(method, v_curr_co, v_prev_co, v_next_co); + add_weighted_edge(delta_buf, storage, head_next, head_prev, luv_next, luv_prev, weight_curr); + + /* Triangulated with a boundary? We need the incoming edges to solve the boundary. */ + const float weight_prev = tri_weight_v3(method, v_prev_co, v_curr_co, v_next_co); + add_weighted_edge(delta_buf, storage, head_next, head_curr, luv_next, luv_curr, weight_prev); + + if (method == UV_SCULPT_TOOL_RELAX_LAPLACIAN) { + /* Laplacian method has zero weights on virtual edges. */ + continue; + } + + /* Meshes with quads (or other n-gons) need "virtual" edges too. */ + const float weight_next = tri_weight_v3(method, v_next_co, v_curr_co, v_prev_co); + add_weighted_edge(delta_buf, storage, head_prev, head_curr, luv_prev, luv_curr, weight_next); + } + + Brush *brush = BKE_paint_brush(sculptdata->uvsculpt); + for (int i = 0; i < sculptdata->totalUniqueUvs; i++) { + UvAdjacencyElement *adj_el = &sculptdata->uv[i]; + if (adj_el->is_locked) { + continue; /* Locked UVs can't move. */ + } + + /* Is UV within brush's influence? */ + float diff[2]; + sub_v2_v2v2(diff, adj_el->uv, mouse_coord); + diff[1] /= aspect_ratio; + const float dist_squared = len_squared_v2(diff); + if (dist_squared > radius_squared) { + continue; + } + const float strength = alpha * BKE_brush_curve_strength_clamped( + brush, sqrtf(dist_squared), sqrtf(radius_squared)); + + const float *delta_sum = delta_buf[adj_el->element - storage]; + + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(adj_el->element->l, cd_loop_uv_offset); + BLI_assert(adj_el->uv == luv->uv); /* Only true for head. */ + adj_el->uv[0] = luv->uv[0] + strength * safe_divide(delta_sum[0], delta_sum[2]); + adj_el->uv[1] = luv->uv[1] + strength * safe_divide(delta_sum[1], delta_sum[2]); + apply_sculpt_data_constraints(sculptdata, adj_el->uv); + } + + /* Copy UV co-ordinates to all UvElements. */ + UvElement *tail = adj_el->element; + while (tail) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(tail->l, cd_loop_uv_offset); + copy_v2_v2(luv->uv, adj_el->uv); + tail = tail->next; + if (tail && tail->separate) { + break; + } + } + } + + MEM_SAFE_FREE(delta_buf); +} + static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *event, @@ -327,17 +507,15 @@ static void uv_sculpt_stroke_apply(bContext *C, int i; alpha *= invert; for (i = 0; i < sculptdata->totalUniqueUvs; i++) { - float dist, diff[2]; - /* This is supposed to happen only if "Lock Borders" is on, - * since we have initialization on stroke start. - * If ever uv brushes get their own mode we should check for toolsettings option too. */ - if (sculptdata->uv[i].flag & MARK_BOUNDARY) { + if (sculptdata->uv[i].is_locked) { continue; } + float diff[2]; sub_v2_v2v2(diff, sculptdata->uv[i].uv, co); diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { + float dist = dot_v2v2(diff, diff); + if (dist <= radius) { UvElement *element; float strength; strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); @@ -346,6 +524,8 @@ static void uv_sculpt_stroke_apply(bContext *C, sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f; sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f; + apply_sculpt_data_constraints(sculptdata, sculptdata->uv[i].uv); + for (element = sculptdata->uv[i].element; element; element = element->next) { MLoopUV *luv; BMLoop *l; @@ -363,16 +543,11 @@ static void uv_sculpt_stroke_apply(bContext *C, } /* - * Smooth Tool + * Relax Tool */ else if (tool == UV_SCULPT_TOOL_RELAX) { - uint method = toolsettings->uv_relax_method; - if (method == UV_SCULPT_TOOL_RELAX_HC) { - HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio); - } - else { - laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio); - } + relaxation_iteration_uv( + em, sculptdata, co, alpha, radius, aspectRatio, toolsettings->uv_relax_method); } /* @@ -392,6 +567,8 @@ static void uv_sculpt_stroke_apply(bContext *C, sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1]; + apply_sculpt_data_constraints(sculptdata, sculptdata->uv[uvindex].uv); + for (element = sculptdata->uv[uvindex].element; element; element = element->next) { MLoopUV *luv; BMLoop *l; @@ -405,11 +582,18 @@ static void uv_sculpt_stroke_apply(bContext *C, copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv); } } + if (sima->flag & SI_LIVE_UNWRAP) { + ED_uvedit_live_unwrap_re_solve(); + } } } static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op) { + SpaceImage *sima = CTX_wm_space_image(C); + if (sima->flag & SI_LIVE_UNWRAP) { + ED_uvedit_live_unwrap_end(false); + } UvSculptData *data = op->customdata; if (data->timer) { WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer); @@ -454,6 +638,17 @@ static bool uv_edge_compare(const void *a, const void *b) return true; } +static void set_element_flag(UvElement *element, const int flag) +{ + while (element) { + element->flag |= flag; + element = element->next; + if (!element || element->separate) { + break; + } + } +} + static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); @@ -481,8 +676,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS); int island_index = 0; - /* Holds, for each UvElement in elementMap, an index of its unique UV. */ - int *uniqueUv; data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ? UV_SCULPT_TOOL_RELAX : ts->uvsculpt->paint.brush->uv_sculpt_tool; @@ -522,12 +715,13 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm } /* Allocate the unique uv buffers */ - 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"); + data->uv = MEM_callocN(sizeof(*data->uv) * unique_uvs, "uv_brush_unique_uvs"); + /* Holds, for each UvElement in elementMap, an index of its unique UV. */ + int *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->total_uvs, "uv_brush_all_edges"); + edges = MEM_callocN(sizeof(*edges) * data->elementMap->total_uvs, "uv_brush_all_edges"); if (!data->uv || !uniqueUv || !edgeHash || !edges) { MEM_SAFE_FREE(edges); MEM_SAFE_FREE(uniqueUv); @@ -559,8 +753,12 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm counter++; data->uv[counter].element = element; - data->uv[counter].flag = 0; data->uv[counter].uv = luv->uv; + if (data->tool != UV_SCULPT_TOOL_GRAB) { + if (luv->flag & MLOOPUV_PINNED) { + data->uv[counter].is_locked = true; + } + } } /* Pointer arithmetic to the rescue, as always :). */ uniqueUv[element - data->elementMap->storage] = counter; @@ -576,7 +774,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm data->elementMap, efa, l, island_index, do_island_optimization); int offset2, itmp2 = uv_element_offset_from_face_get( data->elementMap, efa, l->next, island_index, do_island_optimization); - char *flag; /* Skip edge if not found(unlikely) or not on valid island */ if (itmp1 == -1 || itmp2 == -1) { @@ -586,7 +783,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm offset1 = uniqueUv[itmp1]; offset2 = uniqueUv[itmp2]; - edges[counter].flag = 0; /* Using an order policy, sort UV's according to address space. * This avoids having two different UvEdges with the same UV's on different positions. */ if (offset1 < offset2) { @@ -597,15 +793,13 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm edges[counter].uv1 = offset2; edges[counter].uv2 = offset1; } - /* Hack! Set the value of the key to its flag. - * Now we can set the flag when an edge exists twice :) */ - flag = BLI_ghash_lookup(edgeHash, &edges[counter]); - if (flag) { - *flag = 1; + UvEdge *prev_edge = BLI_ghash_lookup(edgeHash, &edges[counter]); + if (prev_edge) { + prev_edge->is_interior = true; + edges[counter].is_interior = true; } else { - /* Hack mentioned */ - BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag); + BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter]); } counter++; } @@ -614,7 +808,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm MEM_SAFE_FREE(uniqueUv); /* Allocate connectivity data, we allocate edges once */ - data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash), + data->uvedges = MEM_callocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash), "uv_brush_edge_connectivity_data"); if (!data->uvedges) { BLI_ghash_free(edgeHash, NULL, NULL); @@ -637,20 +831,27 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm MEM_SAFE_FREE(edges); /* transfer boundary edge property to UV's */ - if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) { - 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; + for (int i = 0; i < data->totalUvEdges; i++) { + if (!data->uvedges[i].is_interior) { + data->uv[data->uvedges[i].uv1].is_boundary = true; + data->uv[data->uvedges[i].uv2].is_boundary = true; + if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) { + data->uv[data->uvedges[i].uv1].is_locked = true; + data->uv[data->uvedges[i].uv2].is_locked = true; } + set_element_flag(data->uv[data->uvedges[i].uv1].element, MARK_BOUNDARY); + set_element_flag(data->uv[data->uvedges[i].uv2].element, MARK_BOUNDARY); } } + SpaceImage *sima = CTX_wm_space_image(C); + data->constrain_to_bounds = (sima->flag & SI_CLIP_UV); + BKE_image_find_nearest_tile_with_offset(sima->image, co, data->uv_base_offset); + /* Allocate initial selection for grab tool */ if (data->tool == UV_SCULPT_TOOL_GRAB) { float radius, radius_root; UvSculptData *sculptdata = (UvSculptData *)op->customdata; - SpaceImage *sima; int width, height; float aspectRatio; float alpha, zoomx, zoomy; @@ -659,7 +860,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm alpha = BKE_brush_alpha_get(scene, brush); radius = BKE_brush_size_get(scene, brush); - sima = CTX_wm_space_image(C); ED_space_image_get_size(sima, &width, &height); ED_space_image_get_zoom(sima, region, &zoomx, &zoomy); @@ -684,16 +884,16 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm copy_v2_v2(data->initial_stroke->init_coord, co); counter = 0; - for (int i = 0; i < data->totalUniqueUvs; i++) { - float dist, diff[2]; - if (data->uv[i].flag & MARK_BOUNDARY) { + if (data->uv[i].is_locked) { continue; } + float diff[2]; sub_v2_v2v2(diff, data->uv[i].uv, co); diff[1] /= aspectRatio; - if ((dist = dot_v2v2(diff, diff)) <= radius) { + float dist = dot_v2v2(diff, diff); + if (dist <= radius) { float strength; strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root); @@ -705,6 +905,9 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm } data->initial_stroke->totalInitialSelected = counter; + if (sima->flag & SI_LIVE_UNWRAP) { + ED_uvedit_live_unwrap_begin(scene, obedit); + } } } diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt index 841bd5cf91b..b9e27c4de49 100644 --- a/source/blender/editors/space_action/CMakeLists.txt +++ b/source/blender/editors/space_action/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index b509eae8ea6..d0ad510f5cf 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -9,7 +9,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../bmesh # RNA_prototypes.h diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt index eddf1780d8b..8cb5299df6d 100644 --- a/source/blender/editors/space_clip/CMakeLists.txt +++ b/source/blender/editors/space_clip/CMakeLists.txt @@ -13,7 +13,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # dna_type_offsets.h diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index ce6409a7784..4cf2e6e15e8 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -811,8 +811,8 @@ static void clip_main_region_draw(const bContext *C, ARegion *region) int width, height; bool show_cursor = false; - /* if tracking is in progress, we should synchronize framenr from clipuser - * so latest tracked frame would be shown */ + /* If tracking is in progress, we should synchronize the frame from the clip-user + * (#MovieClipUser.framenr) so latest tracked frame would be shown. */ if (clip && clip->tracking_context) { BKE_autotrack_context_sync_user(clip->tracking_context, &sc->user); } diff --git a/source/blender/editors/space_console/CMakeLists.txt b/source/blender/editors/space_console/CMakeLists.txt index 841c21f12e7..345ab8b0970 100644 --- a/source/blender/editors/space_console/CMakeLists.txt +++ b/source/blender/editors/space_console/CMakeLists.txt @@ -9,7 +9,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index b8c28e354da..792b9120e7b 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -15,7 +15,6 @@ set(INC ../../render ../../windowmanager ../../../../intern/atomic - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 310c688383b..30e13235f45 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -443,7 +443,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, if (STREQ(tfsm->path, fsm_iter->path)) { icon = tfsm->icon; if (tfsm->name[0] && (!name || !name[0])) { - name = tfsm->name; + name = DATA_(tfsm->name); } break; } diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt index ebcbf59be5f..39878debc39 100644 --- a/source/blender/editors/space_graph/CMakeLists.txt +++ b/source/blender/editors/space_graph/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index c6a1a6a77b4..4284d0f76af 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -16,7 +16,6 @@ set(INC ../../render ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc # 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 2109d3f9701..bc367a99d6b 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -922,7 +922,7 @@ void uiTemplateImage(uiLayout *layout, } } - /* Colorspace and alpha */ + /* Color-space and alpha. */ { uiItemS(layout); @@ -1212,8 +1212,8 @@ 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); + eGPUTextureFormat texture_format = IMB_gpu_get_texture_format( + ibuf, ima->flag & IMA_HIGH_BITDEPTH, ibuf->planes >= 8); const char *texture_format_description = GPU_texture_format_description(texture_format); ofs += BLI_snprintf_rlen(str + ofs, len - ofs, TIP_(", %s"), texture_format_description); diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index febb025f5bd..4e9df2b93b0 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -14,7 +14,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index e41ff02254b..450769d7225 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -161,42 +161,6 @@ static void stats_object(Object *ob, stats->totlampsel++; } break; - case OB_SURF: - case OB_CURVES_LEGACY: - case OB_FONT: { - const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob); - if ((me_eval != nullptr) && !BLI_gset_add(objects_gset, (void *)me_eval)) { - break; - } - - if (stats_mesheval(me_eval, is_selected, stats)) { - break; - } - ATTR_FALLTHROUGH; /* Fall-through to displist. */ - } - case OB_MBALL: { - int totv = 0, totf = 0, tottri = 0; - - if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) { - /* NOTE: We only get the same curve_cache for instances of the same curve/font/... - * For simple linked duplicated objects, each has its own dispList. */ - if (!BLI_gset_add(objects_gset, ob->runtime.curve_cache)) { - break; - } - - BKE_displist_count(&ob->runtime.curve_cache->disp, &totv, &totf, &tottri); - } - - stats->totvert += totv; - stats->totface += totf; - stats->tottri += tottri; - - if (is_selected) { - stats->totvertsel += totv; - stats->totfacesel += totf; - } - break; - } case OB_GPENCIL: { if (is_selected) { bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt index 85a2c3fd0a1..e6995085dbe 100644 --- a/source/blender/editors/space_nla/CMakeLists.txt +++ b/source/blender/editors/space_nla/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 26fddda8c22..8a1d47eaa8d 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -17,7 +17,6 @@ set(INC ../../nodes ../../render ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc index b9bee3ed15e..4f7497b5f49 100644 --- a/source/blender/editors/space_node/node_context_path.cc +++ b/source/blender/editors/space_node/node_context_path.cc @@ -28,27 +28,26 @@ #include "node_intern.hh" -struct Curve; -struct Light; struct Material; -struct Mesh; -struct World; namespace blender::ed::space_node { static void context_path_add_object_data(Vector<ui::ContextPathItem> &path, Object &object) { - if (object.type == OB_MESH && object.data) { - Mesh *mesh = (Mesh *)object.data; - ui::context_path_add_generic(path, RNA_Mesh, mesh); + if (!object.data) { + return; } - if (object.type == OB_LAMP && object.data) { - Light *light = (Light *)object.data; - ui::context_path_add_generic(path, RNA_Light, light); + if (object.type == OB_MESH) { + ui::context_path_add_generic(path, RNA_Mesh, object.data); } - if (ELEM(object.type, OB_CURVES_LEGACY, OB_FONT, OB_SURF) && object.data) { - Curve *curve = (Curve *)object.data; - ui::context_path_add_generic(path, RNA_Curve, curve); + else if (object.type == OB_CURVES) { + ui::context_path_add_generic(path, RNA_Curves, object.data); + } + else if (object.type == OB_LAMP) { + ui::context_path_add_generic(path, RNA_Light, object.data); + } + else if (ELEM(object.type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { + ui::context_path_add_generic(path, RNA_Curve, object.data); } } @@ -71,8 +70,7 @@ static void get_context_path_node_shader(const bContext &C, Scene *scene = CTX_data_scene(&C); ui::context_path_add_generic(path, RNA_Scene, scene); if (scene != nullptr) { - World *world = scene->world; - ui::context_path_add_generic(path, RNA_World, world); + ui::context_path_add_generic(path, RNA_World, scene->world); } /* Skip the base node tree here, because the world contains a node tree already. */ context_path_add_node_tree_and_node_groups(snode, path, true); @@ -95,8 +93,7 @@ static void get_context_path_node_shader(const bContext &C, Scene *scene = CTX_data_scene(&C); ui::context_path_add_generic(path, RNA_Scene, scene); if (scene != nullptr) { - World *world = scene->world; - ui::context_path_add_generic(path, RNA_World, world); + ui::context_path_add_generic(path, RNA_World, scene->world); } } #ifdef WITH_FREESTYLE diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index c74cd58d8fb..2cee7c4984a 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -663,7 +663,9 @@ static void node_draw_mute_line(const bContext &C, GPU_blend(GPU_BLEND_ALPHA); LISTBASE_FOREACH (const bNodeLink *, link, &node.internal_links) { - node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE, false); + if (!nodeLinkIsHidden(link)) { + node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE, false); + } } GPU_blend(GPU_BLEND_NONE); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 0b1f2037292..36836ed3691 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -729,19 +729,26 @@ void ED_node_set_active( } } - /* Sync to Image Editor. */ + /* Sync to Image Editor under the following conditions: + * - current image is not pinned + * - current image is not a Render Result or ViewerNode (want to keep looking at these) */ Image *image = (Image *)node->id; wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - if (sl->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sl; - if (!sima->pin) { - ED_space_image_set(bmain, sima, image, true); - } + if (sl->spacetype != SPACE_IMAGE) { + continue; + } + SpaceImage *sima = (SpaceImage *)sl; + if (sima->pin) { + continue; + } + if (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) { + continue; } + ED_space_image_set(bmain, sima, image, true); } } } @@ -913,15 +920,24 @@ static void edit_node_properties_get( /** \name Node Generic * \{ */ -/* is rct in visible part of node? */ -static bNode *visible_node(SpaceNode &snode, const rctf &rct) +static bool socket_is_occluded(const bNodeSocket &sock, + const bNode &node_the_socket_belongs_to, + const SpaceNode &snode) { LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) { - if (BLI_rctf_isect(&node->totr, &rct, nullptr)) { - return node; + if (node == &node_the_socket_belongs_to) { + /* Nodes after this one are underneath and can't occlude the socket. */ + return false; + } + + rctf socket_hitbox; + const float socket_hitbox_radius = NODE_SOCKSIZE - 0.1f * U.widget_unit; + BLI_rctf_init_pt_radius(&socket_hitbox, float2(sock.locx, sock.locy), socket_hitbox_radius); + if (BLI_rctf_inside_rctf(&node->totr, &socket_hitbox)) { + return true; } } - return nullptr; + return false; } /** \} */ @@ -1216,10 +1232,8 @@ bool node_find_indicated_socket(SpaceNode &snode, *sockp = nullptr; /* check if we click in a socket */ - LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) { BLI_rctf_init_pt_radius(&rect, cursor, size_sock_padded); - rctf node_visible; - BLI_rctf_init_pt_radius(&node_visible, cursor, size_sock_padded); if (!(node->flag & NODE_HIDDEN)) { /* extra padding inside and out - allow dragging on the text areas too */ @@ -1238,7 +1252,7 @@ bool node_find_indicated_socket(SpaceNode &snode, if (!nodeSocketIsHidden(sock)) { if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) { if (cursor_isect_multi_input_socket(cursor, *sock)) { - if (node == visible_node(snode, node_visible)) { + if (!socket_is_occluded(*sock, *node, snode)) { *nodep = node; *sockp = sock; return true; @@ -1246,7 +1260,7 @@ bool node_find_indicated_socket(SpaceNode &snode, } } else if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - if (node == visible_node(snode, node_visible)) { + if (!socket_is_occluded(*sock, *node, snode)) { *nodep = node; *sockp = sock; return true; @@ -1259,7 +1273,7 @@ bool node_find_indicated_socket(SpaceNode &snode, LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (!nodeSocketIsHidden(sock)) { if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - if (node == visible_node(snode, node_visible)) { + if (!socket_is_occluded(*sock, *node, snode)) { *nodep = node; *sockp = sock; return true; diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index b9f79303a06..d29028dad63 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -13,7 +13,6 @@ set(INC ../../sequencer ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_outliner/outliner_collections.cc b/source/blender/editors/space_outliner/outliner_collections.cc index 02d54e4f702..836ad3e3f93 100644 --- a/source/blender/editors/space_outliner/outliner_collections.cc +++ b/source/blender/editors/space_outliner/outliner_collections.cc @@ -38,6 +38,8 @@ #include "outliner_intern.hh" /* own include */ +namespace blender::ed::outliner { + /* -------------------------------------------------------------------- */ /** \name Utility API * \{ */ @@ -122,8 +124,12 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom return TRAVERSE_CONTINUE; } +} // namespace blender::ed::outliner + void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects) { + using namespace blender::ed::outliner; + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); struct IDsSelectedData data = {{nullptr}}; outliner_tree_traverse(space_outliner, @@ -140,12 +146,16 @@ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects) BLI_freelistN(&data.selected_array); } +namespace blender::ed::outliner { + /** \} */ /* -------------------------------------------------------------------- */ /** \name Poll Functions * \{ */ +} // namespace blender::ed::outliner + bool ED_outliner_collections_editor_poll(bContext *C) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); @@ -153,6 +163,8 @@ bool ED_outliner_collections_editor_poll(bContext *C) ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES); } +namespace blender::ed::outliner { + static bool outliner_view_layer_collections_editor_poll(bContext *C) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); @@ -1636,3 +1648,5 @@ void OUTLINER_OT_collection_color_tag_set(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_context.cc b/source/blender/editors/space_outliner/outliner_context.cc index 1a804cb58b8..001bda57fa2 100644 --- a/source/blender/editors/space_outliner/outliner_context.cc +++ b/source/blender/editors/space_outliner/outliner_context.cc @@ -14,7 +14,7 @@ #include "outliner_intern.hh" #include "tree/tree_iterator.hh" -using namespace blender::ed::outliner; +namespace blender::ed::outliner { static void outliner_context_selected_ids_recursive(const SpaceOutliner &space_outliner, bContextDataResult *result) @@ -55,3 +55,5 @@ int /*eContextResult*/ outliner_context(const bContext *C, return CTX_RESULT_MEMBER_NOT_FOUND; } + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc index 2fa512b4006..81224fb6a2b 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.cc +++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc @@ -45,6 +45,8 @@ #include "outliner_intern.hh" +namespace blender::ed::outliner { + static Collection *collection_parent_from_ID(ID *id); /* -------------------------------------------------------------------- */ @@ -1592,3 +1594,5 @@ void outliner_dropboxes(void) } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index e67eab4e432..7004f4cec61 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -74,8 +74,7 @@ #include "tree/tree_element_rna.hh" #include "tree/tree_iterator.hh" -using namespace blender; -using namespace blender::ed::outliner; +namespace blender::ed::outliner { /* -------------------------------------------------------------------- */ /** \name Tree Size Functions @@ -701,7 +700,6 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) if (ob->type == OB_MBALL) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); break; } default: @@ -732,6 +730,8 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) lib->id.tag &= ~LIB_TAG_MISSING; } } + + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); } else { switch (tselem->type) { @@ -740,6 +740,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) 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); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); break; } case TSE_NLA_ACTION: { @@ -747,6 +748,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BKE_main_namemap_remove_name(bmain, &act->id, oldname); BLI_libblock_ensure_unique_name(bmain, act->id.name); WM_msg_publish_rna_prop(mbus, &act->id, &act->id, ID, name); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); break; } case TSE_EBONE: { @@ -761,6 +763,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) ED_armature_bone_rename(bmain, arm, oldname, newname); WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); } break; } @@ -782,6 +785,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) ED_armature_bone_rename(bmain, arm, oldname, newname); WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); break; } case TSE_POSE_CHANNEL: { @@ -804,6 +808,8 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) 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); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); break; } case TSE_POSEGRP: { @@ -818,6 +824,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) sizeof(grp->name)); WM_msg_publish_rna_prop(mbus, &ob->id, grp, ActionGroup, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); break; } case TSE_GP_LAYER: { @@ -834,6 +841,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) WM_msg_publish_rna_prop(mbus, &gpd->id, gpl, GPencilLayer, info); DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); break; } case TSE_R_LAYER: { @@ -849,6 +857,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BKE_view_layer_rename(bmain, scene, view_layer, newname); WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name); WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); break; } case TSE_LAYER_COLLECTION: { @@ -858,6 +867,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BLI_libblock_ensure_unique_name(bmain, collection->id.name); WM_msg_publish_rna_prop(mbus, &collection->id, &collection->id, ID, name); WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr); + DEG_id_tag_update(tselem->id, ID_RECALC_COPY_ON_WRITE); break; } } @@ -3325,7 +3335,7 @@ static void outliner_draw_tree_element(bContext *C, /* Scene collection in view layer can't expand/collapse. */ } else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) || - (te->flag & TE_LAZY_CLOSED)) { + (te->flag & TE_PRETEND_HAS_CHILDREN)) { /* Open/close icon, only when sub-levels, except for scene. */ int icon_x = startx; @@ -3983,3 +3993,5 @@ void draw_outliner(const bContext *C) } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc index f22db5d20fc..712684624f7 100644 --- a/source/blender/editors/space_outliner/outliner_edit.cc +++ b/source/blender/editors/space_outliner/outliner_edit.cc @@ -65,6 +65,8 @@ using namespace blender::ed::outliner; +namespace blender::ed::outliner { + static void outliner_show_active(SpaceOutliner *space_outliner, ARegion *region, TreeElement *te, @@ -144,14 +146,10 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot) /** \name Toggle Open/Closed Operator * \{ */ -void outliner_item_openclose(SpaceOutliner *space_outliner, - TreeElement *te, - bool open, - bool toggle_all) +void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all) { - /* Prevent opening leaf elements in the tree unless in the Data API display mode because in that - * mode subtrees are empty unless expanded. */ - if (space_outliner->outlinevis != SO_DATA_API && BLI_listbase_is_empty(&te->subtree)) { + /* Only allow opening elements with children. */ + if (!(te->flag & TE_PRETEND_HAS_CHILDREN) && BLI_listbase_is_empty(&te->subtree)) { return; } @@ -198,7 +196,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv /* Only toggle openclose on the same level as the first clicked element */ if (te->xs == data->x_location) { - outliner_item_openclose(space_outliner, te, data->open, false); + outliner_item_openclose(te, data->open, false); outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region); } @@ -242,7 +240,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE const bool open = (tselem->flag & TSE_CLOSED) || (toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1))); - outliner_item_openclose(space_outliner, te, open, toggle_all); + outliner_item_openclose(te, open, toggle_all); outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region); /* Only toggle once for single click toggling */ @@ -1410,129 +1408,6 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot) /** \} */ -#if 0 /* TODO: probably obsolete now with filtering? */ - -/* -------------------------------------------------------------------- */ -/** \name Search - * \{ */ - - -/* find next element that has this name */ -static TreeElement *outliner_find_name( - SpaceOutliner *space_outliner, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound) -{ - TreeElement *te, *tes; - - for (te = lb->first; te; te = te->next) { - int found = outliner_filter_has_name(te, name, flags); - - if (found) { - /* name is right, but is element the previous one? */ - if (prev) { - if ((te != prev) && (*prevFound)) { - return te; - } - if (te == prev) { - *prevFound = 1; - } - } - else { - return te; - } - } - - tes = outliner_find_name(space_outliner, &te->subtree, name, flags, prev, prevFound); - if (tes) { - return tes; - } - } - - /* nothing valid found */ - return nullptr; -} - -static void outliner_find_panel( - Scene *UNUSED(scene), ARegion *region, SpaceOutliner *space_outliner, int again, int flags) -{ - ReportList *reports = nullptr; /* CTX_wm_reports(C); */ - TreeElement *te = nullptr; - TreeElement *last_find; - TreeStoreElem *tselem; - int ytop, xdelta, prevFound = 0; - char name[sizeof(space_outliner->search_string)]; - - /* get last found tree-element based on stored search_tse */ - last_find = outliner_find_tse(space_outliner, &space_outliner->search_tse); - - /* determine which type of search to do */ - if (again && last_find) { - /* no popup panel - previous + user wanted to search for next after previous */ - BLI_strncpy(name, space_outliner->search_string, sizeof(name)); - flags = space_outliner->search_flags; - - /* try to find matching element */ - te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound); - if (te == nullptr) { - /* no more matches after previous, start from beginning again */ - prevFound = 1; - te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound); - } - } - else { - /* pop up panel - no previous, or user didn't want search after previous */ - name[0] = '\0'; - // XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { - // te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, nullptr, &prevFound); - // } - // else return; XXX RETURN! XXX - } - - /* do selection and reveal */ - if (te) { - tselem = TREESTORE(te); - if (tselem) { - /* expand branches so that it will be visible, we need to get correct coordinates */ - if (outliner_open_back(space_outliner, te)) { - outliner_set_coordinates(region, space_outliner); - } - - /* deselect all visible, and select found element */ - outliner_flag_set(space_outliner, &space_outliner->tree, TSE_SELECTED, 0); - tselem->flag |= TSE_SELECTED; - - /* Make `te->ys` center of view. */ - ytop = (int)(te->ys + BLI_rctf_size_y(®ion->v2d.mask) / 2); - if (ytop > 0) { - ytop = 0; - } - region->v2d.cur.ymax = (float)ytop; - region->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(®ion->v2d.mask)); - - /* Make `te->xs` ==> `te->xend` center of view. */ - xdelta = (int)(te->xs - region->v2d.cur.xmin); - region->v2d.cur.xmin += xdelta; - region->v2d.cur.xmax += xdelta; - - /* store selection */ - space_outliner->search_tse = *tselem; - - BLI_strncpy(space_outliner->search_string, name, sizeof(space_outliner->search_string)); - space_outliner->search_flags = flags; - - /* redraw */ - ED_region_tag_redraw_no_rebuild(region); - } - } - else { - /* no tree-element found */ - BKE_reportf(reports, RPT_WARNING, "Not found: %s", name); - } -} - -/** \} */ - -#endif /* if 0 */ - /* -------------------------------------------------------------------- */ /** \name Show One Level Operator * \{ */ @@ -2357,3 +2232,5 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh index 5362782dd84..47b3dbe6152 100644 --- a/source/blender/editors/space_outliner/outliner_intern.hh +++ b/source/blender/editors/space_outliner/outliner_intern.hh @@ -14,10 +14,6 @@ /* Needed for `tree_element_cast()`. */ #include "tree/tree_element.hh" -#ifdef __cplusplus -extern "C" { -#endif - /* internal exports only */ struct ARegion; @@ -27,7 +23,6 @@ struct ListBase; struct Main; struct Object; struct Scene; -struct TreeElement; struct TreeStoreElem; struct ViewLayer; struct bContext; @@ -37,47 +32,52 @@ struct View2D; struct wmKeyConfig; struct wmOperatorType; +namespace blender::bke::outliner::treehash { +class TreeHash; +} + namespace blender::ed::outliner { + class AbstractTreeDisplay; class AbstractTreeElement; -} // namespace blender::ed::outliner -namespace outliner = blender::ed::outliner; +namespace treehash = blender::bke::outliner::treehash; + +struct TreeElement; struct SpaceOutliner_Runtime { /** Object to create and manage the tree for a specific display type (View Layers, Scenes, * Blender File, etc.). */ - std::unique_ptr<outliner::AbstractTreeDisplay> tree_display; + std::unique_ptr<AbstractTreeDisplay> tree_display; - /** Pointers to tree-store elements, grouped by `(id, type, nr)` - * in hash-table for faster searching. */ - struct GHash *treehash; + /* Hash table for tree-store elements, using `(id, type, index)` as key. */ + std::unique_ptr<treehash::TreeHash> tree_hash; SpaceOutliner_Runtime() = default; /** Used for copying runtime data to a duplicated space. */ SpaceOutliner_Runtime(const SpaceOutliner_Runtime &); - ~SpaceOutliner_Runtime(); + ~SpaceOutliner_Runtime() = default; }; -typedef enum TreeElementInsertType { +enum TreeElementInsertType { TE_INSERT_BEFORE, TE_INSERT_AFTER, TE_INSERT_INTO, -} TreeElementInsertType; +}; -typedef enum TreeTraversalAction { +enum TreeTraversalAction { /** Continue traversal regularly, don't skip children. */ TRAVERSE_CONTINUE = 0, /** Stop traversal. */ TRAVERSE_BREAK, /** Continue traversal, but skip children of traversed element. */ TRAVERSE_SKIP_CHILDS, -} TreeTraversalAction; +}; -typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata); +typedef TreeTraversalAction (*TreeTraversalFunc)(TreeElement *te, void *customdata); -typedef struct TreeElement { - struct TreeElement *next, *prev, *parent; +struct TreeElement { + TreeElement *next, *prev, *parent; /** * The new inheritance based representation of the element (a derived type of base @@ -85,7 +85,7 @@ typedef struct TreeElement { * be moved to it and operations based on the type should become virtual methods of the class * hierarchy. */ - std::unique_ptr<outliner::AbstractTreeElement> abstract_element; + std::unique_ptr<AbstractTreeElement> abstract_element; ListBase subtree; int xs, ys; /* Do selection. */ @@ -96,12 +96,12 @@ typedef struct TreeElement { short xend; /* Width of item display, for select. */ const char *name; void *directdata; /* Armature Bones, Base, ... */ -} TreeElement; +}; -typedef struct TreeElementIcon { +struct TreeElementIcon { struct ID *drag_id, *drag_parent; int icon; -} TreeElementIcon; +}; #define TREESTORE_ID_TYPE(_id) \ (ELEM(GS((_id)->name), \ @@ -153,7 +153,10 @@ enum { /* Closed items display their children as icon within the row. TE_ICONROW is for * these child-items that are visible but only within the row of the closed parent. */ TE_ICONROW = (1 << 1), - TE_LAZY_CLOSED = (1 << 2), + /** Treat the element as if it had children, e.g. draw an icon to un-collapse it, even if it + * doesn't. Used where children are lazy-built only if the parent isn't collapsed (see + * #AbstractTreeDisplay::is_lazy_built()). */ + TE_PRETEND_HAS_CHILDREN = (1 << 2), TE_FREE_NAME = (1 << 3), TE_DRAGGING = (1 << 4), TE_CHILD_NOT_IN_COLLECTION = (1 << 6), @@ -165,17 +168,17 @@ enum { /* button events */ #define OL_NAMEBUTTON 1 -typedef enum { +enum eOLDrawState { OL_DRAWSEL_NONE = 0, /* inactive (regular black text) */ OL_DRAWSEL_NORMAL = 1, /* active object (draws white text) */ OL_DRAWSEL_ACTIVE = 2, /* active obdata (draws a circle around the icon) */ -} eOLDrawState; +}; -typedef enum { +enum eOLSetState { OL_SETSEL_NONE = 0, /* don't change the selection state */ OL_SETSEL_NORMAL = 1, /* select the item */ OL_SETSEL_EXTEND = 2, /* select the item and extend (also toggles selection) */ -} eOLSetState; +}; /* get TreeStoreElem associated with a TreeElement * < a: (TreeElement) tree element to find stored element for @@ -225,7 +228,7 @@ typedef enum { * Container to avoid passing around these variables to many functions. * Also so we can have one place to assign these variables. */ -typedef struct TreeViewContext { +struct TreeViewContext { /* Scene level. */ struct Scene *scene; struct ViewLayer *view_layer; @@ -238,16 +241,16 @@ typedef struct TreeViewContext { * The pose object may not be the active object (when in weight paint mode). * Checking this in draw loops isn't efficient, so set only once. */ Object *ob_pose; -} TreeViewContext; +}; -typedef enum TreeItemSelectAction { +enum TreeItemSelectAction { OL_ITEM_DESELECT = 0, /* Deselect the item */ OL_ITEM_SELECT = (1 << 0), /* Select the item */ OL_ITEM_SELECT_DATA = (1 << 1), /* Select object data */ OL_ITEM_ACTIVATE = (1 << 2), /* Activate the item */ OL_ITEM_EXTEND = (1 << 3), /* Extend the current selection */ OL_ITEM_RECURSIVE = (1 << 4), /* Select recursively */ -} TreeItemSelectAction; +}; /* outliner_tree.c ----------------------------------------------- */ @@ -270,24 +273,19 @@ void outliner_build_tree(struct Main *mainvar, struct SpaceOutliner *space_outliner, struct ARegion *region); -struct TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, - struct Collection *collection, - TreeElement *ten); +TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, + struct Collection *collection, + TreeElement *ten); bool outliner_requires_rebuild_on_select_or_active_change( const struct SpaceOutliner *space_outliner); -/** - * Check if a display mode needs a full rebuild if the open/collapsed state changes. - * Element types in these modes don't actually add children if collapsed, so the rebuild is needed. - */ -bool outliner_requires_rebuild_on_open_change(const struct SpaceOutliner *space_outliner); typedef struct IDsSelectedData { struct ListBase selected_array; } IDsSelectedData; -TreeTraversalAction outliner_find_selected_collections(struct TreeElement *te, void *customdata); -TreeTraversalAction outliner_find_selected_objects(struct TreeElement *te, void *customdata); +TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata); +TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata); /* outliner_draw.c ---------------------------------------------- */ @@ -349,7 +347,7 @@ struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_ */ void outliner_item_select(struct bContext *C, struct SpaceOutliner *space_outliner, - struct TreeElement *te, + TreeElement *te, short select_flag); /** @@ -379,7 +377,7 @@ void outliner_item_mode_toggle(struct bContext *C, typedef void (*outliner_operation_fn)(struct bContext *C, struct ReportList *, struct Scene *scene, - struct TreeElement *, + TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *); @@ -408,12 +406,10 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, int curlevel); * Set or unset \a flag for all outliner elements in \a lb and sub-trees. * \return if any flag was modified. */ -extern "C++" { bool outliner_flag_set(const SpaceOutliner &space_outliner, short flag, short set); bool outliner_flag_set(const ListBase &lb, short flag, short set); bool outliner_flag_flip(const SpaceOutliner &space_outliner, short flag); bool outliner_flag_flip(const ListBase &lb, short flag); -} void item_rename_fn(struct bContext *C, struct ReportList *reports, @@ -425,14 +421,14 @@ void item_rename_fn(struct bContext *C, void lib_relocate_fn(struct bContext *C, struct ReportList *reports, struct Scene *scene, - struct TreeElement *te, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); void lib_reload_fn(struct bContext *C, struct ReportList *reports, struct Scene *scene, - struct TreeElement *te, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); @@ -440,14 +436,14 @@ void lib_reload_fn(struct bContext *C, void id_delete_tag_fn(struct bContext *C, struct ReportList *reports, struct Scene *scene, - struct TreeElement *te, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); void id_remap_fn(struct bContext *C, struct ReportList *reports, struct Scene *scene, - struct TreeElement *te, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); @@ -461,10 +457,7 @@ void outliner_set_coordinates(const struct ARegion *region, /** * Open or close a tree element, optionally toggling all children recursively. */ -void outliner_item_openclose(struct SpaceOutliner *space_outliner, - TreeElement *te, - bool open, - bool toggle_all); +void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all); /* outliner_dragdrop.c */ @@ -612,10 +605,6 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner, bool *r_is_merged_icon, bool *r_is_over_icon); /** - * `tse` is not in the tree-store, we use its contents to find a match. - */ -TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse); -/** * Find specific item from the trees-tore. */ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem); @@ -691,12 +680,6 @@ int outliner_context(const struct bContext *C, const char *member, struct bContextDataResult *result); -#ifdef __cplusplus -} -#endif - -namespace blender::ed::outliner { - /** * Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible. * \return nullptr if the tree-element doesn't match the requested type \a TreeElementT or the diff --git a/source/blender/editors/space_outliner/outliner_ops.cc b/source/blender/editors/space_outliner/outliner_ops.cc index b384c41aa69..cf9c4834667 100644 --- a/source/blender/editors/space_outliner/outliner_ops.cc +++ b/source/blender/editors/space_outliner/outliner_ops.cc @@ -11,6 +11,7 @@ #include "outliner_intern.hh" +namespace blender::ed::outliner { /* -------------------------------------------------------------------- */ /** \name Registration * \{ */ @@ -103,3 +104,5 @@ void outliner_keymap(wmKeyConfig *keyconf) } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_query.cc b/source/blender/editors/space_outliner/outliner_query.cc index d6483c44fce..11929cbe2f0 100644 --- a/source/blender/editors/space_outliner/outliner_query.cc +++ b/source/blender/editors/space_outliner/outliner_query.cc @@ -13,7 +13,7 @@ #include "outliner_intern.hh" #include "tree/tree_display.hh" -using namespace blender::ed::outliner; +namespace blender::ed::outliner { bool outliner_shows_mode_column(const SpaceOutliner &space_outliner) { @@ -46,3 +46,5 @@ bool outliner_has_element_warnings(const SpaceOutliner &space_outliner) return recursive_fn(space_outliner.tree); } + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc index 31ae4aef7ff..7929f448daa 100644 --- a/source/blender/editors/space_outliner/outliner_select.cc +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -70,7 +70,7 @@ #include "tree/tree_element_seq.hh" #include "tree/tree_iterator.hh" -using namespace blender::ed::outliner; +namespace blender::ed::outliner { /* -------------------------------------------------------------------- */ /** \name Internal Utilities @@ -1885,7 +1885,7 @@ static TreeElement *outliner_walk_left(SpaceOutliner *space_outliner, TreeStoreElem *tselem = TREESTORE(te); if (TSELEM_OPEN(tselem, space_outliner)) { - outliner_item_openclose(space_outliner, te, false, toggle_all); + outliner_item_openclose(te, false, toggle_all); } /* Only walk up a level if the element is closed and not toggling expand */ else if (!toggle_all && te->parent) { @@ -1906,7 +1906,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner, te = static_cast<TreeElement *>(te->subtree.first); } else { - outliner_item_openclose(space_outliner, te, true, toggle_all); + outliner_item_openclose(te, true, toggle_all); } return te; @@ -2040,3 +2040,5 @@ void OUTLINER_OT_select_walk(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_sync.cc b/source/blender/editors/space_outliner/outliner_sync.cc index 772a5826f9f..5899d04c353 100644 --- a/source/blender/editors/space_outliner/outliner_sync.cc +++ b/source/blender/editors/space_outliner/outliner_sync.cc @@ -94,6 +94,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C) wm->outliner_sync_select_dirty = 0; } +namespace blender::ed::outliner { + /** * Outliner sync select dirty flags are not enough to determine which types to sync, * outliner display mode also needs to be considered. This stores the types of data @@ -335,8 +337,12 @@ static void outliner_sync_selection_from_outliner(Scene *scene, } } +} // namespace blender::ed::outliner + void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner) { + using namespace blender::ed::outliner; + /* Don't sync if not checked or in certain outliner display modes */ if (!(space_outliner->flag & SO_SYNC_SELECT) || ELEM(space_outliner->outlinevis, SO_LIBRARIES, @@ -380,6 +386,8 @@ void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_out } } +namespace blender::ed::outliner { + static void outliner_select_sync_from_object(ViewLayer *view_layer, Object *obact, TreeElement *te, @@ -561,3 +569,5 @@ void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner) } } } + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index f51a70af3bc..ae6b2ee6d58 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -89,6 +89,8 @@ #include "tree/tree_element_seq.hh" #include "tree/tree_iterator.hh" +namespace blender::ed::outliner { + static CLG_LogRef LOG = {"ed.outliner.tools"}; using namespace blender::ed::outliner; @@ -1274,22 +1276,68 @@ static void id_override_library_reset_fn(bContext *C, OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; - if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { - Main *bmain = CTX_data_main(C); + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name); + return; + } - if (do_hierarchy) { - BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false); + Main *bmain = CTX_data_main(C); + + if (do_hierarchy) { + BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false); + } + else { + BKE_lib_override_library_id_reset(bmain, id_root, false); + } +} + +static void id_override_library_clear_single_fn(bContext *C, + ReportList *reports, + Scene *scene, + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ID *id = tselem->id; + + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot clear embedded library override id '%s', only overrides of real " + "data-blocks can be directly deleted", + id->name); + return; + } + + /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy), + * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset system + * override. */ + if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) { + bool do_remap_active = false; + if (OBACT(view_layer) == reinterpret_cast<Object *>(id)) { + BLI_assert(GS(id->name) == ID_OB); + do_remap_active = true; } - else { - BKE_lib_override_library_id_reset(bmain, id_root, false); + BKE_libblock_remap(bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE); + if (do_remap_active) { + Object *ref_object = reinterpret_cast<Object *>(id->override_library->reference); + Base *basact = BKE_view_layer_base_find(view_layer, ref_object); + if (basact != nullptr) { + view_layer->basact = basact; + } + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); } - - WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr); + BKE_id_delete(bmain, id); } else { - CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name); + BKE_lib_override_library_id_reset(bmain, id, true); } + + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); } static void id_override_library_resync_fn(bContext *UNUSED(C), @@ -1340,13 +1388,13 @@ static void id_override_library_resync_hierarchy_process(bContext *C, WM_event_add_notifier(C, NC_WINDOW, nullptr); } -static void id_override_library_clear_hierarchy_fn(bContext *UNUSED(C), - ReportList *UNUSED(reports), - Scene *UNUSED(scene), - TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *user_data) +static void id_override_library_delete_hierarchy_fn(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *user_data) { OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); @@ -1366,52 +1414,15 @@ static void id_override_library_clear_hierarchy_fn(bContext *UNUSED(C), } /* Clear (delete) a hierarchy of library overrides. */ -static void id_override_library_clear_hierarchy_process(bContext *C, - ReportList *UNUSED(reports), - OutlinerLibOverrideData &data) +static void id_override_library_delete_hierarchy_process(bContext *C, + ReportList *UNUSED(reports), + OutlinerLibOverrideData &data) { Main *bmain = CTX_data_main(C); for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) { BKE_lib_override_library_delete(bmain, id_hierarchy_root); } - - WM_event_add_notifier(C, NC_WINDOW, nullptr); -} - -static void id_override_library_clear_single_fn(bContext *C, - ReportList *reports, - Scene *UNUSED(scene), - TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) -{ - BLI_assert(TSE_IS_REAL_ID(tselem)); - Main *bmain = CTX_data_main(C); - ID *id = tselem->id; - - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { - BKE_reportf(reports, - RPT_WARNING, - "Cannot clear embedded library override id '%s', only overrides of real " - "data-blocks can be directly deleted", - id->name); - return; - } - - /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy), - * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset system - * override. */ - if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) { - BKE_libblock_remap(bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE); - BKE_id_delete(bmain, id); - } - else { - BKE_lib_override_library_id_reset(bmain, id, true); - } - - WM_event_add_notifier(C, NC_WINDOW, nullptr); } static void id_fake_user_set_fn(bContext *UNUSED(C), @@ -1634,14 +1645,14 @@ static const EnumPropertyItem prop_liboverride_op_types[] = { {OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY, "OVERRIDE_LIBRARY_CREATE_HIERARCHY", 0, - "Create", - "Make a local override of the selected linked data-blocks, and their hierarchy of " + "Make", + "Create a local override of the selected linked data-blocks, and their hierarchy of " "dependencies"}, {OUTLINER_LIBOVERRIDE_OP_RESET, "OVERRIDE_LIBRARY_RESET", 0, "Reset", - "Reset the selected local override to their linked references values"}, + "Reset the selected local overrides to their linked references values"}, {OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE, "OVERRIDE_LIBRARY_CLEAR_SINGLE", 0, @@ -1665,6 +1676,7 @@ static const EnumPropertyItem prop_liboverride_troubleshoot_op_types[] = { "Rebuild the selected local overrides from their linked references, as well as their " "hierarchies of dependencies, enforcing these hierarchies to match the linked data (i.e. " "ignoring existing overrides on data-blocks pointer properties)"}, + RNA_ENUM_ITEM_SEPR, {OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY, "OVERRIDE_LIBRARY_DELETE_HIERARCHY", 0, @@ -1784,11 +1796,11 @@ static int outliner_liboverride_operation_exec(bContext *C, wmOperator *op) op->reports, scene, space_outliner, - id_override_library_clear_hierarchy_fn, + id_override_library_delete_hierarchy_fn, OUTLINER_LIB_SELECTIONSET_SELECTED, nullptr); - id_override_library_clear_hierarchy_process(C, op->reports, override_data); + id_override_library_delete_hierarchy_process(C, op->reports, override_data); ED_undo_push(C, "Delete Overridden Data Hierarchy"); break; @@ -1798,11 +1810,9 @@ static int outliner_liboverride_operation_exec(bContext *C, wmOperator *op) break; } - /* wrong notifier still... */ - WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); - - /* XXX: this is just so that outliner is always up to date. */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr); + WM_event_add_notifier(C, NC_WINDOW, nullptr); + WM_event_add_notifier(C, NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr); return OPERATOR_FINISHED; } @@ -1812,6 +1822,7 @@ void OUTLINER_OT_liboverride_operation(wmOperatorType *ot) /* identifiers */ ot->name = "Outliner Library Override Operation"; ot->idname = "OUTLINER_OT_liboverride_operation"; + ot->description = "Create, reset or clear library override hierarchies"; /* callbacks */ ot->invoke = WM_menu_invoke; @@ -1834,6 +1845,7 @@ void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot) /* identifiers */ ot->name = "Outliner Library Override Troubleshoot Operation"; ot->idname = "OUTLINER_OT_liboverride_troubleshoot_operation"; + ot->description = "Advanced operations over library override to help fix broken hierarchies"; /* callbacks */ ot->invoke = WM_menu_invoke; @@ -1842,18 +1854,18 @@ void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot) ot->flag = 0; - RNA_def_enum(ot->srna, - "type", - prop_liboverride_troubleshoot_op_types, - 0, - "Library Override Troubleshoot Operation", - ""); ot->prop = RNA_def_enum(ot->srna, - "selection_set", - prop_lib_op_selection_set, + "type", + prop_liboverride_troubleshoot_op_types, 0, - "Selection Set", - "Over which part of the tree items to apply the operation"); + "Library Override Troubleshoot Operation", + ""); + RNA_def_enum(ot->srna, + "selection_set", + prop_lib_op_selection_set, + 0, + "Selection Set", + "Over which part of the tree items to apply the operation"); } /** \} */ @@ -2338,6 +2350,17 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void return TRAVERSE_SKIP_CHILDS; } + /* Do not allow to delete children objects of an override collection. */ + TreeElement *te_parent = te->parent; + if (outliner_is_collection_tree_element(te_parent)) { + TreeStoreElem *tselem_parent = TREESTORE(te_parent); + ID *id_parent = tselem_parent->id; + BLI_assert(GS(id_parent->name) == ID_GR); + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_parent)) { + return TRAVERSE_SKIP_CHILDS; + } + } + ID *id = tselem->id; if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { @@ -2734,6 +2757,7 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot) /* identifiers */ ot->name = "Outliner ID Data Operation"; ot->idname = "OUTLINER_OT_id_operation"; + ot->description = "General data-block management operations"; /* callbacks */ ot->invoke = WM_menu_invoke; @@ -3437,3 +3461,5 @@ void OUTLINER_OT_operation(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index 0906bbb5797..b8cdf18f599 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -41,6 +41,7 @@ #include "BLI_fnmatch.h" #include "BLI_listbase.h" #include "BLI_mempool.h" +#include "BLI_timeit.hh" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -51,7 +52,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_modifier.h" -#include "BKE_outliner_treehash.h" +#include "BKE_outliner_treehash.hh" #include "ED_screen.h" @@ -69,7 +70,7 @@ # include "BLI_math_base.h" /* M_PI */ #endif -using namespace blender::ed::outliner; +namespace blender::ed::outliner { /* prototypes */ static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner); @@ -110,10 +111,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) if (BLI_mempool_len(ts) == unused) { BLI_mempool_destroy(ts); space_outliner->treestore = nullptr; - if (space_outliner->runtime->treehash) { - BKE_outliner_treehash_free(space_outliner->runtime->treehash); - space_outliner->runtime->treehash = nullptr; - } + space_outliner->runtime->tree_hash = nullptr; } else { TreeStoreElem *tsenew; @@ -128,16 +126,15 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) } BLI_mempool_destroy(ts); space_outliner->treestore = new_ts; - if (space_outliner->runtime->treehash) { + if (space_outliner->runtime->tree_hash) { /* update hash table to fix broken pointers */ - BKE_outliner_treehash_rebuild_from_treestore(space_outliner->runtime->treehash, - space_outliner->treestore); + space_outliner->runtime->tree_hash->rebuild_from_treestore(*space_outliner->treestore); } } } } - else if (space_outliner->runtime->treehash) { - BKE_outliner_treehash_clear_used(space_outliner->runtime->treehash); + else if (space_outliner->runtime->tree_hash) { + space_outliner->runtime->tree_hash->clear_used(); } } } @@ -150,15 +147,14 @@ static void check_persistent( space_outliner->treestore = BLI_mempool_create( sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); } - if (space_outliner->runtime->treehash == nullptr) { - space_outliner->runtime->treehash = static_cast<GHash *>( - BKE_outliner_treehash_create_from_treestore(space_outliner->treestore)); + if (space_outliner->runtime->tree_hash == nullptr) { + space_outliner->runtime->tree_hash = treehash::TreeHash::create_from_treestore( + *space_outliner->treestore); } /* find any unused tree element in treestore and mark it as used * (note that there may be multiple unused elements in case of linked objects) */ - TreeStoreElem *tselem = BKE_outliner_treehash_lookup_unused( - space_outliner->runtime->treehash, type, nr, id); + TreeStoreElem *tselem = space_outliner->runtime->tree_hash->lookup_unused(type, nr, id); if (tselem) { te->store_elem = tselem; tselem->used = 1; @@ -173,7 +169,7 @@ static void check_persistent( tselem->used = 0; tselem->flag = TSE_CLOSED; te->store_elem = tselem; - BKE_outliner_treehash_add_element(space_outliner->runtime->treehash, tselem); + space_outliner->runtime->tree_hash->add_element(*tselem); } /** \} */ @@ -221,11 +217,6 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE); } -bool outliner_requires_rebuild_on_open_change(const SpaceOutliner *space_outliner) -{ - return ELEM(space_outliner->outlinevis, SO_DATA_API); -} - /* special handling of hierarchical non-lib data */ static void outliner_add_bone(SpaceOutliner *space_outliner, ListBase *lb, @@ -795,8 +786,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } } -namespace blender::ed::outliner { - TreeElement *outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, void *idv, @@ -933,8 +922,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, return te; } -} // namespace blender::ed::outliner - /* ======================================================= */ BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection) @@ -1684,10 +1671,9 @@ void outliner_build_tree(Main *mainvar, space_outliner->search_flags &= ~SO_SEARCH_RECURSIVE; } - if (space_outliner->runtime->treehash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) && + if (space_outliner->runtime->tree_hash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) && space_outliner->treestore) { - BKE_outliner_treehash_rebuild_from_treestore(space_outliner->runtime->treehash, - space_outliner->treestore); + space_outliner->runtime->tree_hash->rebuild_from_treestore(*space_outliner->treestore); } space_outliner->storeflag &= ~SO_TREESTORE_REBUILD; @@ -1698,6 +1684,10 @@ void outliner_build_tree(Main *mainvar, return; } + /* Enable for benchmarking. Starts a timer, results will be printed on function exit. */ + // SCOPED_TIMER("Outliner Rebuild"); + // SCOPED_TIMER_AVERAGED("Outliner Rebuild"); + OutlinerTreeElementFocus focus; outliner_store_scrolling_position(space_outliner, region, &focus); @@ -1733,3 +1723,5 @@ void outliner_build_tree(Main *mainvar, } /** \} */ + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc index d8c50cd04f9..3ff4a058de3 100644 --- a/source/blender/editors/space_outliner/outliner_utils.cc +++ b/source/blender/editors/space_outliner/outliner_utils.cc @@ -18,7 +18,7 @@ #include "BKE_context.h" #include "BKE_layer.h" #include "BKE_object.h" -#include "BKE_outliner_treehash.h" +#include "BKE_outliner_treehash.hh" #include "ED_outliner.h" #include "ED_screen.h" @@ -27,9 +27,10 @@ #include "UI_view2d.h" #include "outliner_intern.hh" +#include "tree/tree_display.hh" #include "tree/tree_iterator.hh" -using namespace blender::ed::outliner; +namespace blender::ed::outliner { /* -------------------------------------------------------------------- */ /** \name Tree View Context @@ -175,24 +176,6 @@ TreeElement *outliner_find_parent_element(ListBase *lb, return nullptr; } -TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse) -{ - TreeStoreElem *tselem; - - if (tse->id == nullptr) { - return nullptr; - } - - /* Check if 'tse' is in tree-store. */ - tselem = BKE_outliner_treehash_lookup_any( - space_outliner->runtime->treehash, tse->type, tse->nr, tse->id); - if (tselem) { - return outliner_find_tree_element(&space_outliner->tree, tselem); - } - - return nullptr; -} - TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id) { LISTBASE_FOREACH (TreeElement *, te, lb) { @@ -454,7 +437,7 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space ARegion *region) { /* Avoid rebuild if possible. */ - if (outliner_requires_rebuild_on_open_change(space_outliner)) { + if (space_outliner->runtime->tree_display->is_lazy_built()) { ED_region_tag_redraw(region); } else { @@ -462,6 +445,10 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space } } +} // namespace blender::ed::outliner + +using namespace blender::ed::outliner; + Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) { ARegion *region = CTX_wm_region(C); diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc index 61bc3d35dfd..04f326d62f9 100644 --- a/source/blender/editors/space_outliner/space_outliner.cc +++ b/source/blender/editors/space_outliner/space_outliner.cc @@ -16,7 +16,7 @@ #include "BKE_context.h" #include "BKE_lib_remap.h" -#include "BKE_outliner_treehash.h" +#include "BKE_outliner_treehash.hh" #include "BKE_screen.h" #include "ED_screen.h" @@ -37,16 +37,11 @@ #include "outliner_intern.hh" #include "tree/tree_display.hh" -SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/) - : tree_display(nullptr), treehash(nullptr) -{ -} +namespace blender::ed::outliner { -SpaceOutliner_Runtime::~SpaceOutliner_Runtime() +SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/) + : tree_display(nullptr), tree_hash(nullptr) { - if (treehash) { - BKE_outliner_treehash_free(treehash); - } } static void outliner_main_region_init(wmWindowManager *wm, ARegion *region) @@ -191,7 +186,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) } break; case NC_ID: - if (ELEM(wmn->action, NA_RENAME, NA_ADDED)) { + if (ELEM(wmn->action, NA_RENAME, NA_ADDED, NA_REMOVED)) { ED_region_tag_redraw(region); } break; @@ -391,8 +386,6 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRe { SpaceOutliner *space_outliner = (SpaceOutliner *)slink; - BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT); - if (!space_outliner->treestore) { return; } @@ -420,7 +413,7 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRe /* Note that the Outliner may not be the active editor of the area, and hence not initialized. * So runtime data might not have been created yet. */ - if (space_outliner->runtime && space_outliner->runtime->treehash && changed) { + if (space_outliner->runtime && space_outliner->runtime->tree_hash && changed) { /* rebuild hash table, because it depends on ids too */ /* postpone a full rebuild because this can be called many times on-free */ space_outliner->storeflag |= SO_TREESTORE_REBUILD; @@ -442,8 +435,12 @@ static void outliner_deactivate(struct ScrArea *area) ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); } +} // namespace blender::ed::outliner + void ED_spacetype_outliner(void) { + using namespace blender::ed::outliner; + SpaceType *st = MEM_cnew<SpaceType>("spacetype time"); ARegionType *art; diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc index e590b0c97d1..199c80f021a 100644 --- a/source/blender/editors/space_outliner/tree/common.cc +++ b/source/blender/editors/space_outliner/tree/common.cc @@ -21,6 +21,8 @@ #include "common.hh" #include "tree_display.hh" +namespace blender::ed::outliner { + /* -------------------------------------------------------------------- */ /** \name ID Helpers. * \{ */ @@ -63,3 +65,5 @@ bool outliner_animdata_test(const AnimData *adt) } return false; } + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/common.hh b/source/blender/editors/space_outliner/tree/common.hh index 96c1eb34354..ba2d1c3fab6 100644 --- a/source/blender/editors/space_outliner/tree/common.hh +++ b/source/blender/editors/space_outliner/tree/common.hh @@ -8,7 +8,11 @@ struct ListBase; +namespace blender::ed::outliner { + const char *outliner_idcode_to_plural(short idcode); void outliner_make_object_parent_hierarchy(ListBase *lb); bool outliner_animdata_test(const struct AnimData *adt); + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc index 6ab497b3fbb..fe4937829d6 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.cc +++ b/source/blender/editors/space_outliner/tree/tree_display.cc @@ -50,4 +50,9 @@ bool AbstractTreeDisplay::supportsModeColumn() const return false; } +bool AbstractTreeDisplay::is_lazy_built() const +{ + return false; +} + } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index f8e35655c26..295eeb59eaa 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -30,11 +30,11 @@ struct Main; struct Scene; struct Sequence; struct SpaceOutliner; -struct TreeElement; struct ViewLayer; namespace blender::ed::outliner { +struct TreeElement; class TreeElementID; /** @@ -84,6 +84,15 @@ class AbstractTreeDisplay { */ virtual bool supportsModeColumn() const; + /** + * Some trees may want to skip building children of collapsed parents. This should be done if the + * tree type may become very complex, which could cause noticeable slowdowns. + * Problem: This doesn't address performance issues while searching, since all elements are + * constructed for that. Trees of this type have to be rebuilt for any change to the collapsed + * state of any element. + */ + virtual bool is_lazy_built() const; + protected: /** All derived classes will need a handle to this, so storing it in the base for convenience. */ SpaceOutliner &space_outliner_; @@ -157,6 +166,8 @@ class TreeDisplayOverrideLibraryHierarchies final : public AbstractTreeDisplay { ListBase buildTree(const TreeSourceData &source_data) override; + bool is_lazy_built() const override; + private: ListBase build_hierarchy_for_lib_or_main(Main *bmain, TreeElement &parent_te, @@ -232,6 +243,8 @@ class TreeDisplayDataAPI final : public AbstractTreeDisplay { TreeDisplayDataAPI(SpaceOutliner &space_outliner); ListBase buildTree(const TreeSourceData &source_data) override; + + bool is_lazy_built() const override; }; } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc index bfeb8ce2bdc..3d9b927fbf1 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc @@ -42,4 +42,9 @@ ListBase TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data) return tree; } +bool TreeDisplayDataAPI::is_lazy_built() const +{ + return true; +} + } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc index e0a1958795a..fa4479d0d9d 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc @@ -75,6 +75,11 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData & return tree; } +bool TreeDisplayOverrideLibraryHierarchies::is_lazy_built() const +{ + return true; +} + /* -------------------------------------------------------------------- */ /** \name Library override hierarchy building * \{ */ @@ -165,10 +170,14 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID(ID &override_root_id, build_hierarchy_for_ID_recursive(override_root_id, build_data, te_to_expand); } +enum ForeachChildReturn { + FOREACH_CONTINUE, + FOREACH_BREAK, +}; /* Helpers (defined below). */ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, const ID &parent_id, - FunctionRef<void(ID &)> fn); + FunctionRef<ForeachChildReturn(ID &)> fn); static bool id_is_in_override_hierarchy(const Main &bmain, const ID &id, const ID &relationship_parent_id, @@ -184,22 +193,30 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare foreach_natural_hierarchy_child(id_relations_, parent_id, [&](ID &id) { /* Some IDs can use themselves, early abort. */ if (&id == &parent_id) { - return; + return FOREACH_CONTINUE; } if (!id_is_in_override_hierarchy(bmain_, id, parent_id, build_data.override_root_id_)) { - return; + return FOREACH_CONTINUE; } /* Avoid endless recursion: If there is an ancestor for this ID already, it recurses into * itself. */ if (build_data.parent_ids.lookup_key_default(&id, nullptr)) { - return; + return FOREACH_CONTINUE; } /* Avoid duplicates: If there is a sibling for this ID already, the same ID is just used * multiple times by the same parent. */ if (build_data.sibling_ids.lookup_key_default(&id, nullptr)) { - return; + return FOREACH_CONTINUE; + } + + /* We only want to add children whose parent isn't collapsed. Otherwise, in complex scenes with + * thousands of relationships, the building can slow down tremendously. Tag the parent to allow + * un-collapsing, but don't actually add the children. */ + if (!TSELEM_OPEN(TREESTORE(&te_to_expand), &space_outliner_)) { + te_to_expand.flag |= TE_PRETEND_HAS_CHILDREN; + return FOREACH_BREAK; } TreeElement *new_te = outliner_add_element( @@ -213,6 +230,8 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare child_build_data.parent_ids.add(&id); child_build_data.sibling_ids.reserve(10); build_hierarchy_for_ID_recursive(id, child_build_data, *new_te); + + return FOREACH_CONTINUE; }); } @@ -238,7 +257,7 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare */ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, const ID &parent_id, - FunctionRef<void(ID &)> fn) + FunctionRef<ForeachChildReturn(ID &)> fn) { const MainIDRelationsEntry *relations_of_id = static_cast<MainIDRelationsEntry *>( BLI_ghash_lookup(id_relations.relations_from_pointers, &parent_id)); @@ -259,12 +278,16 @@ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, if (GS(target_id.name) == ID_OB) { const Object &potential_child_ob = reinterpret_cast<const Object &>(target_id); if (potential_child_ob.parent) { - fn(potential_child_ob.parent->id); + if (fn(potential_child_ob.parent->id) == FOREACH_BREAK) { + return; + } continue; } } - fn(target_id); + if (fn(target_id) == FOREACH_BREAK) { + return; + } } /* If the ID is an object, find and iterate over any child objects. */ @@ -277,9 +300,13 @@ static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations, continue; } - Object &potential_child_ob = reinterpret_cast<Object &>(potential_child_id); - if (potential_child_ob.parent && &potential_child_ob.parent->id == &parent_id) { - fn(potential_child_id); + const Object &potential_child_ob = reinterpret_cast<Object &>(potential_child_id); + if (!potential_child_ob.parent || &potential_child_ob.parent->id != &parent_id) { + continue; + } + + if (fn(potential_child_id) == FOREACH_BREAK) { + return; } } } diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index fc6211f20ea..1b145a48daa 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -14,10 +14,11 @@ struct ListBase; struct SpaceOutliner; -struct TreeElement; namespace blender::ed::outliner { +struct TreeElement; + /* -------------------------------------------------------------------- */ /* Tree-Display Interface */ diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh index 956cf3dec48..f3372329dd1 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh @@ -8,8 +8,6 @@ #include "tree_element.hh" -struct TreeElement; - namespace blender::ed::outliner { class TreeElementAnimData final : public AbstractTreeElement { diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.hh b/source/blender/editors/space_outliner/tree/tree_element_driver.hh index 053217e18ec..f0213dd39f2 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_driver.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_driver.hh @@ -8,8 +8,6 @@ #include "tree_element.hh" -struct TreeElement; - namespace blender::ed::outliner { class TreeElementDriverBase final : public AbstractTreeElement { 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 6dd5ec84041..9e1f22b49d6 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_rna.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc @@ -124,7 +124,7 @@ void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const } } else if (tot) { - legacy_te_.flag |= TE_LAZY_CLOSED; + legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN; } } @@ -172,7 +172,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1); } else { - legacy_te_.flag |= TE_LAZY_CLOSED; + legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN; } } } @@ -189,7 +189,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const } } else if (tot) { - legacy_te_.flag |= TE_LAZY_CLOSED; + legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN; } } else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { @@ -207,7 +207,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const } } else if (tot) { - legacy_te_.flag |= TE_LAZY_CLOSED; + legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN; } } } diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh index de5bcd2c462..0c94c2f95cf 100644 --- a/source/blender/editors/space_outliner/tree/tree_iterator.hh +++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh @@ -10,9 +10,11 @@ struct ListBase; struct SpaceOutliner; -struct TreeElement; namespace blender::ed::outliner { + +struct TreeElement; + namespace tree_iterator { using VisitorFn = FunctionRef<void(TreeElement *)>; diff --git a/source/blender/editors/space_script/CMakeLists.txt b/source/blender/editors/space_script/CMakeLists.txt index 8486fa0e872..f7fc4e38c17 100644 --- a/source/blender/editors/space_script/CMakeLists.txt +++ b/source/blender/editors/space_script/CMakeLists.txt @@ -8,7 +8,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 44f919ca361..deaec0136c4 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -15,7 +15,6 @@ set(INC ../../sequencer ../../windowmanager ../../../../intern/atomic - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 9313e45a1d4..7f23df4c94f 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2637,12 +2637,12 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) Sequence *seq_other; const char *error_msg; - if (SEQ_select_active_get_pair(scene, &seq_act, &seq_other) == 0) { + if (SEQ_select_active_get_pair(scene, &seq_act, &seq_other) == false) { BKE_report(op->reports, RPT_ERROR, "Please select two strips"); return OPERATOR_CANCELLED; } - if (SEQ_edit_sequence_swap(scene, seq_act, seq_other, &error_msg) == 0) { + if (SEQ_edit_sequence_swap(scene, seq_act, seq_other, &error_msg) == false) { BKE_report(op->reports, RPT_ERROR, error_msg); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index f134cdb95c2..173d976c124 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -14,7 +14,6 @@ set(INC ../../makesrna ../../nodes ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_statusbar/CMakeLists.txt b/source/blender/editors/space_statusbar/CMakeLists.txt index fba40c1ec26..cf0ccd4e552 100644 --- a/source/blender/editors/space_statusbar/CMakeLists.txt +++ b/source/blender/editors/space_statusbar/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 6410e971a66..38787a84fce 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/space_topbar/CMakeLists.txt b/source/blender/editors/space_topbar/CMakeLists.txt index 26c6b796df5..f529c855e6d 100644 --- a/source/blender/editors/space_topbar/CMakeLists.txt +++ b/source/blender/editors/space_topbar/CMakeLists.txt @@ -10,7 +10,6 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index a76cd3377bc..100266f4433 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -15,7 +15,6 @@ set(INC ../../makesrna ../../render ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../../../intern/mantaflow/extern @@ -61,7 +60,7 @@ set(SRC view3d_ops.c view3d_placement.c view3d_project.c - view3d_select.c + view3d_select.cc view3d_snap.c view3d_utils.c view3d_view.c diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index d6ddd6d044e..6001f701c00 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -697,7 +697,7 @@ static int drop_world_exec(bContext *C, wmOperator *op) id_us_plus(&world->id); scene->world = world; - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_WORLD, scene); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 53fc450107a..4c9e2595023 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -9,6 +9,10 @@ #include "ED_view3d.h" +#ifdef __cplusplus +extern "C" { +#endif + /* internal exports only */ struct ARegion; @@ -83,7 +87,7 @@ void view3d_depths_rect_create(struct ARegion *region, struct rcti *rect, struct */ float view3d_depth_near(struct ViewDepths *d); -/* view3d_select.c */ +/* view3d_select.cc */ void VIEW3D_OT_select(struct wmOperatorType *ot); void VIEW3D_OT_select_circle(struct wmOperatorType *ot); @@ -241,3 +245,7 @@ void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt); extern uchar view3d_camera_border_hack_col[3]; extern bool view3d_camera_border_hack_test; #endif + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/space_view3d/view3d_navigate_ndof.c b/source/blender/editors/space_view3d/view3d_navigate_ndof.c index 1ce9bdcb211..88abf602c26 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_ndof.c +++ b/source/blender/editors/space_view3d/view3d_navigate_ndof.c @@ -373,6 +373,9 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event) const bool has_translate = !is_zero_v2(ndof->tvec); const bool has_zoom = ndof->tvec[2] != 0.0f; + float pan_vec[3]; + WM_event_ndof_pan_get(ndof, pan_vec, true); + /* NOTE(@campbellbarton): In principle rotating could pass through to regular * non-camera NDOF behavior (exiting the camera-view and rotating). * Disabled this block since in practice it's difficult to control NDOF devices @@ -388,14 +391,14 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event) if (has_translate) { const float speed = ndof->dt * NDOF_PIXELS_PER_SECOND; - float event_ofs[2] = {ndof->tvec[0] * speed, ndof->tvec[1] * speed}; + float event_ofs[2] = {pan_vec[0] * speed, pan_vec[1] * speed}; if (ED_view3d_camera_view_pan(region, event_ofs)) { changed = true; } } if (has_zoom) { - const float scale = 1.0f + (ndof->dt * ndof->tvec[2]); + const float scale = 1.0f + (ndof->dt * pan_vec[2]); if (ED_view3d_camera_view_zoom_scale(rv3d, scale)) { changed = true; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.cc index 763848574ed..036d951efaa 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -5,10 +5,10 @@ * \ingroup spview3d */ -#include <float.h> -#include <math.h> -#include <stdio.h> -#include <string.h> +#include <cfloat> +#include <cmath> +#include <cstdio> +#include <cstring> #include "DNA_action_types.h" #include "DNA_armature_types.h" @@ -23,7 +23,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_array.h" #include "BLI_bitmap.h" #include "BLI_lasso_2d.h" #include "BLI_linklist.h" @@ -32,6 +31,7 @@ #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BLI_vector.hh" #ifdef __BIG_ENDIAN__ # include "BLI_endian_switch.h" @@ -205,14 +205,14 @@ static void editselect_buf_cache_init(ViewContext *vc, short select_mode) } } -static void editselect_buf_cache_free(struct EditSelectBuf_Cache *esel) +static void editselect_buf_cache_free(EditSelectBuf_Cache *esel) { MEM_SAFE_FREE(esel->select_bitmap); } static void editselect_buf_cache_free_voidp(void *esel_voidp) { - editselect_buf_cache_free(esel_voidp); + editselect_buf_cache_free(static_cast<EditSelectBuf_Cache *>(esel_voidp)); MEM_freeN(esel_voidp); } @@ -220,7 +220,7 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w ViewContext *vc, short select_mode) { - struct EditSelectBuf_Cache *esel = MEM_callocN(sizeof(*esel), __func__); + EditSelectBuf_Cache *esel = MEM_cnew<EditSelectBuf_Cache>(__func__); wm_userdata->data = esel; wm_userdata->free_fn = editselect_buf_cache_free_voidp; wm_userdata->use_free = true; @@ -233,7 +233,7 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w /** \name Internal Edit-Mesh Utilities * \{ */ -static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel, +static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, @@ -265,7 +265,7 @@ static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel return changed; } -static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel, +static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, @@ -297,7 +297,7 @@ static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel return changed; } -static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel, +static bool edbm_backbuf_check_and_select_faces(EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, @@ -331,7 +331,7 @@ static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel /* object mode, edbm_ prefix is confusing here, rename? */ static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, - struct EditSelectBuf_Cache *esel, + EditSelectBuf_Cache *esel, const eSelectOp sel_op) { MVert *mv = me->mvert; @@ -360,7 +360,7 @@ static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, /* object mode, edbm_ prefix is confusing here, rename? */ static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me, - struct EditSelectBuf_Cache *esel, + EditSelectBuf_Cache *esel, const eSelectOp sel_op) { MPoly *mpoly = me->mpoly; @@ -393,7 +393,7 @@ static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me, /** \name Lasso Select * \{ */ -typedef struct LassoSelectUserData { +struct LassoSelectUserData { ViewContext *vc; const rcti *rect; const rctf *rect_fl; @@ -407,7 +407,7 @@ typedef struct LassoSelectUserData { int pass; bool is_done; bool is_changed; -} LassoSelectUserData; +}; static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, ViewContext *vc, @@ -426,7 +426,7 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->mcoords_len = mcoords_len; r_data->sel_op = sel_op; /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ - r_data->select_flag = SELECT; + r_data->select_flag = (eBezTriple_Flag)SELECT; /* runtime */ r_data->pass = 0; @@ -505,12 +505,12 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2 } static void do_lasso_select_pose__do_tag(void *userData, - struct bPoseChannel *pchan, + bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]) { - LassoSelectUserData *data = userData; - const bArmature *arm = data->vc->obact->data; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); + const bArmature *arm = static_cast<bArmature *>(data->vc->obact->data); if (!PBONE_SELECTABLE(arm, pchan->bone)) { return; } @@ -531,7 +531,7 @@ static void do_lasso_tag_pose(ViewContext *vc, LassoSelectUserData data; rcti rect; - if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) { + if ((ob->type != OB_ARMATURE) || (ob->pose == nullptr)) { return; } @@ -540,7 +540,8 @@ static void do_lasso_tag_pose(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0); + view3d_userdata_lassoselect_init( + &data, vc, &rect, mcoords, mcoords_len, static_cast<eSelectOp>(0)); ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d); @@ -564,7 +565,7 @@ static bool do_lasso_select_objects(ViewContext *vc, changed |= object_deselect_all_visible(vc->view_layer, vc->v3d); } - for (base = vc->view_layer->object_bases.first; base; base = base->next) { + for (base = static_cast<Base *>(vc->view_layer->object_bases.first); base; base = base->next) { if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */ const bool is_select = base->flag & BASE_SELECTED; const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) && @@ -588,32 +589,31 @@ static bool do_lasso_select_objects(ViewContext *vc, /** * Use for lasso & box select. */ -static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len) +static blender::Vector<Base *> do_pose_tag_select_op_prepare(ViewContext *vc) { - Base **bases = NULL; - BLI_array_declare(bases); + blender::Vector<Base *> bases; + FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_ARMATURE, OB_MODE_POSE, base_iter) { Object *ob_iter = base_iter->object; - bArmature *arm = ob_iter->data; + bArmature *arm = static_cast<bArmature *>(ob_iter->data); LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) { Bone *bone = pchan->bone; bone->flag &= ~BONE_DONE; } arm->id.tag |= LIB_TAG_DOIT; ob_iter->id.tag &= ~LIB_TAG_DOIT; - BLI_array_append(bases, base_iter); + bases.append(base_iter); } FOREACH_BASE_IN_MODE_END; - *r_bases_len = BLI_array_len(bases); return bases; } -static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op) +static bool do_pose_tag_select_op_exec(blender::MutableSpan<Base *> bases, const eSelectOp sel_op) { bool changed_multi = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - for (int i = 0; i < bases_len; i++) { + for (const int i : bases.index_range()) { Base *base_iter = bases[i]; Object *ob_iter = base_iter->object; if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, false)) { @@ -623,10 +623,10 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const } } - for (int i = 0; i < bases_len; i++) { + for (const int i : bases.index_range()) { Base *base_iter = bases[i]; Object *ob_iter = base_iter->object; - bArmature *arm = ob_iter->data; + bArmature *arm = static_cast<bArmature *>(ob_iter->data); /* Don't handle twice. */ if (arm->id.tag & LIB_TAG_DOIT) { @@ -647,7 +647,7 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const SET_FLAG_FROM_TEST(bone->flag, sel_op_result, BONE_SELECTED); if (sel_op_result == 0) { if (arm->act_bone == bone) { - arm->act_bone = NULL; + arm->act_bone = nullptr; } } changed = true; @@ -667,22 +667,20 @@ static bool do_lasso_select_pose(ViewContext *vc, const int mcoords_len, const eSelectOp sel_op) { - uint bases_len; - Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len); + blender::Vector<Base *> bases = do_pose_tag_select_op_prepare(vc); - for (int i = 0; i < bases_len; i++) { + for (const int i : bases.index_range()) { Base *base_iter = bases[i]; Object *ob_iter = base_iter->object; do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len); } - const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op); + const bool changed_multi = do_pose_tag_select_op_exec(bases, sel_op); if (changed_multi) { DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene); } - MEM_freeN(bases); return changed_multi; } @@ -691,7 +689,7 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, const float screen_co[2], int UNUSED(index)) { - LassoSelectUserData *data = userData; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && @@ -705,7 +703,7 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, } struct LassoSelectUserData_ForMeshEdge { LassoSelectUserData *data; - struct EditSelectBuf_Cache *esel; + EditSelectBuf_Cache *esel; uint backbuf_offset; }; static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, @@ -714,7 +712,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, const float screen_co_b[2], int index) { - struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data; + LassoSelectUserData_ForMeshEdge *data_for_edge = static_cast<LassoSelectUserData_ForMeshEdge *>( + user_data); LassoSelectUserData *data = data_for_edge->data; bool is_visible = true; if (data_for_edge->backbuf_offset) { @@ -742,7 +741,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, const float screen_co_b[2], int index) { - struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data; + LassoSelectUserData_ForMeshEdge *data_for_edge = static_cast<LassoSelectUserData_ForMeshEdge *>( + user_data); LassoSelectUserData *data = data_for_edge->data; bool is_visible = true; if (data_for_edge->backbuf_offset) { @@ -768,7 +768,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, const float screen_co[2], int UNUSED(index)) { - LassoSelectUserData *data = userData; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && @@ -812,13 +812,13 @@ static bool do_lasso_select_mesh(ViewContext *vc, const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); - struct EditSelectBuf_Cache *esel = wm_userdata->data; + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); if (use_zbuf) { - if (wm_userdata->data == NULL) { + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); - esel = wm_userdata->data; + esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr); } } @@ -834,16 +834,15 @@ static bool do_lasso_select_mesh(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ - struct LassoSelectUserData_ForMeshEdge data_for_edge = { - .data = &data, - .esel = use_zbuf ? esel : NULL, - .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( - vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : - 0, - }; + LassoSelectUserData_ForMeshEdge data_for_edge{}; + data_for_edge.data = &data; + data_for_edge.esel = use_zbuf ? esel : nullptr; + data_for_edge.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( + vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : + 0; const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | - (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); + (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB); /* Fully inside. */ mesh_foreachScreenEdge_clip_bb_segment( vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag); @@ -882,7 +881,7 @@ static void do_lasso_select_curve__doSelect(void *userData, bool handles_visible, const float screen_co[2]) { - LassoSelectUserData *data = userData; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); const bool is_inside = BLI_lasso_is_point_inside( data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED); @@ -948,14 +947,14 @@ static bool do_lasso_select_curve(ViewContext *vc, } if (data.is_changed) { - BKE_curve_nurb_vert_active_validate(vc->obedit->data); + BKE_curve_nurb_vert_active_validate(static_cast<Curve *>(vc->obedit->data)); } return data.is_changed; } static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2]) { - LassoSelectUserData *data = userData; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); const bool is_select = bp->f1 & SELECT; const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && @@ -994,8 +993,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, const float screen_co_a[2], const float screen_co_b[2]) { - LassoSelectUserData *data = userData; - const bArmature *arm = data->vc->obedit->data; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); + const bArmature *arm = static_cast<const bArmature *>(data->vc->obedit->data); if (!EBONE_VISIBLE(arm, ebone)) { return; } @@ -1043,8 +1042,8 @@ static void do_lasso_select_armature__doSelectBone_clip_content(void *userData, const float screen_co_a[2], const float screen_co_b[2]) { - LassoSelectUserData *data = userData; - bArmature *arm = data->vc->obedit->data; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); + bArmature *arm = static_cast<bArmature *>(data->vc->obedit->data); if (!EBONE_VISIBLE(arm, ebone)) { return; } @@ -1083,7 +1082,7 @@ static bool do_lasso_select_armature(ViewContext *vc, data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit); } - bArmature *arm = vc->obedit->data; + bArmature *arm = static_cast<bArmature *>(vc->obedit->data); ED_armature_ebone_listbase_temp_clear(arm->edbo); @@ -1101,7 +1100,7 @@ static bool do_lasso_select_armature(ViewContext *vc, &data, V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT); - data.is_changed |= ED_armature_edit_select_op_from_tagged(vc->obedit->data, sel_op); + data.is_changed |= ED_armature_edit_select_op_from_tagged(arm, sel_op); if (data.is_changed) { WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit); @@ -1110,10 +1109,10 @@ static bool do_lasso_select_armature(ViewContext *vc, } static void do_lasso_select_mball__doSelectElem(void *userData, - struct MetaElem *ml, + MetaElem *ml, const float screen_co[2]) { - LassoSelectUserData *data = userData; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); const bool is_select = ml->flag & SELECT; const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && @@ -1156,7 +1155,7 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, const float screen_co[2], int UNUSED(index)) { - LassoSelectUserData *data = userData; + LassoSelectUserData *data = static_cast<LassoSelectUserData *>(userData); const bool is_select = mv->flag & SELECT; const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && @@ -1176,10 +1175,10 @@ static bool do_lasso_select_paintvert(ViewContext *vc, { const bool use_zbuf = !XRAY_ENABLED(vc->v3d); Object *ob = vc->obact; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); rcti rect; - if (me == NULL || me->totvert == 0) { + if (me == nullptr || me->totvert == 0) { return false; } @@ -1191,18 +1190,18 @@ static bool do_lasso_select_paintvert(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - struct EditSelectBuf_Cache *esel = wm_userdata->data; + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); if (use_zbuf) { - if (wm_userdata->data == NULL) { + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX); - esel = wm_userdata->data; + esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr); } } if (use_zbuf) { - if (esel->select_bitmap != NULL) { + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); } } @@ -1236,10 +1235,10 @@ static bool do_lasso_select_paintface(ViewContext *vc, const eSelectOp sel_op) { Object *ob = vc->obact; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); rcti rect; - if (me == NULL || me->totpoly == 0) { + if (me == nullptr || me->totpoly == 0) { return false; } @@ -1251,12 +1250,12 @@ static bool do_lasso_select_paintface(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - struct EditSelectBuf_Cache *esel = wm_userdata->data; - if (esel == NULL) { + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); + if (esel == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE); - esel = wm_userdata->data; + esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr); } if (esel->select_bitmap) { @@ -1281,7 +1280,7 @@ static bool view3d_lasso_select(bContext *C, wmGenericUserData wm_userdata_buf = {0}; wmGenericUserData *wm_userdata = &wm_userdata_buf; - if (vc->obedit == NULL) { /* Object Mode */ + if (vc->obedit == nullptr) { /* Object Mode */ if (BKE_paint_select_face_test(ob)) { changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op); } @@ -1293,7 +1292,7 @@ static bool view3d_lasso_select(bContext *C, /* pass */ } else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { - changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op); + changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op) != OPERATOR_CANCELLED; } else if (ob && (ob->mode & OB_MODE_POSE)) { changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op); @@ -1339,7 +1338,7 @@ static bool view3d_lasso_select(bContext *C, } if (changed) { - DEG_id_tag_update(vc->obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc->obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data); changed_multi = true; } @@ -1368,7 +1367,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc, depsgraph); - eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + eSelectOp sel_op = static_cast<eSelectOp>(RNA_enum_get(op->ptr, "mode")); bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op); MEM_freeN((void *)mcoords); @@ -1408,12 +1407,12 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot) * \{ */ /* The max number of menu items in an object select menu */ -typedef struct SelMenuItemF { +struct SelMenuItemF { char idname[MAX_ID_NAME - 2]; int icon; Base *base_ptr; void *item_ptr; -} SelMenuItemF; +}; #define SEL_MENU_SIZE 22 static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE]; @@ -1424,12 +1423,12 @@ static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, PropertyRNA *UNUSED(prop), bool *r_free) { - EnumPropertyItem *item = NULL, item_tmp = {0}; + EnumPropertyItem *item = nullptr, item_tmp = {0}; int totitem = 0; int i = 0; /* Don't need context but avoid API doc-generation using this. */ - if (C == NULL || object_mouse_select_menu_data[i].idname[0] == '\0') { + if (C == nullptr || object_mouse_select_menu_data[i].idname[0] == '\0') { return DummyRNA_NULL_items; } @@ -1460,7 +1459,7 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); const Base *oldbasact = BASACT(view_layer); - Base *basact = NULL; + Base *basact = nullptr; CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { /* This is a bit dodgy, there should only be ONE object with this name, * but library objects can mess this up. */ @@ -1471,7 +1470,7 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - if (basact == NULL) { + if (basact == nullptr) { return OPERATOR_CANCELLED; } UNUSED_VARS_NDEBUG(v3d); @@ -1542,7 +1541,7 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) /* #Object.id.name to select (dynamic enum). */ prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", ""); RNA_def_enum_funcs(prop, object_select_menu_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE)); ot->prop = prop; prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", ""); @@ -1561,12 +1560,12 @@ static bool object_mouse_select_menu(bContext *C, const GPUSelectResult *buffer, const int hits, const int mval[2], - const struct SelectPick_Params *params, + const SelectPick_Params *params, Base **r_basact) { int base_count = 0; bool ok; - LinkNodePair linklist = {NULL, NULL}; + LinkNodePair linklist = {nullptr, nullptr}; /* handle base->object->select_id */ CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { @@ -1603,14 +1602,14 @@ static bool object_mouse_select_menu(bContext *C, } CTX_DATA_END; - *r_basact = NULL; + *r_basact = nullptr; if (base_count == 0) { return false; } if (base_count == 1) { Base *base = (Base *)linklist.list->link; - BLI_linklist_free(linklist.list, NULL); + BLI_linklist_free(linklist.list, nullptr); *r_basact = base; return false; } @@ -1622,7 +1621,7 @@ static bool object_mouse_select_menu(bContext *C, memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data)); for (node = linklist.list, i = 0; node; node = node->next, i++) { - Base *base = node->link; + Base *base = static_cast<Base *>(node->link); Object *ob = base->object; const char *name = ob->id.name + 2; @@ -1637,10 +1636,10 @@ static bool object_mouse_select_menu(bContext *C, RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD); RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB); RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); WM_operator_properties_free(&ptr); - BLI_linklist_free(linklist.list, NULL); + BLI_linklist_free(linklist.list, nullptr); return true; } @@ -1648,9 +1647,8 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op) { const int name_index = RNA_enum_get(op->ptr, "name"); - const struct SelectPick_Params params = { - .sel_op = ED_select_op_from_operator(op->ptr), - }; + SelectPick_Params params{}; + params.sel_op = ED_select_op_from_operator(op->ptr); View3D *v3d = CTX_wm_view3d(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -1658,7 +1656,7 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op) Base *basact = object_mouse_select_menu_data[name_index].base_ptr; - if (basact == NULL) { + if (basact == nullptr) { return OPERATOR_CANCELLED; } @@ -1733,7 +1731,7 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot) /* #Object.id.name to select (dynamic enum). */ prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Bone Name", ""); RNA_def_enum_funcs(prop, object_select_menu_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE)); ot->prop = prop; prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", ""); @@ -1751,19 +1749,19 @@ static bool bone_mouse_select_menu(bContext *C, const GPUSelectResult *buffer, const int hits, const bool is_editmode, - const struct SelectPick_Params *params) + const SelectPick_Params *params) { BLI_assert(buffer); int bone_count = 0; - LinkNodePair base_list = {NULL, NULL}; - LinkNodePair bone_list = {NULL, NULL}; + LinkNodePair base_list = {nullptr, nullptr}; + LinkNodePair bone_list = {nullptr, nullptr}; GSet *added_bones = BLI_gset_ptr_new("Bone mouse select menu"); /* Select logic taken from ed_armature_pick_bone_from_selectbuffer_impl in armature_select.c */ for (int a = 0; a < hits; a++) { - void *bone_ptr = NULL; - Base *bone_base = NULL; + void *bone_ptr = nullptr; + Base *bone_base = nullptr; uint hitresult = buffer[a].id; if (!(hitresult & BONESEL_ANY)) { @@ -1791,8 +1789,8 @@ static bool bone_mouse_select_menu(bContext *C, if (is_editmode) { EditBone *ebone; const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16; - bArmature *arm = bone_base->object->data; - ebone = BLI_findlink(arm->edbo, hit_bone); + bArmature *arm = static_cast<bArmature *>(bone_base->object->data); + ebone = static_cast<EditBone *>(BLI_findlink(arm->edbo, hit_bone)); if (ebone && !(ebone->flag & BONE_UNSELECTABLE)) { bone_ptr = ebone; } @@ -1800,7 +1798,8 @@ static bool bone_mouse_select_menu(bContext *C, else { bPoseChannel *pchan; const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16; - pchan = BLI_findlink(&bone_base->object->pose->chanbase, hit_bone); + pchan = static_cast<bPoseChannel *>( + BLI_findlink(&bone_base->object->pose->chanbase, hit_bone)); if (pchan && !(pchan->bone->flag & BONE_UNSELECTABLE)) { bone_ptr = pchan; } @@ -1825,14 +1824,14 @@ static bool bone_mouse_select_menu(bContext *C, } } - BLI_gset_free(added_bones, NULL); + BLI_gset_free(added_bones, nullptr); if (bone_count == 0) { return false; } if (bone_count == 1) { - BLI_linklist_free(base_list.list, NULL); - BLI_linklist_free(bone_list.list, NULL); + BLI_linklist_free(base_list.list, nullptr); + BLI_linklist_free(bone_list.list, nullptr); return false; } @@ -1846,15 +1845,15 @@ static bool bone_mouse_select_menu(bContext *C, base_node = base_node->next, bone_node = bone_node->next, i++) { char *name; - object_mouse_select_menu_data[i].base_ptr = base_node->link; + object_mouse_select_menu_data[i].base_ptr = static_cast<Base *>(base_node->link); if (is_editmode) { - EditBone *ebone = bone_node->link; + EditBone *ebone = static_cast<EditBone *>(bone_node->link); object_mouse_select_menu_data[i].item_ptr = ebone; name = ebone->name; } else { - bPoseChannel *pchan = bone_node->link; + bPoseChannel *pchan = static_cast<bPoseChannel *>(bone_node->link); object_mouse_select_menu_data[i].item_ptr = pchan; name = pchan->name; } @@ -1870,11 +1869,11 @@ static bool bone_mouse_select_menu(bContext *C, RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD); RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB); RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); WM_operator_properties_free(&ptr); - BLI_linklist_free(base_list.list, NULL); - BLI_linklist_free(bone_list.list, NULL); + BLI_linklist_free(base_list.list, nullptr); + BLI_linklist_free(bone_list.list, nullptr); return true; } @@ -1932,7 +1931,7 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc, int hits15, hits9 = 0, hits5 = 0; bool has_bones15 = false, has_bones9 = false, has_bones5 = false; - int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); + eV3DSelectMode select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); int hits = 0; if (do_nearest_xray_if_supported) { @@ -2088,7 +2087,7 @@ static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b * that are visible but not select-able, * since you may be in pose mode with an un-selectable object. * - * \return the active base or NULL. + * \return the active base or nullptr. */ static Base *mouse_select_eval_buffer(ViewContext *vc, const GPUSelectResult *buffer, @@ -2140,7 +2139,8 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, else { { - GPUSelectResult *buffer_sorted = MEM_mallocN(sizeof(*buffer_sorted) * hits, __func__); + GPUSelectResult *buffer_sorted = static_cast<GPUSelectResult *>( + MEM_mallocN(sizeof(*buffer_sorted) * hits, __func__)); memcpy(buffer_sorted, buffer, sizeof(*buffer_sorted) * hits); /* Remove non-bone objects. */ if (has_bones && do_bones_get_priotity) { @@ -2186,7 +2186,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, MEM_freeN((void *)buffer); } - Base *basact = NULL; + Base *basact = nullptr; if (found) { for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) { @@ -2215,7 +2215,7 @@ static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const const float mval_fl[2] = {(float)mval[0], (float)mval[1]}; float dist = ED_view3d_select_dist_px() * 1.3333f; - Base *basact = NULL; + Base *basact = nullptr; /* Put the active object at a disadvantage to cycle through other objects. */ const float penalty_dist = 10.0f * UI_DPI_FAC; @@ -2238,7 +2238,7 @@ static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const } base = base->next; - if (base == NULL) { + if (base == nullptr) { base = FIRSTBASE(view_layer); } if (base == startbase) { @@ -2254,7 +2254,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C, { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - Base *basact = NULL; + Base *basact = nullptr; GPUSelectResult buffer[MAXPICKELEMS]; /* setup view context for argument to callbacks */ @@ -2264,7 +2264,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C, ED_view3d_viewcontext_init(C, &vc, depsgraph); const bool do_nearest = !XRAY_ACTIVE(vc.v3d); - const bool do_material_slot_selection = r_material_slot != NULL; + const bool do_material_slot_selection = r_material_slot != nullptr; const int hits = mixed_bones_object_selectbuffer(&vc, buffer, ARRAY_SIZE(buffer), @@ -2275,7 +2275,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C, do_material_slot_selection); if (hits > 0) { - const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits); + const bool has_bones = (r_material_slot == nullptr) && selectbuffer_has_bones(buffer, hits); basact = mouse_select_eval_buffer( &vc, buffer, hits, do_nearest, has_bones, true, r_material_slot); } @@ -2285,7 +2285,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C, Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) { - return ed_view3d_give_base_under_cursor_ex(C, mval, NULL); + return ed_view3d_give_base_under_cursor_ex(C, mval, nullptr); } Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2]) @@ -2294,33 +2294,33 @@ Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2]) if (base) { return base->object; } - return NULL; + return nullptr; } -struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C, - const int mval[2], - int *r_material_slot) +Object *ED_view3d_give_material_slot_under_cursor(bContext *C, + const int mval[2], + int *r_material_slot) { Base *base = ed_view3d_give_base_under_cursor_ex(C, mval, r_material_slot); if (base) { return base->object; } - return NULL; + return nullptr; } bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2]) { - return ED_view3d_give_object_under_cursor(C, mval) != NULL; + return ED_view3d_give_object_under_cursor(C, mval) != nullptr; } static void deselect_all_tracks(MovieTracking *tracking) { MovieTrackingObject *object; - object = tracking->objects.first; + object = static_cast<MovieTrackingObject *>(tracking->objects.first); while (object) { ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object); - MovieTrackingTrack *track = tracksbase->first; + MovieTrackingTrack *track = static_cast<MovieTrackingTrack *>(tracksbase->first); while (track) { BKE_tracking_track_deselect(track, TRACK_AREA_ALL); @@ -2336,16 +2336,16 @@ static bool ed_object_select_pick_camera_track(bContext *C, Scene *scene, Base *basact, MovieClip *clip, - const struct GPUSelectResult *buffer, + const GPUSelectResult *buffer, const short hits, - const struct SelectPick_Params *params) + const SelectPick_Params *params) { bool changed = false; bool found = false; MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = NULL; - MovieTrackingTrack *track = NULL; + ListBase *tracksbase = nullptr; + MovieTrackingTrack *track = nullptr; for (int i = 0; i < hits; i++) { const int hitresult = buffer[i].id; @@ -2433,7 +2433,7 @@ static bool ed_object_select_pick_camera_track(bContext *C, */ static bool ed_object_select_pick(bContext *C, const int mval[2], - const struct SelectPick_Params *params, + const SelectPick_Params *params, const bool center, const bool enumerate, const bool object_only) @@ -2447,21 +2447,21 @@ static bool ed_object_select_pick(bContext *C, View3D *v3d = vc.v3d; /* Menu activation may find a base to make active (if it only finds a single item to select). */ - Base *basact_override = NULL; + Base *basact_override = nullptr; - const bool is_obedit = (vc.obedit != NULL); + const bool is_obedit = (vc.obedit != nullptr); if (object_only) { /* Signal for #view3d_opengl_select to skip edit-mode objects. */ - vc.obedit = NULL; + vc.obedit = nullptr; } - /* Set for GPU depth buffer picking, leave NULL when selecting by center. */ - struct { + /* Set for GPU depth buffer picking, leave null when selecting by center. */ + struct GPUData { GPUSelectResult buffer[MAXPICKELEMS]; int hits; bool do_nearest; bool has_bones; - } *gpu = NULL; + } *gpu = nullptr; /* First handle menu selection, early exit if a menu opens * since this takes ownership of the selection action. @@ -2470,7 +2470,7 @@ static bool ed_object_select_pick(bContext *C, * the item under the cursor. */ if (center == false) { - gpu = MEM_mallocN(sizeof(*gpu), __func__); + gpu = MEM_new<GPUData>(__func__); gpu->do_nearest = false; gpu->has_bones = false; @@ -2497,7 +2497,7 @@ static bool ed_object_select_pick(bContext *C, if (enumerate) { bool has_menu = false; if (center) { - if (object_mouse_select_menu(C, &vc, NULL, 0, mval, params, &basact_override)) { + if (object_mouse_select_menu(C, &vc, nullptr, 0, mval, params, &basact_override)) { has_menu = true; } } @@ -2515,7 +2515,7 @@ static bool ed_object_select_pick(bContext *C, /* Let the menu handle any further actions. */ if (has_menu) { - if (gpu != NULL) { + if (gpu != nullptr) { MEM_freeN(gpu); } return false; @@ -2526,13 +2526,14 @@ static bool ed_object_select_pick(bContext *C, ViewLayer *view_layer = vc.view_layer; /* Don't set when the context has no active object (hidden), see: T60807. */ - const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL; + const Base *oldbasact = vc.obact ? BASACT(view_layer) : nullptr; /* Always start list from `basact` when cycling the selection. */ Base *startbase = (oldbasact && oldbasact->next) ? oldbasact->next : FIRSTBASE(view_layer); /* The next object's base to make active. */ - Base *basact = NULL; - const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT; + Base *basact = nullptr; + const eObjectMode object_mode = oldbasact ? static_cast<eObjectMode>(oldbasact->object->mode) : + OB_MODE_OBJECT; /* When enabled, don't attempt any further selection. */ bool handled = false; @@ -2579,8 +2580,8 @@ static bool ed_object_select_pick(bContext *C, gpu->do_nearest, gpu->has_bones, do_bones_get_priotity, - NULL) : - NULL; + nullptr) : + nullptr; } /* Select pose-bones or camera-tracks. */ @@ -2590,7 +2591,7 @@ static bool ed_object_select_pick(bContext *C, if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) { MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false); - if (clip != NULL) { + if (clip != nullptr) { if (ed_object_select_pick_camera_track( C, scene, basact, clip, gpu->buffer, gpu->hits, params)) { ED_object_base_select(basact, BA_SELECT); @@ -2603,7 +2604,7 @@ static bool ed_object_select_pick(bContext *C, /* Fallback to regular object selection if no new bundles were selected, * allows to select object parented to reconstruction object. */ basact = mouse_select_eval_buffer( - &vc, gpu->buffer, gpu->hits, gpu->do_nearest, false, false, NULL); + &vc, gpu->buffer, gpu->hits, gpu->do_nearest, false, false, nullptr); } } } @@ -2620,7 +2621,7 @@ static bool ed_object_select_pick(bContext *C, /* When there is no `baseact` this will have operated on `oldbasact`, * allowing #SelectPick_Params.deselect_all work in pose-mode. * In this case no object operations are needed. */ - if (basact != NULL) { + if (basact != nullptr) { /* By convention the armature-object is selected when in pose-mode. * While leaving it unselected will work, leaving pose-mode would leave the object * active + unselected which isn't ideal when performing other actions on the object. */ @@ -2675,11 +2676,11 @@ static bool ed_object_select_pick(bContext *C, if (is_obedit == false) { if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) { if (object_mode == OB_MODE_OBJECT) { - struct Main *bmain = vc.bmain; + Main *bmain = vc.bmain; ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object); } if (!BKE_object_is_mode_compat(basact->object, object_mode)) { - basact = NULL; + basact = nullptr; } } @@ -2688,7 +2689,7 @@ static bool ed_object_select_pick(bContext *C, if (basact && oldbasact) { if ((oldbasact->object->mode != basact->object->mode) && (oldbasact->object->mode & basact->object->mode) == 0) { - basact = NULL; + basact = nullptr; } } } @@ -2697,10 +2698,10 @@ static bool ed_object_select_pick(bContext *C, /* Ensure code above doesn't change the active base. This code is already fairly involved, * it's best if changing the active object is localized to a single place. */ - BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL)); + BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : nullptr)); - bool found = (basact != NULL); - if ((handled == false) && (vc.obedit == NULL)) { + bool found = (basact != nullptr); + if ((handled == false) && (vc.obedit == nullptr)) { /* Object-mode (pose mode will have been handled already). */ if (params->sel_op == SEL_OP_SET) { if ((found && params->select_passthrough) && (basact->flag & BASE_SELECTED)) { @@ -2708,7 +2709,7 @@ static bool ed_object_select_pick(bContext *C, } else if (found || params->deselect_all) { /* Deselect everything. */ - /* `basact` may be NULL. */ + /* `basact` may be nullptr. */ if (object_deselect_all_except(view_layer, basact)) { changed_object = true; } @@ -2768,7 +2769,7 @@ static bool ed_object_select_pick(bContext *C, /* Perform the activation even when 'handled', since this is used to ensure * the object from the pose-bone selected is also activated. */ - if (use_activate_selected_base && (basact != NULL)) { + if (use_activate_selected_base && (basact != nullptr)) { changed_object = true; ED_object_base_activate(C, basact); /* adds notifier */ if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) { @@ -2787,7 +2788,7 @@ static bool ed_object_select_pick(bContext *C, ED_outliner_select_sync_from_pose_bone_tag(C); } - if (gpu != NULL) { + if (gpu != nullptr) { MEM_freeN(gpu); } @@ -2802,13 +2803,13 @@ static bool ed_object_select_pick(bContext *C, */ static bool ed_wpaint_vertex_select_pick(bContext *C, const int mval[2], - const struct SelectPick_Params *params, + const SelectPick_Params *params, Object *obact) { View3D *v3d = CTX_wm_view3d(C); const bool use_zbuf = !XRAY_ENABLED(v3d); - Mesh *me = obact->data; /* already checked for NULL */ + Mesh *me = static_cast<Mesh *>(obact->data); /* already checked for nullptr */ uint index = 0; MVert *mv; bool changed = false; @@ -2877,7 +2878,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); - struct SelectPick_Params params = {0}; + SelectPick_Params params{}; ED_select_pick_params_from_operator(op->ptr, ¶ms); const bool vert_without_handles = RNA_boolean_get(op->ptr, "vert_without_handles"); @@ -2898,8 +2899,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op) int mval[2]; if (object_only) { - obedit = NULL; - obact = NULL; + obedit = nullptr; + obact = nullptr; /* ack, this is incorrect but to do this correctly we would need an * alternative edit-mode/object-mode keymap, this copies the functionality @@ -3033,7 +3034,7 @@ void VIEW3D_OT_select(wmOperatorType *ot) prop = RNA_def_int_vector(ot->srna, "location", 2, - NULL, + nullptr, INT_MIN, INT_MAX, "Location", @@ -3049,7 +3050,7 @@ void VIEW3D_OT_select(wmOperatorType *ot) /** \name Box Select * \{ */ -typedef struct BoxSelectUserData { +struct BoxSelectUserData { ViewContext *vc; const rcti *rect; const rctf *rect_fl; @@ -3060,7 +3061,7 @@ typedef struct BoxSelectUserData { /* runtime */ bool is_done; bool is_changed; -} BoxSelectUserData; +}; static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, ViewContext *vc, @@ -3075,7 +3076,7 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, r_data->sel_op = sel_op; /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ - r_data->select_flag = SELECT; + r_data->select_flag = (eBezTriple_Flag)SELECT; /* runtime */ r_data->is_done = false; @@ -3096,7 +3097,7 @@ static void do_paintvert_box_select__doSelectVert(void *userData, const float screen_co[2], int UNUSED(index)) { - BoxSelectUserData *data = userData; + BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData); const bool is_select = mv->flag & SELECT; const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -3112,11 +3113,9 @@ static bool do_paintvert_box_select(ViewContext *vc, { const bool use_zbuf = !XRAY_ENABLED(vc->v3d); - Mesh *me; - - me = vc->obact->data; - if ((me == NULL) || (me->totvert == 0)) { - return OPERATOR_CANCELLED; + Mesh *me = static_cast<Mesh *>(vc->obact->data); + if ((me == nullptr) || (me->totvert == 0)) { + return false; } bool changed = false; @@ -3128,14 +3127,14 @@ static bool do_paintvert_box_select(ViewContext *vc, /* pass */ } else if (use_zbuf) { - struct EditSelectBuf_Cache *esel = wm_userdata->data; - if (wm_userdata->data == NULL) { + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX); - esel = wm_userdata->data; + esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_rect( - vc->depsgraph, vc->region, vc->v3d, rect, NULL); + vc->depsgraph, vc->region, vc->v3d, rect, nullptr); } - if (esel->select_bitmap != NULL) { + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); } } @@ -3164,13 +3163,13 @@ static bool do_paintvert_box_select(ViewContext *vc, static bool do_paintface_box_select(ViewContext *vc, wmGenericUserData *wm_userdata, const rcti *rect, - int sel_op) + eSelectOp sel_op) { Object *ob = vc->obact; Mesh *me; me = BKE_mesh_from_object(ob); - if ((me == NULL) || (me->totpoly == 0)) { + if ((me == nullptr) || (me->totpoly == 0)) { return false; } @@ -3183,14 +3182,14 @@ static bool do_paintface_box_select(ViewContext *vc, /* pass */ } else { - struct EditSelectBuf_Cache *esel = wm_userdata->data; - if (wm_userdata->data == NULL) { + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE); - esel = wm_userdata->data; + esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_rect( - vc->depsgraph, vc->region, vc->v3d, rect, NULL); + vc->depsgraph, vc->region, vc->v3d, rect, nullptr); } - if (esel->select_bitmap != NULL) { + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); } } @@ -3209,7 +3208,7 @@ static void do_nurbs_box_select__doSelect(void *userData, bool handles_visible, const float screen_co[2]) { - BoxSelectUserData *data = userData; + BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData); const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); if (bp) { @@ -3266,14 +3265,14 @@ static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel data.is_changed |= BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); } - BKE_curve_nurb_vert_active_validate(vc->obedit->data); + BKE_curve_nurb_vert_active_validate(curve); return data.is_changed; } static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2]) { - BoxSelectUserData *data = userData; + BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData); const bool is_select = bp->f1 & SELECT; const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -3304,7 +3303,7 @@ static void do_mesh_box_select__doSelectVert(void *userData, const float screen_co[2], int UNUSED(index)) { - BoxSelectUserData *data = userData; + BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData); const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -3315,7 +3314,7 @@ static void do_mesh_box_select__doSelectVert(void *userData, } struct BoxSelectUserData_ForMeshEdge { BoxSelectUserData *data; - struct EditSelectBuf_Cache *esel; + EditSelectBuf_Cache *esel; uint backbuf_offset; }; /** @@ -3324,7 +3323,8 @@ struct BoxSelectUserData_ForMeshEdge { static void do_mesh_box_select__doSelectEdge_pass0( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData; + BoxSelectUserData_ForMeshEdge *data_for_edge = static_cast<BoxSelectUserData_ForMeshEdge *>( + userData); BoxSelectUserData *data = data_for_edge->data; bool is_visible = true; if (data_for_edge->backbuf_offset) { @@ -3348,7 +3348,8 @@ static void do_mesh_box_select__doSelectEdge_pass0( static void do_mesh_box_select__doSelectEdge_pass1( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData; + BoxSelectUserData_ForMeshEdge *data_for_edge = static_cast<BoxSelectUserData_ForMeshEdge *>( + userData); BoxSelectUserData *data = data_for_edge->data; bool is_visible = true; if (data_for_edge->backbuf_offset) { @@ -3369,7 +3370,7 @@ static void do_mesh_box_select__doSelectFace(void *userData, const float screen_co[2], int UNUSED(index)) { - BoxSelectUserData *data = userData; + BoxSelectUserData *data = static_cast<BoxSelectUserData *>(userData); const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -3402,13 +3403,13 @@ static bool do_mesh_box_select(ViewContext *vc, const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); - struct EditSelectBuf_Cache *esel = wm_userdata->data; + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); if (use_zbuf) { - if (wm_userdata->data == NULL) { + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); - esel = wm_userdata->data; + esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_rect( - vc->depsgraph, vc->region, vc->v3d, rect, NULL); + vc->depsgraph, vc->region, vc->v3d, rect, nullptr); } } @@ -3424,16 +3425,16 @@ static bool do_mesh_box_select(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ - struct BoxSelectUserData_ForMeshEdge cb_data = { - .data = &data, - .esel = use_zbuf ? esel : NULL, - .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( - vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : - 0, + struct BoxSelectUserData_ForMeshEdge cb_data { }; + cb_data.data = &data; + cb_data.esel = use_zbuf ? esel : nullptr; + cb_data.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( + vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : + 0; const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | - (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); + (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB); /* Fully inside. */ mesh_foreachScreenEdge_clip_bb_segment( vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag); @@ -3483,7 +3484,8 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO } int metaelem_id = 0; - for (ml = mb->editelems->first; ml; ml = ml->next, metaelem_id += 0x10000) { + for (ml = static_cast<MetaElem *>(mb->editelems->first); ml; + ml = ml->next, metaelem_id += 0x10000) { bool is_inside_radius = false; bool is_inside_stiff = false; @@ -3557,7 +3559,7 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel Object *obedit = bases[base_index]->object; obedit->id.tag &= ~LIB_TAG_DOIT; - bArmature *arm = obedit->data; + bArmature *arm = static_cast<bArmature *>(obedit->data); ED_armature_ebone_listbase_temp_clear(arm->edbo); } @@ -3581,7 +3583,8 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel Object *obedit = bases[base_index]->object; if (obedit->id.tag & LIB_TAG_DOIT) { obedit->id.tag &= ~LIB_TAG_DOIT; - changed |= ED_armature_edit_select_op_from_tagged(obedit->data, sel_op); + changed |= ED_armature_edit_select_op_from_tagged(static_cast<bArmature *>(obedit->data), + sel_op); } } @@ -3619,8 +3622,8 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const int totobj = MAXPICKELEMS; /* XXX solve later */ /* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */ - GPUSelectResult *buffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), - "selection buffer"); + GPUSelectResult *buffer = static_cast<GPUSelectResult *>( + MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__)); const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); const int hits = view3d_opengl_select( @@ -3630,8 +3633,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const base->object->id.tag &= ~LIB_TAG_DOIT; } - Base **bases = NULL; - BLI_array_declare(bases); + blender::Vector<Base *> bases; bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -3645,7 +3647,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) { if (BASE_SELECTABLE(v3d, base)) { if ((base->object->runtime.select_id & 0x0000FFFF) != 0) { - BLI_array_append(bases, base); + bases.append(base); } } } @@ -3657,13 +3659,14 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const buf_iter++) { bPoseChannel *pchan_dummy; Base *base = ED_armature_base_and_pchan_from_select_buffer( - bases, BLI_array_len(bases), buf_iter->id, &pchan_dummy); - if (base != NULL) { + bases.data(), bases.size(), buf_iter->id, &pchan_dummy); + if (base != nullptr) { base->object->id.tag |= LIB_TAG_DOIT; } } - for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) { + for (Base *base = static_cast<Base *>(vc->view_layer->object_bases.first); base && hits; + base = base->next) { if (BASE_SELECTABLE(v3d, base)) { const bool is_select = base->flag & BASE_SELECTED; const bool is_inside = base->object->id.tag & LIB_TAG_DOIT; @@ -3676,9 +3679,6 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const } finally: - if (bases != NULL) { - MEM_freeN(bases); - } MEM_freeN(buffer); @@ -3691,14 +3691,13 @@ finally: static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op) { - uint bases_len; - Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len); + blender::Vector<Base *> bases = do_pose_tag_select_op_prepare(vc); int totobj = MAXPICKELEMS; /* XXX solve later */ /* Selection buffer has bones potentially too, so add #MAXPICKELEMS. */ - GPUSelectResult *buffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), - "selection buffer"); + GPUSelectResult *buffer = static_cast<GPUSelectResult *>( + MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__)); const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); const int hits = view3d_opengl_select( @@ -3722,16 +3721,16 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e buf_iter++) { Bone *bone; Base *base = ED_armature_base_and_bone_from_select_buffer( - bases, bases_len, buf_iter->id, &bone); + bases.data(), bases.size(), buf_iter->id, &bone); - if (base == NULL) { + if (base == nullptr) { continue; } /* Loop over contiguous bone hits for 'base'. */ for (; buf_iter != buf_end; buf_iter++) { /* should never fail */ - if (bone != NULL) { + if (bone != nullptr) { base->object->id.tag |= LIB_TAG_DOIT; bone->flag |= BONE_DONE; } @@ -3742,28 +3741,26 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e if ((base->object->runtime.select_id & 0x0000FFFF) != (col_next->id & 0x0000FFFF)) { break; } - if (base->object->pose != NULL) { + if (base->object->pose != nullptr) { const uint hit_bone = (col_next->id & ~BONESEL_ANY) >> 16; - bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone); - bone = pchan ? pchan->bone : NULL; + bPoseChannel *pchan = static_cast<bPoseChannel *>( + BLI_findlink(&base->object->pose->chanbase, hit_bone)); + bone = pchan ? pchan->bone : nullptr; } else { - bone = NULL; + bone = nullptr; } } } } } - const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op); + const bool changed_multi = do_pose_tag_select_op_exec(bases, sel_op); if (changed_multi) { DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); } - if (bases != NULL) { - MEM_freeN(bases); - } MEM_freeN(buffer); return changed_multi; @@ -3785,7 +3782,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc, depsgraph); - eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + eSelectOp sel_op = static_cast<eSelectOp>(RNA_enum_get(op->ptr, "mode")); WM_operator_properties_border_to_rcti(op, &rect); if (vc.obedit) { @@ -3799,7 +3796,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) vc.em = BKE_editmesh_from_object(vc.obedit); changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op); if (changed) { - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); } break; @@ -3807,14 +3804,14 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) case OB_SURF: changed = do_nurbs_box_select(&vc, &rect, sel_op); if (changed) { - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); } break; case OB_MBALL: changed = do_meta_box_select(&vc, &rect, sel_op); if (changed) { - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); } break; @@ -3829,7 +3826,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) case OB_LATTICE: changed = do_lattice_box_select(&vc, &rect, sel_op); if (changed) { - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); } break; @@ -3901,7 +3898,7 @@ void VIEW3D_OT_select_box(wmOperatorType *ot) /** \name Circle Select * \{ */ -typedef struct CircleSelectUserData { +struct CircleSelectUserData { ViewContext *vc; bool select; int mval[2]; @@ -3912,7 +3909,7 @@ typedef struct CircleSelectUserData { /* runtime */ bool is_changed; -} CircleSelectUserData; +}; static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, ViewContext *vc, @@ -3930,7 +3927,7 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, r_data->radius_squared = rad * rad; /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ - r_data->select_flag = SELECT; + r_data->select_flag = (eBezTriple_Flag)SELECT; /* runtime */ r_data->is_changed = false; @@ -3941,7 +3938,7 @@ static void mesh_circle_doSelectVert(void *userData, const float screen_co[2], int UNUSED(index)) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { BM_vert_select_set(data->vc->em->bm, eve, data->select); @@ -3954,7 +3951,7 @@ static void mesh_circle_doSelectEdge(void *userData, const float screen_co_b[2], int UNUSED(index)) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) { BM_edge_select_set(data->vc->em->bm, eed, data->select); @@ -3966,7 +3963,7 @@ static void mesh_circle_doSelectFace(void *userData, const float screen_co[2], int UNUSED(index)) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { BM_face_select_set(data->vc->em->bm, efa, data->select); @@ -4003,22 +4000,22 @@ static bool mesh_circle_select(ViewContext *vc, const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); if (use_zbuf) { - if (wm_userdata->data == NULL) { + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); } } - struct EditSelectBuf_Cache *esel = wm_userdata->data; + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); if (use_zbuf) { - if (esel->select_bitmap == NULL) { + if (esel->select_bitmap == nullptr) { esel->select_bitmap = DRW_select_buffer_bitmap_from_circle( - vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL); + vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), nullptr); } } if (ts->selectmode & SCE_SELECT_VERTEX) { if (use_zbuf) { - if (esel->select_bitmap != NULL) { + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_verts( esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } @@ -4030,7 +4027,7 @@ static bool mesh_circle_select(ViewContext *vc, if (ts->selectmode & SCE_SELECT_EDGE) { if (use_zbuf) { - if (esel->select_bitmap != NULL) { + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_edges( esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } @@ -4046,7 +4043,7 @@ static bool mesh_circle_select(ViewContext *vc, if (ts->selectmode & SCE_SELECT_FACE) { if (use_zbuf) { - if (esel->select_bitmap != NULL) { + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_faces( esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } @@ -4073,7 +4070,7 @@ static bool paint_facesel_circle_select(ViewContext *vc, { BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); Object *ob = vc->obact; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -4081,18 +4078,18 @@ static bool paint_facesel_circle_select(ViewContext *vc, changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - if (wm_userdata->data == NULL) { + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE); } { - struct EditSelectBuf_Cache *esel = wm_userdata->data; + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_circle( - vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL); - if (esel->select_bitmap != NULL) { + vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), nullptr); + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); MEM_freeN(esel->select_bitmap); - esel->select_bitmap = NULL; + esel->select_bitmap = nullptr; } } @@ -4107,7 +4104,7 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData, const float screen_co[2], int UNUSED(index)) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT); @@ -4123,8 +4120,8 @@ static bool paint_vertsel_circle_select(ViewContext *vc, BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); const bool use_zbuf = !XRAY_ENABLED(vc->v3d); Object *ob = vc->obact; - Mesh *me = ob->data; - /* CircleSelectUserData data = {NULL}; */ /* UNUSED */ + Mesh *me = static_cast<Mesh *>(ob->data); + /* CircleSelectUserData data = {nullptr}; */ /* UNUSED */ bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -4135,19 +4132,19 @@ static bool paint_vertsel_circle_select(ViewContext *vc, const bool select = (sel_op != SEL_OP_SUB); if (use_zbuf) { - if (wm_userdata->data == NULL) { + if (wm_userdata->data == nullptr) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX); } } if (use_zbuf) { - struct EditSelectBuf_Cache *esel = wm_userdata->data; + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_circle( - vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL); - if (esel->select_bitmap != NULL) { + vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), nullptr); + if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); MEM_freeN(esel->select_bitmap); - esel->select_bitmap = NULL; + esel->select_bitmap = nullptr; } } else { @@ -4179,7 +4176,7 @@ static void nurbscurve_circle_doSelect(void *userData, bool UNUSED(handles_visible), const float screen_co[2]) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { if (bp) { @@ -4227,14 +4224,14 @@ static bool nurbscurve_circle_select(ViewContext *vc, data.is_changed |= BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); } - BKE_curve_nurb_vert_active_validate(vc->obedit->data); + BKE_curve_nurb_vert_active_validate(static_cast<Curve *>(vc->obedit->data)); return data.is_changed; } static void latticecurve_circle_doSelect(void *userData, BPoint *bp, const float screen_co[2]) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); @@ -4268,7 +4265,7 @@ static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2]) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { if (data->select) { @@ -4282,12 +4279,12 @@ static bool pchan_circle_doSelectJoint(void *userData, return 0; } static void do_circle_select_pose__doSelectBone(void *userData, - struct bPoseChannel *pchan, + bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]) { - CircleSelectUserData *data = userData; - bArmature *arm = data->vc->obact->data; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); + bArmature *arm = static_cast<bArmature *>(data->vc->obact->data); if (!PBONE_SELECTABLE(arm, pchan->bone)) { return; } @@ -4368,7 +4365,7 @@ static bool armature_circle_doSelectJoint(void *userData, const float screen_co[2], bool head) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { if (head) { @@ -4392,12 +4389,12 @@ static bool armature_circle_doSelectJoint(void *userData, return 0; } static void do_circle_select_armature__doSelectBone(void *userData, - struct EditBone *ebone, + EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]) { - CircleSelectUserData *data = userData; - const bArmature *arm = data->vc->obedit->data; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); + const bArmature *arm = static_cast<const bArmature *>(data->vc->obedit->data); if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) { return; } @@ -4446,19 +4443,19 @@ static void do_circle_select_armature__doSelectBone(void *userData, data->is_changed |= is_point_done; } static void do_circle_select_armature__doSelectBone_clip_content(void *userData, - struct EditBone *ebone, + EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]) { - CircleSelectUserData *data = userData; - bArmature *arm = data->vc->obedit->data; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); + bArmature *arm = static_cast<bArmature *>(data->vc->obedit->data); if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) { return; } /* Set in the first pass, needed so circle select prioritizes joints. */ - if (ebone->temp.i == true) { + if (ebone->temp.i != 0) { return; } @@ -4473,7 +4470,7 @@ static bool armature_circle_select(ViewContext *vc, float rad) { CircleSelectUserData data; - bArmature *arm = vc->obedit->data; + bArmature *arm = static_cast<bArmature *>(vc->obedit->data); const bool select = (sel_op != SEL_OP_SUB); @@ -4506,10 +4503,10 @@ static bool armature_circle_select(ViewContext *vc, } static void do_circle_select_mball__doSelectElem(void *userData, - struct MetaElem *ml, + MetaElem *ml, const float screen_co[2]) { - CircleSelectUserData *data = userData; + CircleSelectUserData *data = static_cast<CircleSelectUserData *>(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { if (data->select) { @@ -4533,7 +4530,7 @@ static bool mball_circle_select(ViewContext *vc, view3d_userdata_circleselect_init(&data, vc, select, mval, rad); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - data.is_changed |= BKE_mball_deselect_all(vc->obedit->data); + data.is_changed |= BKE_mball_deselect_all(static_cast<MetaBall *>(vc->obedit->data)); } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); @@ -4581,7 +4578,7 @@ static bool obedit_circle_select(bContext *C, } if (changed) { - DEG_id_tag_update(vc->obact->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc->obact->data), ID_RECALC_SELECT); WM_main_add_notifier(NC_GEOM | ND_SELECT, vc->obact->data); } return changed; @@ -4597,7 +4594,7 @@ static bool object_circle_select(ViewContext *vc, View3D *v3d = vc->v3d; const float radius_squared = rad * rad; - const float mval_fl[2] = {mval[0], mval[1]}; + const float mval_fl[2] = {static_cast<float>(mval[0]), static_cast<float>(mval[1])}; bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -4627,7 +4624,7 @@ static bool object_circle_select(ViewContext *vc, /* not a real operator, only for circle test */ static void view3d_circle_select_recalc(void *user_data) { - bContext *C = user_data; + bContext *C = static_cast<bContext *>(user_data); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; ED_view3d_viewcontext_init(C, &vc, depsgraph); @@ -4675,12 +4672,12 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")}; /* Allow each selection type to allocate their own data that's used between executions. */ - wmGesture *gesture = op->customdata; /* NULL when non-modal. */ + wmGesture *gesture = static_cast<wmGesture *>(op->customdata); /* nullptr when non-modal. */ wmGenericUserData wm_userdata_buf = {0}; wmGenericUserData *wm_userdata = gesture ? &gesture->user_data : &wm_userdata_buf; - const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), - WM_gesture_is_modal_first(gesture)); + const eSelectOp sel_op = ED_select_op_modal( + static_cast<eSelectOp>(RNA_enum_get(op->ptr, "mode")), WM_gesture_is_modal_first(gesture)); ED_view3d_viewcontext_init(C, &vc, depsgraph); @@ -4689,7 +4686,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) if (obedit || BKE_paint_select_elem_test(obact) || (obact && (obact->mode & OB_MODE_POSE))) { view3d_operator_needs_opengl(C); - if (obedit == NULL) { + if (obedit == nullptr) { BKE_object_update_select_id(CTX_data_main(C)); } @@ -4741,10 +4738,10 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) WM_generic_user_data_free(wm_userdata); } else { - struct EditSelectBuf_Cache *esel = wm_userdata->data; + EditSelectBuf_Cache *esel = static_cast<EditSelectBuf_Cache *>(wm_userdata->data); if (esel && esel->select_bitmap) { MEM_freeN(esel->select_bitmap); - esel->select_bitmap = NULL; + esel->select_bitmap = nullptr; } } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 5f2a4e8c4cc..cb716391fb2 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -705,8 +705,9 @@ bool ED_view3d_camera_lock_undo_test(const View3D *v3d, * Create a MEMFILE undo-step for locked camera movement when transforming the view. * Edit and texture paint mode don't use MEMFILE undo so undo push is skipped for them. * NDOF and track-pad navigation would create an undo step on every gesture and we may end up with - * unnecessary undo steps so undo push for them is not supported for now. Also operators that uses - * smooth view for navigation are excluded too, but they can be supported, see: D15345. + * unnecessary undo steps so undo push for them is not supported for now. + * Operators that use smooth view for navigation are supported via an optional parameter field, + * see: #V3D_SmoothParams.undo_str. */ static bool view3d_camera_lock_undo_ex(const char *str, const View3D *v3d, diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 6984dcb18d4..ec6f62e0f5b 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -15,7 +15,6 @@ set(INC ../../render ../../sequencer ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index fc59787e1ec..0429e37a077 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -355,10 +355,12 @@ typedef struct MouseInput { /** Initial mouse position. */ int imval[2]; - bool precision; - float precision_factor; + float imval_unproj[3]; float center[2]; float factor; + float precision_factor; + bool precision; + /** Additional data, if needed by the particular function. */ void *data; @@ -656,6 +658,9 @@ typedef struct TransInfo { /** Typically for mode settings. */ TransCustomDataContainer custom; + + /* Needed for sculpt transform. */ + const char *undo_name; } TransInfo; /** \} */ @@ -755,6 +760,7 @@ void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]); +void transform_input_update(TransInfo *t, const float fac); void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]); void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]); @@ -803,6 +809,7 @@ void calculateCenter2D(TransInfo *t); void calculateCenterLocal(TransInfo *t, const float center_global[3]); void calculateCenter(TransInfo *t); +void tranformViewUpdate(TransInfo *t); /* API functions for getting center points */ void calculateCenterBound(TransInfo *t, float r_center[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 658901a6991..2e12611a7c9 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -177,7 +177,7 @@ static void axisProjection(const TransInfo *t, const float in[3], float out[3]) { - float norm[3], vec[3], factor, angle; + float vec[3], factor, angle; float t_con_center[3]; if (is_zero_v3(in)) { @@ -214,7 +214,7 @@ static void axisProjection(const TransInfo *t, } else { float v[3]; - float norm_center[3]; + float norm[3], norm_center[3]; float plane[3]; view_vector_calc(t, t_con_center, norm_center); @@ -701,12 +701,12 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) } } -void setUserConstraint(TransInfo *t, int mode, const char ftext[]) +void setUserConstraint(TransInfo *t, int mode, const char text_[]) { char text[256]; const short orientation = transform_orientation_or_default(t); const char *spacename = transform_orientations_spacename_get(t, orientation); - BLI_snprintf(text, sizeof(text), ftext, spacename); + BLI_snprintf(text, sizeof(text), text_, spacename); switch (orientation) { case V3D_ORIENT_LOCAL: diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index 9182330b729..90a693b089e 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -34,7 +34,7 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]); * `ftext` is a format string passed to #BLI_snprintf. It will add the name of * the orientation where %s is (logically). */ -void setUserConstraint(TransInfo *t, int mode, const char text[]); +void setUserConstraint(TransInfo *t, int mode, const char text_[]); void drawConstraint(TransInfo *t); /** * Called from drawview.c, as an extra per-window draw option. diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index d1c2af75274..0815e9b3f62 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -940,15 +940,12 @@ static void init_TransDataContainers(TransInfo *t, bool free_objects = false; if (objects == NULL) { - objects = BKE_view_layer_array_from_objects_in_mode( - t->view_layer, - (t->spacetype == SPACE_VIEW3D) ? t->view : NULL, - &objects_len, - { - .object_mode = object_mode, - /* Pose transform operates on `ob->pose` so don't skip duplicate object-data. */ - .no_dup_data = (object_mode & OB_MODE_POSE) == 0, - }); + struct ObjectsInModeParams params = {0}; + params.object_mode = object_mode; + /* Pose transform operates on `ob->pose` so don't skip duplicate object-data. */ + params.no_dup_data = (object_mode & OB_MODE_POSE) == 0; + objects = BKE_view_layer_array_from_objects_in_mode_params( + t->view_layer, (t->spacetype == SPACE_VIEW3D) ? t->view : NULL, &objects_len, ¶ms); free_objects = true; } diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c index e18f75b71ae..ed19789fdd8 100644 --- a/source/blender/editors/transform/transform_convert_node.c +++ b/source/blender/editors/transform/transform_convert_node.c @@ -27,6 +27,13 @@ #include "transform_convert.h" #include "transform_snap.h" +struct TransCustomDataNode { + View2DEdgePanData edgepan_data; + + /* Compare if the view has changed so we can update with `transformViewUpdate`. */ + rctf viewrect_prev; +}; + /* -------------------------------------------------------------------- */ /** \name Node Transform Creation * \{ */ @@ -95,15 +102,17 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) SpaceNode *snode = t->area->spacedata.first; /* Custom data to enable edge panning during the node transform */ - View2DEdgePanData *customdata = MEM_callocN(sizeof(*customdata), __func__); + struct TransCustomDataNode *customdata = MEM_callocN(sizeof(*customdata), __func__); UI_view2d_edge_pan_init(t->context, - customdata, + &customdata->edgepan_data, NODE_EDGE_PAN_INSIDE_PAD, NODE_EDGE_PAN_OUTSIDE_PAD, NODE_EDGE_PAN_SPEED_RAMP, NODE_EDGE_PAN_MAX_SPEED, NODE_EDGE_PAN_DELAY, NODE_EDGE_PAN_ZOOM_INFLUENCE); + customdata->viewrect_prev = customdata->edgepan_data.initial_rect; + t->custom.type.data = customdata; t->custom.type.use_free = true; @@ -154,11 +163,11 @@ static void flushTransNodes(TransInfo *t) { const float dpi_fac = UI_DPI_FAC; - View2DEdgePanData *customdata = (View2DEdgePanData *)t->custom.type.data; + struct TransCustomDataNode *customdata = (struct TransCustomDataNode *)t->custom.type.data; if (t->options & CTX_VIEW2D_EDGE_PAN) { if (t->state == TRANS_CANCEL) { - UI_view2d_edge_pan_cancel(t->context, customdata); + UI_view2d_edge_pan_cancel(t->context, &customdata->edgepan_data); } else { /* Edge panning functions expect window coordinates, mval is relative to region */ @@ -166,13 +175,19 @@ static void flushTransNodes(TransInfo *t) t->region->winrct.xmin + t->mval[0], t->region->winrct.ymin + t->mval[1], }; - UI_view2d_edge_pan_apply(t->context, customdata, xy); + UI_view2d_edge_pan_apply(t->context, &customdata->edgepan_data, xy); } } - /* Initial and current view2D rects for additional transform due to view panning and zooming */ - const rctf *rect_src = &customdata->initial_rect; - const rctf *rect_dst = &t->region->v2d.cur; + float offset[2] = {0.0f, 0.0f}; + if (t->state != TRANS_CANCEL) { + if (!BLI_rctf_compare(&customdata->viewrect_prev, &t->region->v2d.cur, FLT_EPSILON)) { + /* Additional offset due to change in view2D rect. */ + BLI_rctf_transform_pt_v(&t->region->v2d.cur, &customdata->viewrect_prev, offset, offset); + tranformViewUpdate(t); + customdata->viewrect_prev = t->region->v2d.cur; + } + } FOREACH_TRANS_DATA_CONTAINER (t, tc) { applyGridAbsolute(t); @@ -184,10 +199,7 @@ static void flushTransNodes(TransInfo *t) bNode *node = td->extra; float loc[2]; - copy_v2_v2(loc, td2d->loc); - - /* additional offset due to change in view2D rect */ - BLI_rctf_transform_pt_v(rect_dst, rect_src, loc, loc); + add_v2_v2v2(loc, td2d->loc, offset); #ifdef USE_NODE_CENTER loc[0] -= 0.5f * BLI_rctf_size_x(&node->totr); diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c index 95958b816ab..b3b7d4358bc 100644 --- a/source/blender/editors/transform/transform_convert_sculpt.c +++ b/source/blender/editors/transform/transform_convert_sculpt.c @@ -85,7 +85,7 @@ static void createTransSculpt(bContext *C, TransInfo *t) copy_m3_m4(td->axismtx, ob->obmat); BLI_assert(!(t->options & CTX_PAINT_CURVE)); - ED_sculpt_init_transform(C, ob); + ED_sculpt_init_transform(C, ob, t->undo_name); } /** \} */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 56a7d045dfd..5bdd64dacb9 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1132,6 +1132,33 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[ } } +static void calculateZfac(TransInfo *t) +{ + /* ED_view3d_calc_zfac() defines a factor for perspective depth correction, + * used in ED_view3d_win_to_delta() */ + + /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW + * and never used in other cases. + * + * We need special case here as well, since ED_view3d_calc_zfac will crash when called + * for a region different from RGN_TYPE_WINDOW. + */ + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global); + } + else if (t->spacetype == SPACE_IMAGE) { + SpaceImage *sima = t->area->spacedata.first; + t->zfac = 1.0f / sima->zoom; + } + else { + View2D *v2d = &t->region->v2d; + /* Get zoom fac the same way as in + * `ui_view2d_curRect_validate_resize` - better keep in sync! */ + const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur); + t->zfac = 1.0f / zoomx; + } +} + void calculateCenter(TransInfo *t) { if ((t->flag & T_OVERRIDE_CENTER) == 0) { @@ -1166,22 +1193,46 @@ void calculateCenter(TransInfo *t) } } - if (t->spacetype == SPACE_VIEW3D) { - /* #ED_view3d_calc_zfac() defines a factor for perspective depth correction, - * used in #ED_view3d_win_to_delta(). */ + calculateZfac(t); +} + +/* Called every time the view changes due to navigation. + * Adjusts the mouse position relative to the object. */ +void tranformViewUpdate(TransInfo *t) +{ + float zoom_prev = t->zfac; + float zoom_new; + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + if (!t->persp) { + zoom_prev *= len_v3(t->persinv[0]); + } + + setTransformViewMatrices(t); + calculateZfac(t); - /* NOTE: `t->zfac` is only used #convertViewVec only in cases operator was invoked in - * #RGN_TYPE_WINDOW and never used in other cases. - * - * We need special case here as well, since #ED_view3d_calc_zfac will crash when called - * for a region different from #RGN_TYPE_WINDOW. */ - if (t->region->regiontype == RGN_TYPE_WINDOW) { - t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global); + zoom_new = t->zfac; + if (!t->persp) { + zoom_new *= len_v3(t->persinv[0]); } - else { - t->zfac = 0.0f; + + for (int i = 0; i < ARRAY_SIZE(t->orient); i++) { + if (t->orient[i].type == V3D_ORIENT_VIEW) { + copy_m3_m4(t->orient[i].matrix, t->viewinv); + normalize_m3(t->orient[i].matrix); + if (t->orient_curr == i) { + copy_m3_m3(t->spacemtx, t->orient[i].matrix); + invert_m3_m3_safe_ortho(t->spacemtx_inv, t->spacemtx); + } + } } } + else { + calculateZfac(t); + zoom_new = t->zfac; + } + + calculateCenter2D(t); + transform_input_update(t, zoom_prev / zoom_new); } void calculatePropRatio(TransInfo *t) diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 3b320ff51d5..38dbe742279 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "BKE_context.h" @@ -18,6 +19,7 @@ #include "WM_types.h" #include "transform.h" +#include "transform_mode.h" #include "MEM_guardedalloc.h" @@ -251,11 +253,8 @@ void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[ /** \name Setup & Handle Mouse Input * \{ */ -void initMouseInput(TransInfo *UNUSED(t), - MouseInput *mi, - const float center[2], - const int mval[2], - const bool precision) +void initMouseInput( + TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision) { mi->factor = 0; mi->precision = precision; @@ -266,14 +265,20 @@ void initMouseInput(TransInfo *UNUSED(t), mi->imval[0] = mval[0]; mi->imval[1] = mval[1]; + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + float delta[3] = {mval[0] - center[0], mval[1] - center[1]}; + ED_view3d_win_to_delta(t->region, delta, t->zfac, delta); + add_v3_v3v3(mi->imval_unproj, t->center_global, delta); + } + mi->post = NULL; } static void calcSpringFactor(MouseInput *mi) { - mi->factor = sqrtf( - ((float)(mi->center[1] - mi->imval[1])) * ((float)(mi->center[1] - mi->imval[1])) + - ((float)(mi->center[0] - mi->imval[0])) * ((float)(mi->center[0] - mi->imval[0]))); + float mdir[2] = {(float)(mi->center[1] - mi->imval[1]), (float)(mi->center[0] - mi->imval[0])}; + + mi->factor = len_v2(mdir); if (mi->factor == 0.0f) { mi->factor = 1.0f; /* prevent Inf */ @@ -441,4 +446,52 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp } } +void transform_input_update(TransInfo *t, const float fac) +{ + MouseInput *mi = &t->mouse; + t->mouse.factor *= fac; + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + projectIntView(t, mi->imval_unproj, mi->imval); + } + else { + int offset[2], center_2d_int[2] = {mi->center[0], mi->center[1]}; + sub_v2_v2v2_int(offset, mi->imval, center_2d_int); + offset[0] *= fac; + offset[1] *= fac; + + center_2d_int[0] = t->center2d[0]; + center_2d_int[1] = t->center2d[1]; + add_v2_v2v2_int(mi->imval, center_2d_int, offset); + } + + float center_old[2]; + copy_v2_v2(center_old, mi->center); + copy_v2_v2(mi->center, t->center2d); + + if (mi->use_virtual_mval) { + /* Update accumulator. */ + double mval_delta[2]; + sub_v2_v2v2_db(mval_delta, mi->virtual_mval.accum, mi->virtual_mval.prev); + mval_delta[0] *= fac; + mval_delta[1] *= fac; + copy_v2_v2_db(mi->virtual_mval.accum, mi->virtual_mval.prev); + add_v2_v2_db(mi->virtual_mval.accum, mval_delta); + } + + if (ELEM(mi->apply, InputAngle, InputAngleSpring)) { + float offset_center[2]; + sub_v2_v2v2(offset_center, mi->center, center_old); + struct InputAngle_Data *data = mi->data; + data->mval_prev[0] += offset_center[0]; + data->mval_prev[1] += offset_center[1]; + } + + if (t->mode == TFM_EDGE_SLIDE) { + transform_mode_edge_slide_reproject_input(t); + } + else if (t->mode == TFM_VERT_SLIDE) { + transform_mode_vert_slide_reproject_input(t); + } +} + /** \} */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index eac6734ed88..063de87ebb2 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -117,6 +117,7 @@ void drawEdgeSlide(TransInfo *t); void initEdgeSlide_ex( TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp); void initEdgeSlide(TransInfo *t); +void transform_mode_edge_slide_reproject_input(TransInfo *t); /* transform_mode_gpopacity.c */ @@ -191,3 +192,4 @@ void initTranslation(TransInfo *t); void drawVertSlide(TransInfo *t); void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp); void initVertSlide(TransInfo *t); +void transform_mode_vert_slide_reproject_input(TransInfo *t); diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index b48ba0640ad..85285e38bdd 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -292,6 +292,73 @@ static BMLoop *get_next_loop( return NULL; } +static void edge_slide_projmat_get(TransInfo *t, TransDataContainer *tc, float r_projectMat[4][4]) +{ + RegionView3D *rv3d = NULL; + + if (t->spacetype == SPACE_VIEW3D) { + /* Background mode support. */ + rv3d = t->region ? t->region->regiondata : NULL; + } + + if (!rv3d) { + /* Ok, let's try to survive this. */ + unit_m4(r_projectMat); + } + else { + ED_view3d_ob_project_mat_get(rv3d, tc->obedit, r_projectMat); + } +} + +static void edge_slide_pair_project(TransDataEdgeSlideVert *sv, + ARegion *region, + float projectMat[4][4], + float r_sco_a[3], + float r_sco_b[3]) +{ + BMVert *v = sv->v; + + if (sv->v_side[1]) { + ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, r_sco_b, projectMat); + } + else { + add_v3_v3v3(r_sco_b, v->co, sv->dir_side[1]); + ED_view3d_project_float_v3_m4(region, r_sco_b, r_sco_b, projectMat); + } + + if (sv->v_side[0]) { + ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, r_sco_a, projectMat); + } + else { + add_v3_v3v3(r_sco_a, v->co, sv->dir_side[0]); + ED_view3d_project_float_v3_m4(region, r_sco_a, r_sco_a, projectMat); + } +} + +static void edge_slide_data_init_mval(MouseInput *mi, EdgeSlideData *sld, float *mval_dir) +{ + /* Possible all of the edge loops are pointing directly at the view. */ + if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) { + mval_dir[0] = 0.0f; + mval_dir[1] = 100.0f; + } + + float mval_start[2], mval_end[2]; + + /* Zero out Start. */ + zero_v2(mval_start); + + /* dir holds a vector along edge loop */ + copy_v2_v2(mval_end, mval_dir); + mul_v2_fl(mval_end, 0.5f); + + sld->mval_start[0] = mi->imval[0] + mval_start[0]; + sld->mval_start[1] = mi->imval[1] + mval_start[1]; + + sld->mval_end[0] = mi->imval[0] + mval_end[0]; + sld->mval_end[1] = mi->imval[1] + mval_end[1]; +} + /** * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction. */ @@ -308,29 +375,20 @@ static void calcEdgeSlide_mval_range(TransInfo *t, BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); ARegion *region = t->region; View3D *v3d = NULL; - RegionView3D *rv3d = NULL; float projectMat[4][4]; BMBVHTree *bmbvh; /* only for use_calc_direction */ float(*loop_dir)[3] = NULL, *loop_maxdist = NULL; - float mval_start[2], mval_end[2]; float mval_dir[3], dist_best_sq; if (t->spacetype == SPACE_VIEW3D) { /* background mode support */ v3d = t->area ? t->area->spacedata.first : NULL; - rv3d = t->region ? t->region->regiondata : NULL; } - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); - } + edge_slide_projmat_get(t, tc, projectMat); if (use_occlude_geometry) { bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false); @@ -379,21 +437,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t, continue; } - if (sv->v_side[1]) { - ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, sco_b, projectMat); - } - else { - add_v3_v3v3(sco_b, v->co, sv->dir_side[1]); - ED_view3d_project_float_v3_m4(region, sco_b, sco_b, projectMat); - } - - if (sv->v_side[0]) { - ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, sco_a, projectMat); - } - else { - add_v3_v3v3(sco_a, v->co, sv->dir_side[0]); - ED_view3d_project_float_v3_m4(region, sco_a, sco_a, projectMat); - } + edge_slide_pair_project(sv, region, projectMat, sco_a, sco_b); /* global direction */ dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a); @@ -433,24 +477,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t, MEM_freeN(loop_maxdist); } - /* possible all of the edge loops are pointing directly at the view */ - if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) { - mval_dir[0] = 0.0f; - mval_dir[1] = 100.0f; - } - - /* zero out start */ - zero_v2(mval_start); - - /* dir holds a vector along edge loop */ - copy_v2_v2(mval_end, mval_dir); - mul_v2_fl(mval_end, 0.5f); - - sld->mval_start[0] = t->mval[0] + mval_start[0]; - sld->mval_start[1] = t->mval[1] + mval_start[1]; - - sld->mval_end[0] = t->mval[0] + mval_end[0]; - sld->mval_end[1] = t->mval[1] + mval_end[1]; + edge_slide_data_init_mval(&t->mouse, sld, mval_dir); if (bmbvh) { BKE_bmbvh_free(bmbvh); @@ -466,7 +493,6 @@ static void calcEdgeSlide_even(TransInfo *t, if (sld->totsv > 0) { ARegion *region = t->region; - RegionView3D *rv3d = NULL; float projectMat[4][4]; int i = 0; @@ -475,18 +501,7 @@ static void calcEdgeSlide_even(TransInfo *t, float dist_sq = 0; float dist_min_sq = FLT_MAX; - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - rv3d = t->region ? t->region->regiondata : NULL; - } - - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); - } + edge_slide_projmat_get(t, tc, projectMat); for (i = 0; i < sld->totsv; i++, sv++) { /* Set length */ @@ -1553,3 +1568,32 @@ void initEdgeSlide(TransInfo *t) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse Input Utilities + * \{ */ + +void transform_mode_edge_slide_reproject_input(TransInfo *t) +{ + ARegion *region = t->region; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + if (sld) { + float projectMat[4][4]; + edge_slide_projmat_get(t, tc, projectMat); + + TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + + float mval_dir[3], sco_a[3], sco_b[3]; + edge_slide_pair_project(curr_sv, region, projectMat, sco_a, sco_b); + sub_v3_v3v3(mval_dir, sco_b, sco_a); + edge_slide_data_init_mval(&t->mouse, sld, mval_dir); + } + } + + EdgeSlideData *sld = edgeSlideFirstGet(t); + setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start); +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index 674ffcf17a8..d7c4d862b23 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -68,7 +68,7 @@ typedef struct VertSlideParams { bool flipped; } VertSlideParams; -static void calcVertSlideCustomPoints(struct TransInfo *t) +static void vert_slide_update_input(TransInfo *t) { VertSlideParams *slp = t->custom.mode.data; VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; @@ -94,6 +94,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t) else { setCustomPoints(t, &t->mouse, mval_end, mval_start); } +} + +static void calcVertSlideCustomPoints(struct TransInfo *t) +{ + vert_slide_update_input(t); /* setCustomPoints isn't normally changing as the mouse moves, * in this case apply mouse input immediately so we don't refresh @@ -673,3 +678,22 @@ void initVertSlide(TransInfo *t) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse Input Utilities + * \{ */ + +void transform_mode_vert_slide_reproject_input(TransInfo *t) +{ + if (t->spacetype == SPACE_VIEW3D) { + RegionView3D *rv3d = t->region->regiondata; + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + VertSlideData *sld = tc->custom.mode.data; + ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat); + } + } + + vert_slide_update_input(t); +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7c94241f3e3..99919c0ed78 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -379,6 +379,8 @@ static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event) if (op->customdata == NULL) { TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data2"); + t->undo_name = op->type->name; + int mode = transformops_mode(op); retval = initTransform(C, t, op, event, mode); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 9a563aaf473..48b27cc3e5c 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -195,156 +195,152 @@ static bool doForceIncrementSnap(const TransInfo *t) void drawSnapping(const struct bContext *C, TransInfo *t) { uchar col[4], selectedCol[4], activeCol[4]; - if (!activeSnap(t)) { return; } - if (t->spacetype == SPACE_VIEW3D) { - bool draw_target = (t->tsnap.status & TARGET_INIT) && - (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); - - if (draw_target || validSnap(t)) { - UI_GetThemeColor3ubv(TH_TRANSFORM, col); - col[3] = 128; + bool draw_target = (t->spacetype == SPACE_VIEW3D) && (t->tsnap.status & TARGET_INIT) && + (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); - UI_GetThemeColor3ubv(TH_SELECT, selectedCol); - selectedCol[3] = 128; + if (!(draw_target || validSnap(t))) { + return; + } - UI_GetThemeColor3ubv(TH_ACTIVE, activeCol); - activeCol[3] = 192; + if (t->spacetype == SPACE_SEQ) { + UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col); + col[3] = 128; + } + else if (t->spacetype != SPACE_IMAGE) { + UI_GetThemeColor3ubv(TH_TRANSFORM, col); + col[3] = 128; - const float *loc_cur = NULL; - const float *loc_prev = NULL; - const float *normal = NULL; + UI_GetThemeColor3ubv(TH_SELECT, selectedCol); + selectedCol[3] = 128; - GPU_depth_test(GPU_DEPTH_NONE); + UI_GetThemeColor3ubv(TH_ACTIVE, activeCol); + activeCol[3] = 192; + } - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (!BLI_listbase_is_empty(&t->tsnap.points)) { - /* Draw snap points. */ + if (t->spacetype == SPACE_VIEW3D) { + const float *loc_cur = NULL; + const float *loc_prev = NULL; + const float *normal = NULL; - float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE); - float view_inv[4][4]; - copy_m4_m4(view_inv, rv3d->viewinv); + GPU_depth_test(GPU_DEPTH_NONE); - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (!BLI_listbase_is_empty(&t->tsnap.points)) { + /* Draw snap points. */ - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE); + float view_inv[4][4]; + copy_m4_m4(view_inv, rv3d->viewinv); - LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) { - if (p == t->tsnap.selectedPoint) { - immUniformColor4ubv(selectedCol); - } - else { - immUniformColor4ubv(col); - } - imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); - } + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immUnbindProgram(); - } + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - /* draw normal if needed */ - if (usingSnappingNormal(t) && validSnappingNormal(t)) { - normal = t->tsnap.snapNormal; + LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) { + if (p == t->tsnap.selectedPoint) { + immUniformColor4ubv(selectedCol); + } + else { + immUniformColor4ubv(col); + } + imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); } - if (draw_target) { - loc_prev = t->tsnap.snapTarget; - } + immUnbindProgram(); + } - if (validSnap(t)) { - loc_cur = t->tsnap.snapPoint; - } + /* draw normal if needed */ + if (usingSnappingNormal(t) && validSnappingNormal(t)) { + normal = t->tsnap.snapNormal; + } - ED_view3d_cursor_snap_draw_util( - rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); + if (draw_target) { + loc_prev = t->tsnap.snapTarget; + } - GPU_depth_test(GPU_DEPTH_LESS_EQUAL); + if (validSnap(t)) { + loc_cur = t->tsnap.snapPoint; } + + ED_view3d_cursor_snap_draw_util( + rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); + + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } else if (t->spacetype == SPACE_IMAGE) { - if (validSnap(t)) { - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - float x, y; - const float snap_point[2] = { - t->tsnap.snapPoint[0] / t->aspect[0], - t->tsnap.snapPoint[1] / t->aspect[1], - }; - UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y); - float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize; - - GPU_matrix_push_projection(); - wmOrtho2_region_pixelspace(t->region); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3ub(255, 255, 255); - imm_draw_circle_wire_2d(pos, x, y, radius, 8); - immUnbindProgram(); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - GPU_matrix_pop_projection(); - } - } - else if (t->spacetype == SPACE_NODE) { - if (validSnap(t)) { - ARegion *region = CTX_wm_region(C); - TransSnapPoint *p; - float size; + float x, y; + const float snap_point[2] = { + t->tsnap.snapPoint[0] / t->aspect[0], + t->tsnap.snapPoint[1] / t->aspect[1], + }; + UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y); + float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize; - size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); + GPU_matrix_push_projection(); + wmOrtho2_region_pixelspace(t->region); - GPU_blend(GPU_BLEND_ALPHA); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3ub(255, 255, 255); + imm_draw_circle_wire_2d(pos, x, y, radius, 8); + immUnbindProgram(); - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_matrix_pop_projection(); + } + else if (t->spacetype == SPACE_NODE) { + ARegion *region = CTX_wm_region(C); + TransSnapPoint *p; + float size; - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); - for (p = t->tsnap.points.first; p; p = p->next) { - if (p == t->tsnap.selectedPoint) { - immUniformColor4ubv(selectedCol); - } - else { - immUniformColor4ubv(col); - } + GPU_blend(GPU_BLEND_ALPHA); - ED_node_draw_snap(®ion->v2d, p->co, size, 0, pos); - } + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - if (t->tsnap.status & POINT_INIT) { - immUniformColor4ubv(activeCol); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - ED_node_draw_snap(®ion->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos); + for (p = t->tsnap.points.first; p; p = p->next) { + if (p == t->tsnap.selectedPoint) { + immUniformColor4ubv(selectedCol); + } + else { + immUniformColor4ubv(col); } - immUnbindProgram(); + ED_node_draw_snap(®ion->v2d, p->co, size, 0, pos); + } - GPU_blend(GPU_BLEND_NONE); + if (t->tsnap.status & POINT_INIT) { + immUniformColor4ubv(activeCol); + + ED_node_draw_snap(®ion->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos); } + + immUnbindProgram(); + + GPU_blend(GPU_BLEND_NONE); } else if (t->spacetype == SPACE_SEQ) { - if (validSnap(t)) { - const ARegion *region = CTX_wm_region(C); - GPU_blend(GPU_BLEND_ALPHA); - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col); - col[3] = 128; - immUniformColor4ubv(col); - float pixelx = BLI_rctf_size_x(®ion->v2d.cur) / BLI_rcti_size_x(®ion->v2d.mask); - immRectf(pos, - t->tsnap.snapPoint[0] - pixelx, - region->v2d.cur.ymax, - t->tsnap.snapPoint[0] + pixelx, - region->v2d.cur.ymin); - immUnbindProgram(); - GPU_blend(GPU_BLEND_NONE); - } + const ARegion *region = CTX_wm_region(C); + GPU_blend(GPU_BLEND_ALPHA); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(col); + float pixelx = BLI_rctf_size_x(®ion->v2d.cur) / BLI_rcti_size_x(®ion->v2d.mask); + immRectf(pos, + t->tsnap.snapPoint[0] - pixelx, + region->v2d.cur.ymax, + t->tsnap.snapPoint[0] + pixelx, + region->v2d.cur.ymin); + immUnbindProgram(); + GPU_blend(GPU_BLEND_NONE); } } diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index cdfe40c7d35..640e89a3966 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -16,7 +16,6 @@ set(INC ../../sequencer ../../windowmanager ../../../../intern/clog - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 761e7cd091e..fd3f7c49dc4 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -13,7 +13,6 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/eigen - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c index 3877a9bb63b..68c00b18b09 100644 --- a/source/blender/editors/uvedit/uvedit_islands.c +++ b/source/blender/editors/uvedit/uvedit_islands.c @@ -76,9 +76,10 @@ static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f, static void bm_face_array_calc_bounds(BMFace **faces, int faces_len, - const uint cd_loop_uv_offset, + const int cd_loop_uv_offset, rctf *r_bounds_rect) { + BLI_assert(cd_loop_uv_offset >= 0); float bounds_min[2], bounds_max[2]; INIT_MINMAX2(bounds_min, bounds_max); for (int i = 0; i < faces_len; i++) { @@ -96,8 +97,9 @@ static void bm_face_array_calc_bounds(BMFace **faces, * without duplicating coordinates for loops that share a vertex. */ static float (*bm_face_array_calc_unique_uv_coords( - BMFace **faces, int faces_len, const uint cd_loop_uv_offset, int *r_coords_len))[2] + BMFace **faces, int faces_len, const int cd_loop_uv_offset, int *r_coords_len))[2] { + BLI_assert(cd_loop_uv_offset >= 0); int coords_len_alloc = 0; for (int i = 0; i < faces_len; i++) { BMFace *f = faces[i]; @@ -164,7 +166,7 @@ static float (*bm_face_array_calc_unique_uv_coords( static void bm_face_array_uv_rotate_fit_aabb(BMFace **faces, int faces_len, int align_to_axis, - const uint cd_loop_uv_offset) + const int cd_loop_uv_offset) { /* Calculate unique coordinates since calculating a convex hull can be an expensive operation. */ int coords_len; @@ -209,7 +211,7 @@ static void bm_face_array_uv_rotate_fit_aabb(BMFace **faces, static void bm_face_array_uv_scale_y(BMFace **faces, int faces_len, const float scale_y, - const uint cd_loop_uv_offset) + const int cd_loop_uv_offset) { for (int i = 0; i < faces_len; i++) { BMFace *f = faces[i]; @@ -311,7 +313,7 @@ static float uv_nearest_grid_tile_distance(const int udim_grid[2], * \{ */ struct SharedUVLoopData { - uint cd_loop_uv_offset; + int cd_loop_uv_offset; bool use_seams; }; @@ -338,8 +340,9 @@ int bm_mesh_calc_uv_islands(const Scene *scene, const bool only_selected_uvs, const bool use_seams, const float aspect_y, - const uint cd_loop_uv_offset) + const int cd_loop_uv_offset) { + BLI_assert(cd_loop_uv_offset >= 0); 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 6755630d3ef..c0dd7623ade 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1497,7 +1497,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) if (bm_face_is_all_uv_sel(efa, !swap, cd_loop_uv_offset)) { BM_face_select_set(em->bm, efa, false); } - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); } else { if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) { @@ -1514,7 +1514,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) } } if (!swap) { - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); } } } @@ -1536,7 +1536,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) break; } } - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); } else { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1560,7 +1560,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) } } if (!swap) { - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); } } } diff --git a/source/blender/editors/uvedit/uvedit_path.c b/source/blender/editors/uvedit/uvedit_path.c index 31a1b60167e..19218259b95 100644 --- a/source/blender/editors/uvedit/uvedit_path.c +++ b/source/blender/editors/uvedit/uvedit_path.c @@ -71,7 +71,7 @@ struct PathSelectParams { struct UserData_UV { Scene *scene; BMEditMesh *em; - uint cd_loop_uv_offset; + int cd_loop_uv_offset; }; static void path_select_properties(wmOperatorType *ot) @@ -121,7 +121,7 @@ static bool verttag_test_cb(BMLoop *l, void *user_data_v) /* All connected loops are selected or we return false. */ struct UserData_UV *user_data = user_data_v; const Scene *scene = user_data->scene; - const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset; + const int cd_loop_uv_offset = user_data->cd_loop_uv_offset; const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); BMIter iter; BMLoop *l_iter; @@ -142,7 +142,7 @@ static void verttag_set_cb(BMLoop *l, bool val, void *user_data_v) struct UserData_UV *user_data = user_data_v; const Scene *scene = user_data->scene; BMEditMesh *em = user_data->em; - const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset; + const int cd_loop_uv_offset = user_data->cd_loop_uv_offset; const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); BMIter iter; BMLoop *l_iter; @@ -150,7 +150,7 @@ static void verttag_set_cb(BMLoop *l, bool val, void *user_data_v) if (verttag_filter_cb(l_iter, user_data)) { MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); if (equals_v2v2(luv->uv, luv_iter->uv)) { - uvedit_uv_select_set(scene, em, l_iter, val, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l_iter, val, false, cd_loop_uv_offset); } } } @@ -253,7 +253,7 @@ static bool edgetag_test_cb(BMLoop *l, void *user_data_v) /* All connected loops (UV) are selected or we return false. */ struct UserData_UV *user_data = user_data_v; const Scene *scene = user_data->scene; - const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset; + const int cd_loop_uv_offset = user_data->cd_loop_uv_offset; BMIter iter; BMLoop *l_iter; BM_ITER_ELEM (l_iter, &iter, l->e, BM_LOOPS_OF_EDGE) { @@ -272,7 +272,7 @@ static void edgetag_set_cb(BMLoop *l, bool val, void *user_data_v) struct UserData_UV *user_data = user_data_v; const Scene *scene = user_data->scene; BMEditMesh *em = user_data->em; - const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset; + const int cd_loop_uv_offset = user_data->cd_loop_uv_offset; uvedit_edge_select_set_with_sticky(scene, em, l, val, false, cd_loop_uv_offset); } @@ -375,7 +375,7 @@ static bool facetag_test_cb(BMFace *f, void *user_data_v) /* All connected loops are selected or we return false. */ struct UserData_UV *user_data = user_data_v; const Scene *scene = user_data->scene; - const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset; + const int cd_loop_uv_offset = user_data->cd_loop_uv_offset; BMIter iter; BMLoop *l_iter; BM_ITER_ELEM (l_iter, &iter, f, BM_LOOPS_OF_FACE) { @@ -390,7 +390,7 @@ static void facetag_set_cb(BMFace *f, bool val, void *user_data_v) struct UserData_UV *user_data = user_data_v; const Scene *scene = user_data->scene; BMEditMesh *em = user_data->em; - const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset; + const int cd_loop_uv_offset = user_data->cd_loop_uv_offset; uvedit_face_select_set_with_sticky(scene, em, f, val, false, cd_loop_uv_offset); } diff --git a/source/blender/editors/uvedit/uvedit_rip.c b/source/blender/editors/uvedit/uvedit_rip.c index 545cc57e3c4..52e92b2e3c5 100644 --- a/source/blender/editors/uvedit/uvedit_rip.c +++ b/source/blender/editors/uvedit/uvedit_rip.c @@ -848,7 +848,7 @@ static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter); ULData *ul = UL(l_iter); if (ul->side == side_from_cursor) { - uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, em->bm, l_iter, cd_loop_uv_offset); changed = true; } /* Ensure we don't operate on these again. */ @@ -866,7 +866,7 @@ static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter); ULData *ul = UL(l_iter); if (ul->side == side_from_cursor) { - uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, em->bm, l_iter, cd_loop_uv_offset); changed = true; } /* Ensure we don't operate on these again. */ diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index d88da21ef98..cecf0ff7914 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -207,7 +207,7 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em, BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); } } } @@ -265,7 +265,7 @@ void uvedit_face_select_set_with_sticky(const Scene *scene, const ToolSettings *ts = scene->toolsettings; const char sticky = ts->uv_sticky; if (ts->uv_flag & UV_SYNC_SELECTION) { - uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset); return; } if (!uvedit_face_visible_test(scene, efa)) { @@ -275,7 +275,7 @@ void uvedit_face_select_set_with_sticky(const Scene *scene, * (not part of any face selections). This now uses the sticky location mode logic instead. */ switch (sticky) { case SI_STICKY_DISABLE: { - uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset); break; } default: { @@ -313,32 +313,30 @@ void uvedit_face_select_shared_vert(const Scene *scene, } void uvedit_face_select_set(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset) { if (select) { - uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + uvedit_face_select_enable(scene, bm, efa, do_history, cd_loop_uv_offset); } else { - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + uvedit_face_select_disable(scene, bm, efa, cd_loop_uv_offset); } } -void uvedit_face_select_enable(const Scene *scene, - BMEditMesh *em, - BMFace *efa, - const bool do_history, - const int cd_loop_uv_offset) +void uvedit_face_select_enable( + const Scene *scene, BMesh *bm, BMFace *efa, const bool do_history, const int cd_loop_uv_offset) { + BLI_assert(cd_loop_uv_offset >= 0); const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, true); + BM_face_select_set(bm, efa, true); if (do_history) { - BM_select_history_store(em->bm, (BMElem *)efa); + BM_select_history_store(bm, (BMElem *)efa); } } else { @@ -354,14 +352,15 @@ void uvedit_face_select_enable(const Scene *scene, } void uvedit_face_select_disable(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMFace *efa, const int cd_loop_uv_offset) { + BLI_assert(cd_loop_uv_offset >= 0); const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, false); + BM_face_select_set(bm, efa, false); } else { BMLoop *l; @@ -407,11 +406,11 @@ void uvedit_edge_select_set_with_sticky(const Scene *scene, BMLoop *l, const bool select, const bool do_history, - const uint cd_loop_uv_offset) + const int cd_loop_uv_offset) { const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { - uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); return; } @@ -419,7 +418,7 @@ void uvedit_edge_select_set_with_sticky(const Scene *scene, switch (sticky) { case SI_STICKY_DISABLE: { if (uvedit_face_visible_test(scene, l->f)) { - uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); } break; } @@ -501,7 +500,7 @@ void uvedit_edge_select_set_noflush(const Scene *scene, } void uvedit_edge_select_set(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const bool select, const bool do_history, @@ -509,36 +508,33 @@ void uvedit_edge_select_set(const Scene *scene, { if (select) { - uvedit_edge_select_enable(scene, em, l, do_history, cd_loop_uv_offset); + uvedit_edge_select_enable(scene, bm, l, do_history, cd_loop_uv_offset); } else { - uvedit_edge_select_disable(scene, em, l, cd_loop_uv_offset); + uvedit_edge_select_disable(scene, bm, l, cd_loop_uv_offset); } } -void uvedit_edge_select_enable(const Scene *scene, - BMEditMesh *em, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) +void uvedit_edge_select_enable( + const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) { const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); + BM_face_select_set(bm, l->f, true); } else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, true); + BM_edge_select_set(bm, l->e, true); } else { - BM_vert_select_set(em->bm, l->e->v1, true); - BM_vert_select_set(em->bm, l->e->v2, true); + BM_vert_select_set(bm, l->e->v1, true); + BM_vert_select_set(bm, l->e->v2, true); } if (do_history) { - BM_select_history_store(em->bm, (BMElem *)l->e); + BM_select_history_store(bm, (BMElem *)l->e); } } else { @@ -552,7 +548,7 @@ void uvedit_edge_select_enable(const Scene *scene, } void uvedit_edge_select_disable(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const int cd_loop_uv_offset) @@ -561,14 +557,14 @@ void uvedit_edge_select_disable(const Scene *scene, if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); + BM_face_select_set(bm, l->f, false); } else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, false); + BM_edge_select_set(bm, l->e, false); } else { - BM_vert_select_set(em->bm, l->e->v1, false); - BM_vert_select_set(em->bm, l->e->v2, false); + BM_vert_select_set(bm, l->e->v1, false); + BM_vert_select_set(bm, l->e->v2, false); } } else { @@ -629,11 +625,11 @@ void uvedit_uv_select_set_with_sticky(const Scene *scene, BMLoop *l, const bool select, const bool do_history, - const uint cd_loop_uv_offset) + const int cd_loop_uv_offset) { const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { - uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); return; } @@ -641,7 +637,7 @@ void uvedit_uv_select_set_with_sticky(const Scene *scene, switch (sticky) { case SI_STICKY_DISABLE: { if (uvedit_face_visible_test(scene, l->f)) { - uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); } break; } @@ -695,7 +691,8 @@ void uvedit_uv_select_shared_vert(const Scene *scene, } if (do_select) { - uvedit_uv_select_set(scene, em, l_radial_iter, select, do_history, cd_loop_uv_offset); + uvedit_uv_select_set( + scene, em->bm, l_radial_iter, select, do_history, cd_loop_uv_offset); } } } @@ -704,25 +701,22 @@ void uvedit_uv_select_shared_vert(const Scene *scene, } void uvedit_uv_select_set(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset) { if (select) { - uvedit_uv_select_enable(scene, em, l, do_history, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, bm, l, do_history, cd_loop_uv_offset); } else { - uvedit_uv_select_disable(scene, em, l, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, bm, l, cd_loop_uv_offset); } } -void uvedit_uv_select_enable(const Scene *scene, - BMEditMesh *em, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) +void uvedit_uv_select_enable( + const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) { const ToolSettings *ts = scene->toolsettings; @@ -732,14 +726,14 @@ void uvedit_uv_select_enable(const Scene *scene, if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); + BM_face_select_set(bm, l->f, true); } else { - BM_vert_select_set(em->bm, l->v, true); + BM_vert_select_set(bm, l->v, true); } if (do_history) { - BM_select_history_store(em->bm, (BMElem *)l->v); + BM_select_history_store(bm, (BMElem *)l->v); } } else { @@ -749,7 +743,7 @@ void uvedit_uv_select_enable(const Scene *scene, } void uvedit_uv_select_disable(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const int cd_loop_uv_offset) { @@ -757,10 +751,10 @@ void uvedit_uv_select_disable(const Scene *scene, if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); + BM_face_select_set(bm, l->f, false); } else { - BM_vert_select_set(em->bm, l->v, false); + BM_vert_select_set(bm, l->v, false); } } else { @@ -1140,7 +1134,7 @@ BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene, const float co[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); - const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BMIter liter; BMLoop *l; @@ -1168,7 +1162,8 @@ BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene, const float co[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); - const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BLI_assert(cd_loop_uv_offset >= 0); BMIter eiter; BMLoop *l; @@ -1975,7 +1970,7 @@ static void uv_select_linked_multi(Scene *scene, BM_face_select_set(em->bm, efa, value); \ } \ else { \ - uvedit_face_select_set(scene, em, efa, value, false, cd_loop_uv_offset); \ + uvedit_face_select_set(scene, em->bm, efa, value, false, cd_loop_uv_offset); \ } \ (void)0 @@ -3247,7 +3242,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, UvMapVert *start_vlist = NULL, *vlist_iter; BMFace *efa_vlist; - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); @@ -3265,7 +3260,6 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, vlist_iter = start_vlist; while (vlist_iter) { - if (vlist_iter != start_vlist && vlist_iter->separate) { break; } @@ -3278,7 +3272,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, l_other = BM_iter_at_index( em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); - uvedit_uv_select_set(scene, em, l_other, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l_other, select, false, cd_loop_uv_offset); } vlist_iter = vlist_iter->next; } @@ -3345,7 +3339,7 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, select, false, cd_loop_uv_offset); } } } @@ -3394,7 +3388,7 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); } } } @@ -3423,7 +3417,7 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); } } } @@ -3644,14 +3638,14 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { /* UV_SYNC_SELECTION - can't do pinned selection */ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; } } else if (pinned) { if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); } } @@ -3718,9 +3712,9 @@ void UV_OT_select_box(wmOperatorType *ot) /** \name Circle Select Operator * \{ */ -static int uv_circle_select_is_point_inside(const float uv[2], - const float offset[2], - const float ellipse[2]) +static bool uv_circle_select_is_point_inside(const float uv[2], + const float offset[2], + const float ellipse[2]) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ const float co[2] = { @@ -3730,10 +3724,10 @@ static int uv_circle_select_is_point_inside(const float uv[2], return len_squared_v2(co) < 1.0f; } -static int uv_circle_select_is_edge_inside(const float uv_a[2], - const float uv_b[2], - const float offset[2], - const float ellipse[2]) +static bool uv_circle_select_is_edge_inside(const float uv_a[2], + const float uv_b[2], + const float offset[2], + const float ellipse[2]) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ const float co_a[2] = { @@ -3864,7 +3858,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) { changed = true; - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; } @@ -4094,7 +4088,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (do_lasso_select_mesh_uv_is_point_inside( region, &rect, mcoords, mcoords_len, luv->uv)) { - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; @@ -4214,7 +4208,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (luv->flag & MLOOPUV_PINNED) { - uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em->bm, l, false, cd_loop_uv_offset); changed = true; } } @@ -4467,8 +4461,8 @@ static int uv_select_overlap(bContext *C, const bool extend) /* Main tri-tri overlap test. */ const float endpoint_bias = -1e-4f; if (overlap_tri_tri_uv_test(o_a->tri, o_b->tri, endpoint_bias)) { - uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a); - uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b); + uvedit_face_select_enable(scene, em_a->bm, face_a, false, cd_loop_uv_offset_a); + uvedit_face_select_enable(scene, em_b->bm, face_b, false, cd_loop_uv_offset_b); } } @@ -4764,7 +4758,7 @@ static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) const float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset); bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); if (select) { - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); changed = true; } } @@ -4883,7 +4877,7 @@ static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset); bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); if (select) { - uvedit_edge_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_edge_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); changed = true; } } @@ -4983,7 +4977,7 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op) bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); if (select) { - uvedit_face_select_set(scene, em, face, select, do_history, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, face, select, do_history, cd_loop_uv_offset); changed = true; } } @@ -5103,7 +5097,7 @@ static int uv_select_similar_island_exec(bContext *C, wmOperator *op) 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); + scene, em->bm, island->faces[j], select, do_history, island->cd_loop_uv_offset); } changed = true; } @@ -5487,7 +5481,7 @@ void ED_uvedit_selectmode_clean(const Scene *scene, Object *obedit) if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); } - uvedit_face_select_set(scene, em, efa, false, false, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, false, false, cd_loop_uv_offset); } } uv_select_flush_from_tag_face(scene, obedit, true); diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 4a2ea5c3aa6..e38f9898f39 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -916,7 +916,7 @@ static void stitch_propagate_uv_final_position(Scene *scene, if (final) { copy_v2_v2(luv->uv, final_position[index].uv); - uvedit_uv_select_enable(scene, state->em, l, false, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, state->em->bm, l, false, cd_loop_uv_offset); } else { int face_preview_pos = diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 2c7ad012dd2..b01a24af68f 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1714,10 +1714,12 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot) * such as "Unwrap" & "Smart UV Projections" will need to handle aspect correction themselves. * For now keep using a single aspect for all faces in this case. */ -static void uv_map_clip_correct_multi(Object **objects, - uint objects_len, - wmOperator *op, - bool per_face_aspect) +static void uv_map_clip_correct(const Scene *scene, + Object **objects, + uint objects_len, + wmOperator *op, + bool per_face_aspect, + bool only_selected_uvs) { BMFace *efa; BMLoop *l; @@ -1754,6 +1756,10 @@ static void uv_map_clip_correct_multi(Object **objects, continue; } + if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + continue; + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); minmax_v2v2_v2(min, max, luv->uv); @@ -1767,6 +1773,10 @@ static void uv_map_clip_correct_multi(Object **objects, continue; } + if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + continue; + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); clamp_v2(luv->uv, 0.0f, 1.0f); @@ -1803,6 +1813,10 @@ static void uv_map_clip_correct_multi(Object **objects, continue; } + if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + continue; + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -1814,11 +1828,6 @@ static void uv_map_clip_correct_multi(Object **objects, } } -static void uv_map_clip_correct(Object *ob, wmOperator *op) -{ - uv_map_clip_correct_multi(&ob, 1, op, true); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -2245,6 +2254,12 @@ static int smart_project_exec(bContext *C, wmOperator *op) /* May be NULL. */ View3D *v3d = CTX_wm_view3d(C); + bool only_selected_uvs = false; + if (CTX_wm_space_image(C)) { + /* Inside the UV Editor, only project selected UVs. */ + only_selected_uvs = true; + } + const float project_angle_limit = RNA_float_get(op->ptr, "angle_limit"); const float island_margin = RNA_float_get(op->ptr, "island_margin"); const float area_weight = RNA_float_get(op->ptr, "area_weight"); @@ -2275,7 +2290,8 @@ static int smart_project_exec(bContext *C, wmOperator *op) continue; } - const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BLI_assert(cd_loop_uv_offset >= 0); ThickFace *thick_faces = MEM_mallocN(sizeof(*thick_faces) * em->bm->totface, __func__); uint thick_faces_len = 0; @@ -2283,6 +2299,14 @@ static int smart_project_exec(bContext *C, wmOperator *op) if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { continue; } + + if (only_selected_uvs) { + if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); + continue; + } + } + thick_faces[thick_faces_len].area = BM_face_calc_area(efa); thick_faces[thick_faces_len].efa = efa; thick_faces_len++; @@ -2397,6 +2421,7 @@ static int smart_project_exec(bContext *C, wmOperator *op) .rotate = true, /* We could make this optional. */ .rotate_align_axis = 1, + .only_selected_uvs = true, .only_selected_faces = true, .correct_aspect = correct_aspect, .use_seams = true, @@ -2404,7 +2429,8 @@ static int smart_project_exec(bContext *C, wmOperator *op) /* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */ const bool per_face_aspect = false; - uv_map_clip_correct_multi(objects_changed, object_changed_len, op, per_face_aspect); + uv_map_clip_correct( + scene, objects_changed, object_changed_len, op, per_face_aspect, only_selected_uvs); } MEM_freeN(objects_changed); @@ -2606,7 +2632,9 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) } if (changed_multi) { - uv_map_clip_correct_multi(objects, objects_len, op, true); + const bool per_face_aspect = true; + const bool only_selected_uvs = false; + uv_map_clip_correct(scene, objects, objects_len, op, per_face_aspect, only_selected_uvs); } MEM_freeN(objects); @@ -2766,6 +2794,12 @@ static int sphere_project_exec(bContext *C, wmOperator *op) const Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); + bool only_selected_uvs = false; + if (CTX_wm_space_image(C)) { + /* Inside the UV Editor, only project selected UVs. */ + only_selected_uvs = true; + } + ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( @@ -2798,6 +2832,13 @@ static int sphere_project_exec(bContext *C, wmOperator *op) continue; } + if (only_selected_uvs) { + if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); + continue; + } + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -2807,7 +2848,8 @@ static int sphere_project_exec(bContext *C, wmOperator *op) uv_map_mirror(em, efa); } - uv_map_clip_correct(obedit, op); + const bool per_face_aspect = true; + uv_map_clip_correct(scene, &obedit, 1, op, per_face_aspect, only_selected_uvs); DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); @@ -2864,6 +2906,12 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) const Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); + bool only_selected_uvs = false; + if (CTX_wm_space_image(C)) { + /* Inside the UV Editor, only project selected UVs. */ + only_selected_uvs = true; + } + ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( @@ -2896,16 +2944,21 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) continue; } + if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); + continue; + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv_cylinder_project(luv->uv, l->v->co, center, rotmat); } uv_map_mirror(em, efa); } - uv_map_clip_correct(obedit, op); + const bool per_face_aspect = true; + uv_map_clip_correct(scene, &obedit, 1, op, per_face_aspect, only_selected_uvs); DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); @@ -2939,9 +2992,11 @@ void UV_OT_cylinder_project(wmOperatorType *ot) /** \name Cube UV Project Operator * \{ */ -static void uvedit_unwrap_cube_project(BMesh *bm, +static void uvedit_unwrap_cube_project(const Scene *scene, + BMesh *bm, float cube_size, - bool use_select, + const bool use_select, + const bool only_selected_uvs, const float center[3]) { BMFace *efa; @@ -2973,6 +3028,10 @@ static void uvedit_unwrap_cube_project(BMesh *bm, if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { continue; } + if (only_selected_uvs && !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + uvedit_face_select_disable(scene, bm, efa, cd_loop_uv_offset); + continue; + } axis_dominant_v3(&cox, &coy, efa->no); @@ -2989,6 +3048,12 @@ static int cube_project_exec(bContext *C, wmOperator *op) const Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); + bool only_selected_uvs = false; + if (CTX_wm_space_image(C)) { + /* Inside the UV Editor, only cube project selected UVs. */ + only_selected_uvs = true; + } + PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size"); const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size); @@ -3031,9 +3096,10 @@ static int cube_project_exec(bContext *C, wmOperator *op) } } - uvedit_unwrap_cube_project(em->bm, cube_size, true, center); + uvedit_unwrap_cube_project(scene, em->bm, cube_size, true, only_selected_uvs, center); - uv_map_clip_correct(obedit, op); + const bool per_face_aspect = true; + uv_map_clip_correct(scene, &obedit, 1, op, per_face_aspect, only_selected_uvs); DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); @@ -3100,7 +3166,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob) /* select all uv loops first - pack parameters needs this to make sure charts are registered */ ED_uvedit_select_all(bm); /* A cube size of 2.0 maps [-1..1] vertex coords to [0.0..1.0] in UV coords. */ - uvedit_unwrap_cube_project(bm, 2.0, false, NULL); + uvedit_unwrap_cube_project(scene, bm, 2.0, false, false, NULL); /* Set the margin really quickly before the packing operation. */ scene->toolsettings->uvcalc_margin = 0.001f; uvedit_pack_islands(scene, ob, bm); diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt index c2fad9fef3a..40db98ebd74 100644 --- a/source/blender/freestyle/CMakeLists.txt +++ b/source/blender/freestyle/CMakeLists.txt @@ -548,7 +548,6 @@ set(INC ../python/intern ../render ../render/intern - ../../../extern/glew/include ../../../intern/guardedalloc # RNA_prototypes.h diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index e76e74b89e4..ab357890096 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -77,6 +77,11 @@ NodeGroup *BlenderFileLoader::Load() continue; } + /* Evaluated metaballs will appear as mesh objects in the iterator. */ + if (ob->type == OB_MBALL) { + continue; + } + Mesh *mesh = BKE_object_to_mesh(nullptr, ob, false); if (mesh) { diff --git a/source/blender/freestyle/intern/geometry/FastGrid.h b/source/blender/freestyle/intern/geometry/FastGrid.h index 3d9ec6a64ca..b835e109faa 100644 --- a/source/blender/freestyle/intern/geometry/FastGrid.h +++ b/source/blender/freestyle/intern/geometry/FastGrid.h @@ -12,7 +12,7 @@ namespace Freestyle { /** Class to define a regular grid used for ray casting computations - * We don't use a hashtable here. The grid is explicitly stored for faster computations. + * We don't use a hash-table here. The grid is explicitly stored for faster computations. * However, this might result in significant increase in memory usage * (compared to the regular grid). */ @@ -31,7 +31,7 @@ class FastGrid : public Grid { /** * clears the grid - * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells. + * Deletes all the cells, clears the hash-table, resets size, size of cell, number of cells. */ virtual void clear(); diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h index c25594e620f..d66982eef52 100644 --- a/source/blender/freestyle/intern/geometry/Grid.h +++ b/source/blender/freestyle/intern/geometry/Grid.h @@ -187,7 +187,7 @@ class Grid { } /** clears the grid - * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells. + * Deletes all the cells, clears the hash-table, resets size, size of cell, number of cells. */ virtual void clear(); diff --git a/source/blender/freestyle/intern/geometry/HashGrid.h b/source/blender/freestyle/intern/geometry/HashGrid.h index b08334d3474..18eeb579d07 100644 --- a/source/blender/freestyle/intern/geometry/HashGrid.h +++ b/source/blender/freestyle/intern/geometry/HashGrid.h @@ -52,7 +52,7 @@ class HashGrid : public Grid { } /** clears the grid - * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells. + * Deletes all the cells, clears the hash-table, resets size, size of cell, number of cells. */ virtual void clear(); diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 4b3b184536b..87a610ac0a2 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -14,6 +14,7 @@ #include "BKE_collection.h" #include "BKE_curves.hh" +#include "BKE_deform.h" #include "BKE_geometry_set_instances.hh" #include "BKE_material.h" #include "BKE_mesh.h" @@ -997,6 +998,9 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, const RealizeMeshTask &first_task = tasks.first(); const Mesh &first_mesh = *first_task.mesh_info->mesh; BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh); + /* The above line also copies vertex group names. We don't want that here because the new + * attributes are added explicitly below. */ + BLI_freelistN(&dst_mesh->vertex_group_names); /* Add materials. */ for (const int i : IndexRange(ordered_materials.size())) { diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc index e252e28805e..e4cb99a9eac 100644 --- a/source/blender/geometry/intern/resample_curves.cc +++ b/source/blender/geometry/intern/resample_curves.cc @@ -368,7 +368,7 @@ Curves *resample_to_evaluated(const CurveComponent &src_component, dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY); MutableSpan<int> dst_offsets = dst_curves.offsets_for_write(); - src_curves.ensure_evaluated_offsets(); + src_curves.ensure_can_interpolate_to_evaluated(); threading::parallel_for(selection.index_range(), 4096, [&](IndexRange range) { for (const int i : selection.slice(range)) { dst_offsets[i] = src_curves.evaluated_points_for_curve(i).size(); diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index 947fc32f8c0..5ef9ae1bbc6 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -94,8 +94,6 @@ endif() set(LIB ) -add_definitions(${GL_DEFINITIONS}) - blender_add_lib(bf_gpencil_modifiers "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") add_dependencies(bf_gpencil_modifiers bf_dna) diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 63433113822..ad0dd8a030a 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -483,6 +483,7 @@ typedef struct LineartRenderTaskInfo { typedef struct LineartObjectInfo { struct LineartObjectInfo *next; struct Object *original_ob; + struct Object *original_ob_eval; /* For evaluated materials */ struct Mesh *original_me; double model_view_proj[4][4]; double model_view[4][4]; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 0fd1d8ff51d..ce0a00f5e51 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1470,7 +1470,7 @@ static LineartTriangle *lineart_triangle_from_index(LineartData *ld, typedef struct EdgeFeatData { LineartData *ld; Mesh *me; - Object *ob; + Object *ob_eval; /* For evaluated materials. */ const MLoopTri *mlooptri; LineartTriangle *tri_array; LineartVert *v_array; @@ -1503,7 +1503,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata; EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk; Mesh *me = e_feat_data->me; - Object *ob = e_feat_data->ob; + Object *ob_eval = e_feat_data->ob_eval; LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr; const MLoopTri *mlooptri = e_feat_data->mlooptri; @@ -1653,8 +1653,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr; if (mat1 != mat2) { - Material *m1 = BKE_object_material_get(ob, mat1 + 1); - Material *m2 = BKE_object_material_get(ob, mat2 + 1); + Material *m1 = BKE_object_material_get_eval(ob_eval, mat1 + 1); + Material *m2 = BKE_object_material_get_eval(ob_eval, mat2 + 1); if (m1 && m2 && ((m1->lineart.mat_occlusion == 0 && m2->lineart.mat_occlusion != 0) || (m2->lineart.mat_occlusion == 0 && m1->lineart.mat_occlusion != 0))) { @@ -1869,8 +1869,8 @@ static void lineart_load_tri_task(void *__restrict userdata, tri->v[2] = &vert_arr[v3]; /* Material mask bits and occlusion effectiveness assignment. */ - Material *mat = BKE_object_material_get(ob_info->original_ob, - me->mpoly[mlooptri->poly].mat_nr + 1); + Material *mat = BKE_object_material_get_eval(ob_info->original_ob_eval, + me->mpoly[mlooptri->poly].mat_nr + 1); tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ? mat->lineart.material_mask_bits : 0); @@ -2120,7 +2120,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, EdgeFeatData edge_feat_data = {0}; edge_feat_data.ld = la_data; edge_feat_data.me = me; - edge_feat_data.ob = orig_ob; + edge_feat_data.ob_eval = ob_info->original_ob_eval; edge_feat_data.mlooptri = mlooptri; edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges); edge_feat_data.tri_array = la_tri_arr; @@ -2511,6 +2511,7 @@ static void lineart_object_load_single_instance(LineartData *ld, obi->original_me = use_mesh; obi->original_ob = (ref_ob->id.orig_id ? (Object *)ref_ob->id.orig_id : (Object *)ref_ob); + obi->original_ob_eval = DEG_get_evaluated_object(depsgraph, obi->original_ob); lineart_geometry_load_assign_thread(olti, obi, thread_count, use_mesh->totpoly); } @@ -4091,7 +4092,6 @@ static bool lineart_bounding_area_triangle_intersect(LineartData *fb, * (#LineartBoundingArea) for intersection lines. When splitting the tile into 4 children and * re-linking triangles into the child tiles, intersections are inhibited so we don't get * duplicated intersection lines. - * */ static void lineart_bounding_area_link_triangle(LineartData *ld, LineartBoundingArea *root_ba, @@ -5227,7 +5227,7 @@ static void lineart_gpencil_generate(LineartCache *cache, } if (shaodow_selection) { if (ec->shadow_mask_bits != LRT_SHADOW_MASK_UNDEFINED) { - /* TODO(Yiming): Give a behavior option for how to display undefined shadow info. */ + /* TODO(@Yiming): Give a behavior option for how to display undefined shadow info. */ if ((shaodow_selection == LRT_SHADOW_FILTER_ILLUMINATED && (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED)))) { continue; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 65a6a2dc6b7..9469db1d842 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -34,13 +34,12 @@ set(INC ../../../intern/atomic ../../../intern/clog ../../../intern/ghost - ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/mantaflow/extern ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${Epoxy_INCLUDE_DIRS} ) set(SRC @@ -93,12 +92,10 @@ set(SRC GPU_debug.h GPU_drawlist.h GPU_framebuffer.h - GPU_glew.h GPU_immediate.h GPU_immediate_util.h GPU_index_buffer.h GPU_init_exit.h - GPU_legacy_stubs.h GPU_material.h GPU_matrix.h GPU_platform.h @@ -224,15 +221,9 @@ if(WITH_METAL_BACKEND) endif() set(LIB - ${BLENDER_GL_LIBRARIES} + ${Epoxy_LIBRARIES} ) -if(NOT WITH_SYSTEM_GLEW) - list(APPEND LIB - ${BLENDER_GLEW_LIBRARIES} - ) -endif() - set(MSL_SRC metal/kernels/compute_texture_update.msl @@ -324,9 +315,15 @@ set(GLSL_SRC shaders/common/gpu_shader_common_mix_rgb.glsl shaders/compositor/compositor_alpha_crop.glsl + shaders/compositor/compositor_bilateral_blur.glsl + shaders/compositor/compositor_bokeh_image.glsl shaders/compositor/compositor_box_mask.glsl shaders/compositor/compositor_convert.glsl + shaders/compositor/compositor_despeckle.glsl + shaders/compositor/compositor_directional_blur.glsl + shaders/compositor/compositor_edge_filter.glsl shaders/compositor/compositor_ellipse_mask.glsl + shaders/compositor/compositor_filter.glsl shaders/compositor/compositor_flip.glsl shaders/compositor/compositor_image_crop.glsl shaders/compositor/compositor_projector_lens_distortion.glsl @@ -495,6 +492,8 @@ 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_hiz_info.hh + ../draw/engines/eevee_next/shaders/infos/eevee_light_culling_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 @@ -568,9 +567,15 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/gpu_srgb_to_framebuffer_space_info.hh shaders/compositor/infos/compositor_alpha_crop_info.hh + shaders/compositor/infos/compositor_bilateral_blur_info.hh + shaders/compositor/infos/compositor_bokeh_image_info.hh shaders/compositor/infos/compositor_box_mask_info.hh shaders/compositor/infos/compositor_convert_info.hh + shaders/compositor/infos/compositor_despeckle_info.hh + shaders/compositor/infos/compositor_directional_blur_info.hh + shaders/compositor/infos/compositor_edge_filter_info.hh shaders/compositor/infos/compositor_ellipse_mask_info.hh + shaders/compositor/infos/compositor_filter_info.hh shaders/compositor/infos/compositor_flip_info.hh shaders/compositor/infos/compositor_image_crop_info.hh shaders/compositor/infos/compositor_projector_lens_distortion_info.hh @@ -592,8 +597,6 @@ if(WITH_MOD_FLUID) add_definitions(-DWITH_FLUID) endif() -add_definitions(${GL_DEFINITIONS}) - if(WITH_IMAGE_DDS) add_definitions(-DWITH_DDS) endif() diff --git a/source/blender/gpu/GPU_compute.h b/source/blender/gpu/GPU_compute.h index 6dfd6f73ae8..ff94620f186 100644 --- a/source/blender/gpu/GPU_compute.h +++ b/source/blender/gpu/GPU_compute.h @@ -20,7 +20,7 @@ void GPU_compute_dispatch(GPUShader *shader, uint groups_y_len, uint groups_z_len); -void GPU_compute_dispatch_indirect(GPUShader *shader, GPUStorageBuf *indirect_buf); +void GPU_compute_dispatch_indirect(GPUShader *shader, GPUStorageBuf *indirect_buf_); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_glew.h b/source/blender/gpu/GPU_glew.h deleted file mode 100644 index 38209a0eb17..00000000000 --- a/source/blender/gpu/GPU_glew.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2012 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup gpu - */ - -#pragma once - -#if defined(WITH_OPENGL) -# include "glew-mx.h" -# ifndef WITH_LEGACY_OPENGL -# include "GPU_legacy_stubs.h" -# endif -#endif diff --git a/source/blender/gpu/GPU_legacy_stubs.h b/source/blender/gpu/GPU_legacy_stubs.h deleted file mode 100644 index 5970738a9b3..00000000000 --- a/source/blender/gpu/GPU_legacy_stubs.h +++ /dev/null @@ -1,497 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2017 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup gpu - * - * This is to mark the transition to OpenGL core profile - * The idea is to allow Blender 2.8 to be built with OpenGL 3.3 even if it means breaking things - * - * This file should be removed in the future - */ - -#pragma once - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-parameter" -# pragma GCC diagnostic ignored "-Wunused-function" -#endif - -#include <stdlib.h> /* for abort(). */ - -#include "BLI_utildefines.h" - -/** - * Empty function, use for break-point when a deprecated - * OpenGL function is called. - */ -static void gl_deprecated(void) -{ - BLI_assert(true); -} - -#define _GL_BOOL BLI_INLINE GLboolean -#define _GL_BOOL_RET \ - { \ - gl_deprecated(); \ - return false; \ - } - -#define _GL_ENUM BLI_INLINE GLenum -#define _GL_ENUM_RET \ - { \ - gl_deprecated(); \ - return 0; \ - } - -#define _GL_INT BLI_INLINE GLint -#define _GL_INT_RET \ - { \ - gl_deprecated(); \ - return 0; \ - } - -#define _GL_UINT BLI_INLINE GLuint -#define _GL_UINT_RET \ - { \ - gl_deprecated(); \ - return 0; \ - } - -#define _GL_VOID BLI_INLINE void -#define _GL_VOID_RET \ - { \ - gl_deprecated(); \ - } - -static bool disable_enable_check(GLenum cap) -{ - const bool is_deprecated = ELEM(cap, - GL_ALPHA_TEST, - GL_LINE_STIPPLE, - GL_POINT_SPRITE, - GL_TEXTURE_1D, - GL_TEXTURE_2D, - GL_TEXTURE_GEN_S, - GL_TEXTURE_GEN_T, - -1); - - if (is_deprecated) { - gl_deprecated(); - } - - return is_deprecated; -} - -_GL_VOID USE_CAREFULLY_glDisable(GLenum cap) -{ - if (!disable_enable_check(cap)) { - glDisable(cap); - } -} -#define glDisable USE_CAREFULLY_glDisable - -_GL_VOID USE_CAREFULLY_glEnable(GLenum cap) -{ - if (!disable_enable_check(cap)) { - glEnable(cap); - } -} -#define glEnable USE_CAREFULLY_glEnable - -/** - * Hand written cases - */ - -_GL_VOID DO_NOT_USE_glClientActiveTexture(GLenum texture) _GL_VOID_RET - -/** - * List automatically generated from `gl-deprecated.h` and `glew.h` - */ - -/** - * ENUM values - */ -#define DO_NOT_USE_GL_CURRENT_FOG_COORDINATE 0 -#define DO_NOT_USE_GL_FOG_COORDINATE 0 -#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY 0 -#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0 -#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_POINTER 0 -#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_STRIDE 0 -#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_TYPE 0 -#define DO_NOT_USE_GL_FOG_COORDINATE_SOURCE 0 -#define DO_NOT_USE_GL_POINT_SIZE_GRANULARITY 0 -#define DO_NOT_USE_GL_POINT_SIZE_RANGE 0 -#define DO_NOT_USE_GL_SOURCE0_ALPHA 0 -#define DO_NOT_USE_GL_SOURCE0_RGB 0 -#define DO_NOT_USE_GL_SOURCE1_ALPHA 0 -#define DO_NOT_USE_GL_SOURCE1_RGB 0 -#define DO_NOT_USE_GL_SOURCE2_ALPHA 0 -#define DO_NOT_USE_GL_SOURCE2_RGB 0 - - /** - * Functions - */ - _GL_VOID DO_NOT_USE_glAccum(GLenum op, GLfloat value) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glAlphaFunc(GLenum func, GLclampf ref) _GL_VOID_RET _GL_BOOL - DO_NOT_USE_glAreTexturesResident(GLsizei n, - const GLuint *textures, - GLboolean *residences) _GL_BOOL_RET _GL_VOID - DO_NOT_USE_glArrayElement(GLint i) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glBegin(GLenum mode) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glBitmap(GLsizei width, - GLsizei height, - GLfloat xorig, - GLfloat yorig, - GLfloat xmove, - GLfloat ymove, - const GLubyte *bitmap) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glCallList(GLuint list) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glCallLists(GLsizei n, GLenum type, const void *lists) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glClearIndex(GLfloat c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glClipPlane(GLenum plane, const GLdouble *equation) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3b(GLbyte red, GLbyte green, GLbyte blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3bv(const GLbyte *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3d(GLdouble red, GLdouble green, GLdouble blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3f(GLfloat red, GLfloat green, GLfloat blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3i(GLint red, GLint green, GLint blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3s(GLshort red, GLshort green, GLshort blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3ub(GLubyte red, GLubyte green, GLubyte blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3ubv(const GLubyte *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3ui(GLuint red, GLuint green, GLuint blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3uiv(const GLuint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3us(GLushort red, GLushort green, GLushort blue) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor3usv(const GLushort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4bv(const GLbyte *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glColor4dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glColor4fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4i(GLint red, GLint green, GLint blue, GLint alpha) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glColor4sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glColor4ubv(const GLubyte *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glColor4uiv(const GLuint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glColor4usv(const GLushort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColorMaterial(GLenum face, GLenum mode) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) - _GL_VOID_RET _GL_VOID - DO_NOT_USE_glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) - _GL_VOID_RET _GL_VOID - DO_NOT_USE_glDeleteLists(GLuint list, GLsizei range) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glDisableClientState(GLenum array) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glDrawPixels(GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - const void *pixels) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEdgeFlag(GLboolean flag) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEdgeFlagPointer(GLsizei stride, const void *pointer) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEdgeFlagv(const GLboolean *flag) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEnableClientState(GLenum array) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEnd(void) _GL_VOID_RET _GL_VOID DO_NOT_USE_glEndList(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord1d(GLdouble u) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord1dv(const GLdouble *u) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord1f(GLfloat u) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord1fv(const GLfloat *u) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord2d(GLdouble u, GLdouble v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord2dv(const GLdouble *u) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord2f(GLfloat u, GLfloat v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalCoord2fv(const GLfloat *u) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalMesh1(GLenum mode, GLint i1, GLint i2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) - _GL_VOID_RET _GL_VOID DO_NOT_USE_glEvalPoint1(GLint i) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glEvalPoint2(GLint i, GLint j) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glFogf(GLenum pname, GLfloat param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glFogfv(GLenum pname, const GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glFogi(GLenum pname, GLint param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glFogiv(GLenum pname, const GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glFrustum(GLdouble left, - GLdouble right, - GLdouble bottom, - GLdouble top, - GLdouble zNear, - GLdouble zFar) _GL_VOID_RET _GL_UINT - DO_NOT_USE_glGenLists(GLsizei range) _GL_UINT_RET _GL_VOID - DO_NOT_USE_glGetClipPlane(GLenum plane, GLdouble *equation) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetLightfv(GLenum light, GLenum pname, GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetLightiv(GLenum light, GLenum pname, GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetMapdv(GLenum target, GLenum query, GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetMapfv(GLenum target, GLenum query, GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetMapiv(GLenum target, GLenum query, GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetMaterialfv(GLenum face, GLenum pname, GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetMaterialiv(GLenum face, GLenum pname, GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetPixelMapfv(GLenum map, GLfloat *values) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetPixelMapuiv(GLenum map, GLuint *values) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetPixelMapusv(GLenum map, GLushort *values) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetPolygonStipple(GLubyte *mask) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetTexEnviv(GLenum target, GLenum pname, GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetTexGendv(GLenum coord, GLenum pname, GLdouble *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glGetTexGeniv(GLenum coord, GLenum pname, GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexMask(GLuint mask) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexPointer(GLenum type, - GLsizei stride, - const void *pointer) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexd(GLdouble c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexdv(const GLdouble *c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexf(GLfloat c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexfv(const GLfloat *c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexi(GLint c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexiv(const GLint *c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexs(GLshort c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexsv(const GLshort *c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexub(GLubyte c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glIndexubv(const GLubyte *c) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glInitNames(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glInterleavedArrays(GLenum format, - GLsizei stride, - const void *pointer) _GL_VOID_RET _GL_BOOL - DO_NOT_USE_glIsList(GLuint list) _GL_BOOL_RET _GL_VOID - DO_NOT_USE_glLightModelf(GLenum pname, GLfloat param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLightModelfv(GLenum pname, const GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLightModeli(GLenum pname, GLint param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLightModeliv(GLenum pname, const GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLightf(GLenum light, GLenum pname, GLfloat param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLightfv(GLenum light, GLenum pname, const GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLighti(GLenum light, GLenum pname, GLint param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLightiv(GLenum light, GLenum pname, const GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLineStipple(GLint factor, GLushort pattern) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glListBase(GLuint base) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLoadIdentity(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLoadMatrixd(const GLdouble *m) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLoadMatrixf(const GLfloat *m) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glLoadName(GLuint name) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMap1d(GLenum target, - GLdouble u1, - GLdouble u2, - GLint stride, - GLint order, - const GLdouble *points) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMap1f(GLenum target, - GLfloat u1, - GLfloat u2, - GLint stride, - GLint order, - const GLfloat *points) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMap2d(GLenum target, - GLdouble u1, - GLdouble u2, - GLint ustride, - GLint uorder, - GLdouble v1, - GLdouble v2, - GLint vstride, - GLint vorder, - const GLdouble *points) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMap2f(GLenum target, - GLfloat u1, - GLfloat u2, - GLint ustride, - GLint uorder, - GLfloat v1, - GLfloat v2, - GLint vstride, - GLint vorder, - const GLfloat *points) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMapGrid1d(GLint un, GLdouble u1, GLdouble u2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMapGrid1f(GLint un, GLfloat u1, GLfloat u2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2) - _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2) - _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMaterialf(GLenum face, GLenum pname, GLfloat param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMateriali(GLenum face, GLenum pname, GLint param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMaterialiv(GLenum face, GLenum pname, const GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMatrixMode(GLenum mode) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMultMatrixd(const GLdouble *m) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glMultMatrixf(const GLfloat *m) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNewList(GLuint list, GLenum mode) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3b(GLbyte nx, GLbyte ny, GLbyte nz) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3bv(const GLbyte *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3d(GLdouble nx, GLdouble ny, GLdouble nz) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3i(GLint nx, GLint ny, GLint nz) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3s(GLshort nx, GLshort ny, GLshort nz) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormal3sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glNormalPointer(GLenum type, - GLsizei stride, - const void *pointer) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glOrtho(GLdouble left, - GLdouble right, - GLdouble bottom, - GLdouble top, - GLdouble zNear, - GLdouble zFar) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPassThrough(GLfloat token) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPixelMapfv(GLenum map, - GLsizei mapsize, - const GLfloat *values) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPixelMapuiv(GLenum map, - GLsizei mapsize, - const GLuint *values) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPixelMapusv(GLenum map, - GLsizei mapsize, - const GLushort *values) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPixelTransferf(GLenum pname, GLfloat param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPixelTransferi(GLenum pname, GLint param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPixelZoom(GLfloat xfactor, GLfloat yfactor) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPolygonStipple(const GLubyte *mask) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPopAttrib(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPopClientAttrib(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPopMatrix(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPopName(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPrioritizeTextures(GLsizei n, - const GLuint *textures, - const GLclampf *priorities) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPushAttrib(GLbitfield mask) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPushClientAttrib(GLbitfield mask) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPushMatrix(void) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glPushName(GLuint name) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2d(GLdouble x, GLdouble y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2f(GLfloat x, GLfloat y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2i(GLint x, GLint y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2s(GLshort x, GLshort y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos2sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3d(GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3f(GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3i(GLint x, GLint y, GLint z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3s(GLshort x, GLshort y, GLshort z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos3sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4i(GLint x, GLint y, GLint z, GLint w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRasterPos4sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRectdv(const GLdouble *v1, const GLdouble *v2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRectfv(const GLfloat *v1, const GLfloat *v2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRecti(GLint x1, GLint y1, GLint x2, GLint y2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRectiv(const GLint *v1, const GLint *v2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRectsv(const GLshort *v1, const GLshort *v2) _GL_VOID_RET _GL_INT - DO_NOT_USE_glRenderMode(GLenum mode) _GL_INT_RET _GL_VOID - DO_NOT_USE_glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glScaled(GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glScalef(GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glSelectBuffer(GLsizei size, GLuint *buffer) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glShadeModel(GLenum mode) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1d(GLdouble s) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1f(GLfloat s) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1i(GLint s) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1s(GLshort s) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord1sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2d(GLdouble s, GLdouble t) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2f(GLfloat s, GLfloat t) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2i(GLint s, GLint t) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2s(GLshort s, GLshort t) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord2sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3d(GLdouble s, GLdouble t, GLdouble r) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3f(GLfloat s, GLfloat t, GLfloat r) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3i(GLint s, GLint t, GLint r) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3s(GLshort s, GLshort t, GLshort r) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord3sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4i(GLint s, GLint t, GLint r, GLint q) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoord4sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) - _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexEnvf(GLenum target, GLenum pname, GLfloat param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexEnvi(GLenum target, GLenum pname, GLint param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexEnviv(GLenum target, GLenum pname, const GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexGend(GLenum coord, GLenum pname, GLdouble param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexGendv(GLenum coord, GLenum pname, const GLdouble *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexGenf(GLenum coord, GLenum pname, GLfloat param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexGenfv(GLenum coord, GLenum pname, const GLfloat *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexGeni(GLenum coord, GLenum pname, GLint param) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTexGeniv(GLenum coord, GLenum pname, const GLint *params) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTranslated(GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glTranslatef(GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2d(GLdouble x, GLdouble y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2f(GLfloat x, GLfloat y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2i(GLint x, GLint y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2s(GLshort x, GLshort y) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex2sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3d(GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3f(GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3i(GLint x, GLint y, GLint z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3s(GLshort x, GLshort y, GLshort z) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex3sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4dv(const GLdouble *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4fv(const GLfloat *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4i(GLint x, GLint y, GLint z, GLint w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4iv(const GLint *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4s(GLshort x, GLshort y, GLshort z, GLshort w) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertex4sv(const GLshort *v) _GL_VOID_RET _GL_VOID - DO_NOT_USE_glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) - _GL_VOID_RET - -/** - * End of automatically generated list - */ - -#undef _GL_BOOL -#undef _GL_BOOL_RET -#undef _GL_ENUM -#undef _GL_ENUM_RET -#undef _GL_INT -#undef _GL_INT_RET -#undef _GL_UINT -#undef _GL_UINT_RET -#undef _GL_VOID -#undef _GL_VOID_RET - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 6e31b1b69f6..30e890b1591 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -193,7 +193,7 @@ unsigned int GPU_texture_memory_usage_get(void); * \note \a data is expected to be float. If the \a format is not compatible with float data or if * the data is not in float format, use GPU_texture_update to upload the data with the right data * format. - * \a mips is the number of mip level to allocate. It must be >= 1. + * \a mip_len is the number of mip level to allocate. It must be >= 1. */ GPUTexture *GPU_texture_create_1d( const char *name, int w, int mip_len, eGPUTextureFormat format, const float *data); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index d64b8b4118a..8d9ae8e5257 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -1324,7 +1324,7 @@ bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type, eAttrDomain active_color_domain = active_color_layer ? BKE_id_attribute_domain(&me_query.id, active_color_layer) : - ATTR_DOMAIN_NUM; + ATTR_DOMAIN_POINT; GPUAttrRef vcol_layers[MAX_GPU_ATTR]; int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR, diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 4a45a3e63ed..2e1cb6b4a22 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -259,6 +259,7 @@ class GPUCodegen { MEM_SAFE_FREE(output.volume); MEM_SAFE_FREE(output.thickness); MEM_SAFE_FREE(output.displacement); + MEM_SAFE_FREE(output.composite); MEM_SAFE_FREE(output.material_functions); delete create_info; BLI_freelistN(&ubo_inputs_); diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 5233ff2dbf6..9713a854acc 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -239,9 +239,9 @@ void imm_draw_circle_partial_wire_2d( } void imm_draw_circle_partial_wire_3d( - uint pos, float x, float y, float z, float rad, int nsegments, float start, float sweep) + uint pos, float x, float y, float z, float radius, int nsegments, float start, float sweep) { - imm_draw_circle_partial_3d(GPU_PRIM_LINE_STRIP, pos, x, y, z, rad, nsegments, start, sweep); + imm_draw_circle_partial_3d(GPU_PRIM_LINE_STRIP, pos, x, y, z, radius, nsegments, start, sweep); } static void imm_draw_disk_partial(GPUPrimType prim_type, diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc index d108dd468a0..f8e2c0fe6fc 100644 --- a/source/blender/gpu/intern/gpu_platform.cc +++ b/source/blender/gpu/intern/gpu_platform.cc @@ -79,11 +79,15 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device, this->driver = driver_type; this->support_level = gpu_support_level; - this->vendor = BLI_strdup(vendor_str); - this->renderer = BLI_strdup(renderer_str); - this->version = BLI_strdup(version_str); - this->support_key = create_key(gpu_support_level, vendor_str, renderer_str, version_str); - this->gpu_name = create_gpu_name(vendor_str, renderer_str, version_str); + const char *vendor = vendor_str ? vendor_str : "UNKNOWN"; + const char *renderer = renderer_str ? renderer_str : "UNKNOWN"; + const char *version = version_str ? version_str : "UNKNOWN"; + + this->vendor = BLI_strdup(vendor); + this->renderer = BLI_strdup(renderer); + this->version = BLI_strdup(version); + this->support_key = create_key(gpu_support_level, vendor, renderer, version); + this->gpu_name = create_gpu_name(vendor, renderer, version); this->backend = backend; } diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index 3a14c060484..575f98bf428 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -111,7 +111,7 @@ void BKE_id_attribute_copy_domains_temp(short UNUSED(id_type), const struct CustomData *UNUSED(ldata), const struct CustomData *UNUSED(pdata), const struct CustomData *UNUSED(cdata), - struct ID *UNUSED(i_id)) + struct ID *UNUSED(r_id)) { } @@ -225,6 +225,13 @@ bool CustomData_has_layer(const struct CustomData *UNUSED(data), int UNUSED(type return false; } +void *CustomData_get_layer_named(const struct CustomData *UNUSED(data), + int UNUSED(type), + const char *UNUSED(name)) +{ + return nullptr; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index 82defc436e0..8236e669288 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -745,33 +745,16 @@ struct ShaderCreateInfo { * Used to share parts of the infos that are common to many shaders. * \{ */ - Self &additional_info(StringRefNull info_name0, - StringRefNull info_name1 = "", - StringRefNull info_name2 = "", - StringRefNull info_name3 = "", - StringRefNull info_name4 = "", - StringRefNull info_name5 = "", - StringRefNull info_name6 = "") - { - additional_infos_.append(info_name0); - if (!info_name1.is_empty()) { - additional_infos_.append(info_name1); - } - if (!info_name2.is_empty()) { - additional_infos_.append(info_name2); - } - if (!info_name3.is_empty()) { - additional_infos_.append(info_name3); - } - if (!info_name4.is_empty()) { - additional_infos_.append(info_name4); - } - if (!info_name5.is_empty()) { - additional_infos_.append(info_name5); - } - if (!info_name6.is_empty()) { - additional_infos_.append(info_name6); - } + Self &additional_info(StringRefNull info_name) + { + additional_infos_.append(info_name); + return *(Self *)this; + } + + template<typename... Args> Self &additional_info(StringRefNull info_name, Args... args) + { + additional_info(info_name); + additional_info(args...); return *(Self *)this; } diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc index 961d3fcfe5b..2c59cb6e501 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency.cc +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -108,7 +108,7 @@ struct GPUSource { string_preprocess(); } if ((source.find("drw_debug_") != StringRef::not_found) && - /* Avoid theses two files where it makes no sense to add the dependency. */ + /* Avoid these two files where it makes no sense to add the dependency. */ (filename != "common_debug_draw_lib.glsl" && filename != "draw_debug_draw_display_vert.glsl")) { builtins |= shader::BuiltinBits::USE_DEBUG_DRAW; diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index e52311b3bf0..65daa416cae 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -51,13 +51,13 @@ Texture::~Texture() #endif } -bool Texture::init_1D(int w, int layers, int mips, eGPUTextureFormat format) +bool Texture::init_1D(int w, int layers, int mip_len, eGPUTextureFormat format) { w_ = w; h_ = layers; d_ = 0; - int mips_max = 1 + floorf(log2f(w)); - mipmaps_ = min_ii(mips, mips_max); + int mip_len_max = 1 + floorf(log2f(w)); + mipmaps_ = min_ii(mip_len, mip_len_max); format_ = format; format_flag_ = to_format_flag(format); type_ = (layers > 0) ? GPU_TEXTURE_1D_ARRAY : GPU_TEXTURE_1D; @@ -67,13 +67,13 @@ bool Texture::init_1D(int w, int layers, int mips, eGPUTextureFormat format) return this->init_internal(); } -bool Texture::init_2D(int w, int h, int layers, int mips, eGPUTextureFormat format) +bool Texture::init_2D(int w, int h, int layers, int mip_len, eGPUTextureFormat format) { w_ = w; h_ = h; d_ = layers; - int mips_max = 1 + floorf(log2f(max_ii(w, h))); - mipmaps_ = min_ii(mips, mips_max); + int mip_len_max = 1 + floorf(log2f(max_ii(w, h))); + mipmaps_ = min_ii(mip_len, mip_len_max); format_ = format; format_flag_ = to_format_flag(format); type_ = (layers > 0) ? GPU_TEXTURE_2D_ARRAY : GPU_TEXTURE_2D; @@ -83,13 +83,13 @@ bool Texture::init_2D(int w, int h, int layers, int mips, eGPUTextureFormat form return this->init_internal(); } -bool Texture::init_3D(int w, int h, int d, int mips, eGPUTextureFormat format) +bool Texture::init_3D(int w, int h, int d, int mip_len, eGPUTextureFormat format) { w_ = w; h_ = h; d_ = d; - int mips_max = 1 + floorf(log2f(max_iii(w, h, d))); - mipmaps_ = min_ii(mips, mips_max); + int mip_len_max = 1 + floorf(log2f(max_iii(w, h, d))); + mipmaps_ = min_ii(mip_len, mip_len_max); format_ = format; format_flag_ = to_format_flag(format); type_ = GPU_TEXTURE_3D; @@ -99,13 +99,13 @@ bool Texture::init_3D(int w, int h, int d, int mips, eGPUTextureFormat format) return this->init_internal(); } -bool Texture::init_cubemap(int w, int layers, int mips, eGPUTextureFormat format) +bool Texture::init_cubemap(int w, int layers, int mip_len, eGPUTextureFormat format) { w_ = w; h_ = w; d_ = max_ii(1, layers) * 6; - int mips_max = 1 + floorf(log2f(w)); - mipmaps_ = min_ii(mips, mips_max); + int mip_len_max = 1 + floorf(log2f(w)); + mipmaps_ = min_ii(mip_len, mip_len_max); format_ = format; format_flag_ = to_format_flag(format); type_ = (layers > 0) ? GPU_TEXTURE_CUBE_ARRAY : GPU_TEXTURE_CUBE; @@ -237,29 +237,29 @@ static inline GPUTexture *gpu_texture_create(const char *name, const int h, const int d, const eGPUTextureType type, - int mips, + int mip_len, eGPUTextureFormat tex_format, eGPUDataFormat data_format, const void *pixels) { - BLI_assert(mips > 0); + BLI_assert(mip_len > 0); Texture *tex = GPUBackend::get()->texture_alloc(name); bool success = false; switch (type) { case GPU_TEXTURE_1D: case GPU_TEXTURE_1D_ARRAY: - success = tex->init_1D(w, h, mips, tex_format); + success = tex->init_1D(w, h, mip_len, tex_format); break; case GPU_TEXTURE_2D: case GPU_TEXTURE_2D_ARRAY: - success = tex->init_2D(w, h, d, mips, tex_format); + success = tex->init_2D(w, h, d, mip_len, tex_format); break; case GPU_TEXTURE_3D: - success = tex->init_3D(w, h, d, mips, tex_format); + success = tex->init_3D(w, h, d, mip_len, tex_format); break; case GPU_TEXTURE_CUBE: case GPU_TEXTURE_CUBE_ARRAY: - success = tex->init_cubemap(w, d, mips, tex_format); + success = tex->init_cubemap(w, d, mip_len, tex_format); break; default: break; diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 00bcc9fac00..8521b0fd77f 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -101,10 +101,10 @@ class Texture { virtual ~Texture(); /* Return true on success. */ - bool init_1D(int w, int layers, int mips, eGPUTextureFormat format); - bool init_2D(int w, int h, int layers, int mips, eGPUTextureFormat format); - bool init_3D(int w, int h, int d, int mips, eGPUTextureFormat format); - bool init_cubemap(int w, int layers, int mips, eGPUTextureFormat format); + bool init_1D(int w, int layers, int mip_len, eGPUTextureFormat format); + bool init_2D(int w, int h, int layers, int mip_len, eGPUTextureFormat format); + bool init_3D(int w, int h, int d, int mip_len, eGPUTextureFormat format); + bool init_cubemap(int w, int layers, int mip_len, eGPUTextureFormat format); bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format); bool init_view(const GPUTexture *src, eGPUTextureFormat format, diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 4869bff2737..6a1577fb907 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -51,7 +51,12 @@ void GLBackend::platform_init() os = GPU_OS_UNIX; #endif - if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { + if (!vendor) { + printf("Warning: No OpenGL vendor detected.\n"); + device = GPU_DEVICE_UNKNOWN; + driver = GPU_DRIVER_ANY; + } + else if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { device = GPU_DEVICE_ATI; driver = GPU_DRIVER_OFFICIAL; } @@ -113,7 +118,7 @@ void GLBackend::platform_init() } /* Detect support level */ - if (!GLEW_VERSION_3_3) { + if (!(epoxy_gl_version() >= 33)) { support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; } else { @@ -243,14 +248,14 @@ static void detect_workarounds() return; } - /* Limit support for GLEW_ARB_base_instance to OpenGL 4.0 and higher. NVIDIA Quadro FX 4800 - * (TeraScale) report that they support GLEW_ARB_base_instance, but the driver does not support + /* Limit support for GL_ARB_base_instance to OpenGL 4.0 and higher. NVIDIA Quadro FX 4800 + * (TeraScale) report that they support GL_ARB_base_instance, but the driver does not support * GLEW_ARB_draw_indirect as it has an OpenGL3 context what also matches the minimum needed * requirements. * * We use it as a target for glMapBuffer(Range) what is part of the OpenGL 4 API. So better * disable it when we don't have an OpenGL4 context (See T77657) */ - if (!GLEW_VERSION_4_0) { + if (!(epoxy_gl_version() >= 40)) { GLContext::base_instance_support = false; } if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && @@ -313,7 +318,8 @@ static void detect_workarounds() /* Limit this fix to older hardware with GL < 4.5. This means Broadwell GPUs are * covered since they only support GL 4.4 on windows. * This fixes some issues with workbench anti-aliasing on Win + Intel GPU. (see T76273) */ - if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && !GLEW_VERSION_4_5) { + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && + !(epoxy_gl_version() >= 45)) { GLContext::copy_image_support = false; } /* Special fix for these specific GPUs. @@ -328,7 +334,7 @@ static void detect_workarounds() strstr(renderer, "HD Graphics 2500"))) { GLContext::texture_cube_map_array_support = false; } - /* Maybe not all of these drivers have problems with `GLEW_ARB_base_instance`. + /* Maybe not all of these drivers have problems with `GL_ARB_base_instance`. * But it's hard to test each case. * We get crashes from some crappy Intel drivers don't work well with shaders created in * different rendering contexts. */ @@ -353,7 +359,8 @@ static void detect_workarounds() } /* There is a bug on older Nvidia GPU where GL_ARB_texture_gather * is reported to be supported but yield a compile error (see T55802). */ - if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) && !GLEW_VERSION_4_0) { + if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) && + !(epoxy_gl_version() >= 40)) { GLContext::texture_gather_support = false; } @@ -457,7 +464,7 @@ float GLContext::derivative_signs[2] = {1.0f, 1.0f}; void GLBackend::capabilities_init() { - BLI_assert(GLEW_VERSION_3_3); + BLI_assert(epoxy_gl_version() >= 33); /* Common Capabilities. */ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GCaps.max_texture_size); glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GCaps.max_texture_layers); @@ -482,9 +489,11 @@ void GLBackend::capabilities_init() glGetIntegerv(GL_NUM_EXTENSIONS, &GCaps.extensions_len); GCaps.extension_get = gl_extension_get; - GCaps.mem_stats_support = GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo; - GCaps.shader_image_load_store_support = GLEW_ARB_shader_image_load_store; - GCaps.compute_shader_support = GLEW_ARB_compute_shader && GLEW_VERSION_4_3; + GCaps.mem_stats_support = epoxy_has_gl_extension("GL_NVX_gpu_memory_info") || + epoxy_has_gl_extension("GL_ATI_meminfo"); + GCaps.shader_image_load_store_support = epoxy_has_gl_extension("GL_ARB_shader_image_load_store"); + GCaps.compute_shader_support = epoxy_has_gl_extension("GL_ARB_compute_shader") && + epoxy_gl_version() >= 43; if (GCaps.compute_shader_support) { glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &GCaps.max_work_group_count[0]); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &GCaps.max_work_group_count[1]); @@ -496,7 +505,8 @@ void GLBackend::capabilities_init() &GCaps.max_shader_storage_buffer_bindings); glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &GCaps.max_compute_shader_storage_blocks); } - GCaps.shader_storage_buffer_objects_support = GLEW_ARB_shader_storage_buffer_object; + GCaps.shader_storage_buffer_objects_support = epoxy_has_gl_extension( + "GL_ARB_shader_storage_buffer_object"); /* GL specific capabilities. */ glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GLContext::max_texture_3d_size); glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GLContext::max_cubemap_size); @@ -506,25 +516,32 @@ void GLBackend::capabilities_init() glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &GLContext::max_ssbo_binds); glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &GLContext::max_ssbo_size); } - GLContext::base_instance_support = GLEW_ARB_base_instance; - GLContext::clear_texture_support = GLEW_ARB_clear_texture; - GLContext::copy_image_support = GLEW_ARB_copy_image; - GLContext::debug_layer_support = GLEW_VERSION_4_3 || GLEW_KHR_debug || GLEW_ARB_debug_output; - GLContext::direct_state_access_support = GLEW_ARB_direct_state_access; - GLContext::explicit_location_support = GLEW_VERSION_4_3; - GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5; - GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility; - GLContext::layered_rendering_support = GLEW_AMD_vertex_shader_layer; - GLContext::native_barycentric_support = GLEW_AMD_shader_explicit_vertex_parameter; - GLContext::multi_bind_support = GLEW_ARB_multi_bind; - GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect; - GLContext::shader_draw_parameters_support = GLEW_ARB_shader_draw_parameters; - GLContext::stencil_texturing_support = GLEW_VERSION_4_3; - GLContext::texture_cube_map_array_support = GLEW_ARB_texture_cube_map_array; - GLContext::texture_filter_anisotropic_support = GLEW_EXT_texture_filter_anisotropic; - GLContext::texture_gather_support = GLEW_ARB_texture_gather; - GLContext::texture_storage_support = GLEW_VERSION_4_3; - GLContext::vertex_attrib_binding_support = GLEW_ARB_vertex_attrib_binding; + GLContext::base_instance_support = epoxy_has_gl_extension("GL_ARB_base_instance"); + GLContext::clear_texture_support = epoxy_has_gl_extension("GL_ARB_clear_texture"); + GLContext::copy_image_support = epoxy_has_gl_extension("GL_ARB_copy_image"); + GLContext::debug_layer_support = epoxy_gl_version() >= 43 || + epoxy_has_gl_extension("GL_KHR_debug") || + epoxy_has_gl_extension("GL_ARB_debug_output"); + GLContext::direct_state_access_support = epoxy_has_gl_extension("GL_ARB_direct_state_access"); + GLContext::explicit_location_support = epoxy_gl_version() >= 43; + GLContext::geometry_shader_invocations = epoxy_has_gl_extension("GL_ARB_gpu_shader5"); + GLContext::fixed_restart_index_support = epoxy_has_gl_extension("GL_ARB_ES3_compatibility"); + GLContext::layered_rendering_support = epoxy_has_gl_extension("GL_AMD_vertex_shader_layer"); + GLContext::native_barycentric_support = epoxy_has_gl_extension( + "GL_AMD_shader_explicit_vertex_parameter"); + GLContext::multi_bind_support = epoxy_has_gl_extension("GL_ARB_multi_bind"); + GLContext::multi_draw_indirect_support = epoxy_has_gl_extension("GL_ARB_multi_draw_indirect"); + GLContext::shader_draw_parameters_support = epoxy_has_gl_extension( + "GL_ARB_shader_draw_parameters"); + GLContext::stencil_texturing_support = epoxy_gl_version() >= 43; + GLContext::texture_cube_map_array_support = epoxy_has_gl_extension( + "GL_ARB_texture_cube_map_array"); + GLContext::texture_filter_anisotropic_support = epoxy_has_gl_extension( + "GL_EXT_texture_filter_anisotropic"); + GLContext::texture_gather_support = epoxy_has_gl_extension("GL_ARB_texture_gather"); + GLContext::texture_storage_support = epoxy_gl_version() >= 43; + GLContext::vertex_attrib_binding_support = epoxy_has_gl_extension( + "GL_ARB_vertex_attrib_binding"); detect_workarounds(); diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh index bb53d9b31f1..0d7ea7c4a9e 100644 --- a/source/blender/gpu/opengl/gl_batch.hh +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -17,8 +17,6 @@ #include "gl_index_buffer.hh" #include "gl_vertex_buffer.hh" -#include "glew-mx.h" - namespace blender { namespace gpu { diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc index e6af126e9cd..448e10fb0ed 100644 --- a/source/blender/gpu/opengl/gl_context.cc +++ b/source/blender/gpu/opengl/gl_context.cc @@ -304,12 +304,12 @@ void GLContext::vao_cache_unregister(GLVaoCache *cache) void GLContext::memory_statistics_get(int *r_total_mem, int *r_free_mem) { /* TODO(merwin): use Apple's platform API to get this info. */ - if (GLEW_NVX_gpu_memory_info) { + if (epoxy_has_gl_extension("GL_NVX_gpu_memory_info")) { /* Returned value in Kb. */ glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, r_total_mem); glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, r_free_mem); } - else if (GLEW_ATI_meminfo) { + else if (epoxy_has_gl_extension("GL_ATI_meminfo")) { int stats[4]; glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats); diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index 234bc712513..2f8c2b762f8 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -16,8 +16,6 @@ #include "gl_state.hh" -#include "glew-mx.h" - #include <mutex> namespace blender { diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc index 79b28642a67..4c9f766c93c 100644 --- a/source/blender/gpu/opengl/gl_debug.cc +++ b/source/blender/gpu/opengl/gl_debug.cc @@ -19,8 +19,6 @@ #include "CLG_log.h" -#include "glew-mx.h" - #include "gl_context.hh" #include "gl_uniform_buffer.hh" @@ -138,8 +136,8 @@ void init_gl_callbacks() char msg[256] = ""; const char format[] = "Successfully hooked OpenGL debug callback using %s"; - if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { - SNPRINTF(msg, format, GLEW_VERSION_4_3 ? "OpenGL 4.3" : "KHR_debug extension"); + if (epoxy_gl_version() >= 43 || epoxy_has_gl_extension("GL_KHR_debug")) { + SNPRINTF(msg, format, epoxy_gl_version() >= 43 ? "OpenGL 4.3" : "KHR_debug extension"); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback((GLDEBUGPROC)debug_callback, nullptr); @@ -151,7 +149,7 @@ void init_gl_callbacks() -1, msg); } - else if (GLEW_ARB_debug_output) { + else if (epoxy_has_gl_extension("GL_ARB_debug_output")) { SNPRINTF(msg, format, "ARB_debug_output"); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallbackARB((GLDEBUGPROCARB)debug_callback, nullptr); @@ -327,7 +325,8 @@ static const char *to_str_suffix(GLenum type) void object_label(GLenum type, GLuint object, const char *name) { - if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) { + if ((G.debug & G_DEBUG_GPU) && + (epoxy_gl_version() >= 43 || epoxy_has_gl_extension("GL_KHR_debug"))) { char label[64]; SNPRINTF(label, "%s%s%s", to_str_prefix(type), name, to_str_suffix(type)); /* Small convenience for caller. */ @@ -365,7 +364,8 @@ namespace blender::gpu { void GLContext::debug_group_begin(const char *name, int index) { - if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) { + if ((G.debug & G_DEBUG_GPU) && + (epoxy_gl_version() >= 43 || epoxy_has_gl_extension("GL_KHR_debug"))) { /* Add 10 to avoid collision with other indices from other possible callback layers. */ index += 10; glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, index, -1, name); @@ -374,7 +374,8 @@ void GLContext::debug_group_begin(const char *name, int index) void GLContext::debug_group_end() { - if ((G.debug & G_DEBUG_GPU) && (GLEW_VERSION_4_3 || GLEW_KHR_debug)) { + if ((G.debug & G_DEBUG_GPU) && + (epoxy_gl_version() >= 43 || epoxy_has_gl_extension("GL_KHR_debug"))) { glPopDebugGroup(); } } diff --git a/source/blender/gpu/opengl/gl_debug.hh b/source/blender/gpu/opengl/gl_debug.hh index e24b6f2bb23..b573196216d 100644 --- a/source/blender/gpu/opengl/gl_debug.hh +++ b/source/blender/gpu/opengl/gl_debug.hh @@ -8,8 +8,6 @@ #include "gl_context.hh" -#include "glew-mx.h" - /* Manual line breaks for readability. */ /* clang-format off */ #define _VA_ARG_LIST1(t) t diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh index 2dc0936d0fe..8ee04a584bd 100644 --- a/source/blender/gpu/opengl/gl_framebuffer.hh +++ b/source/blender/gpu/opengl/gl_framebuffer.hh @@ -11,8 +11,6 @@ #include "MEM_guardedalloc.h" -#include "glew-mx.h" - #include "gpu_framebuffer_private.hh" namespace blender::gpu { diff --git a/source/blender/gpu/opengl/gl_immediate.hh b/source/blender/gpu/opengl/gl_immediate.hh index eb94dc20e21..5c6ff510cef 100644 --- a/source/blender/gpu/opengl/gl_immediate.hh +++ b/source/blender/gpu/opengl/gl_immediate.hh @@ -11,8 +11,6 @@ #include "MEM_guardedalloc.h" -#include "glew-mx.h" - #include "gpu_immediate_private.hh" namespace blender::gpu { diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh index 8a10884d48b..d9bd85cefb3 100644 --- a/source/blender/gpu/opengl/gl_index_buffer.hh +++ b/source/blender/gpu/opengl/gl_index_buffer.hh @@ -11,7 +11,7 @@ #include "gpu_index_buffer_private.hh" -#include "glew-mx.h" +#include <epoxy/gl.h> namespace blender::gpu { @@ -35,9 +35,11 @@ class GLIndexBuf : public IndexBuf { { additional_vertex_offset += index_start_; if (index_type_ == GPU_INDEX_U32) { - return (GLuint *)0 + additional_vertex_offset; + return reinterpret_cast<void *>(static_cast<intptr_t>(additional_vertex_offset) * + sizeof(GLuint)); } - return (GLushort *)0 + additional_vertex_offset; + return reinterpret_cast<void *>(static_cast<intptr_t>(additional_vertex_offset) * + sizeof(GLushort)); } GLuint restart_index() const diff --git a/source/blender/gpu/opengl/gl_primitive.hh b/source/blender/gpu/opengl/gl_primitive.hh index 2a8590e8b3e..c4c7734a2cd 100644 --- a/source/blender/gpu/opengl/gl_primitive.hh +++ b/source/blender/gpu/opengl/gl_primitive.hh @@ -13,8 +13,6 @@ #include "GPU_primitive.h" -#include "glew-mx.h" - namespace blender::gpu { static inline GLenum to_gl(GPUPrimType prim_type) diff --git a/source/blender/gpu/opengl/gl_query.hh b/source/blender/gpu/opengl/gl_query.hh index e15a2584e07..a851ab4ecdd 100644 --- a/source/blender/gpu/opengl/gl_query.hh +++ b/source/blender/gpu/opengl/gl_query.hh @@ -11,7 +11,7 @@ #include "gpu_query.hh" -#include "glew-mx.h" +#include <epoxy/gl.h> namespace blender::gpu { diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index ccdf10c1ed2..a08019cc707 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -545,7 +545,7 @@ std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) con if (!GLContext::native_barycentric_support) { /* Disabled or unsupported. */ } - else if (GLEW_AMD_shader_explicit_vertex_parameter) { + else if (epoxy_has_gl_extension("GL_AMD_shader_explicit_vertex_parameter")) { /* Need this for stable barycentric. */ ss << "flat out vec4 gpu_pos_flat;\n"; ss << "out vec4 gpu_pos;\n"; @@ -581,7 +581,7 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n"; ss << "#define gpu_position_at_vertex(v) gpu_pos[v]\n"; } - else if (GLEW_AMD_shader_explicit_vertex_parameter) { + else if (epoxy_has_gl_extension("GL_AMD_shader_explicit_vertex_parameter")) { std::cout << "native" << std::endl; /* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry * shader workaround if this extension/feature is detected. */ @@ -612,7 +612,7 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c if (info.early_fragment_test_) { ss << "layout(early_fragment_tests) in;\n"; } - if (GLEW_ARB_conservative_depth) { + if (epoxy_has_gl_extension("GL_ARB_conservative_depth")) { ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n"; } ss << "\n/* Outputs. */\n"; @@ -805,7 +805,7 @@ static char *glsl_patch_default_get() size_t slen = 0; /* Version need to go first. */ - if (GLEW_VERSION_4_3) { + if (epoxy_gl_version() >= 43) { STR_CONCAT(patch, slen, "#version 430\n"); } else { @@ -816,8 +816,8 @@ static char *glsl_patch_default_get() * don't use an extension for something already available! */ if (GLContext::texture_gather_support) { STR_CONCAT(patch, slen, "#extension GL_ARB_texture_gather: enable\n"); - /* Some drivers don't agree on GLEW_ARB_texture_gather and the actual support in the - * shader so double check the preprocessor define (see T56544). */ + /* Some drivers don't agree on epoxy_has_gl_extension("GL_ARB_texture_gather") and the actual + * support in the shader so double check the preprocessor define (see T56544). */ STR_CONCAT(patch, slen, "#ifdef GL_ARB_texture_gather\n"); STR_CONCAT(patch, slen, "# define GPU_ARB_texture_gather\n"); STR_CONCAT(patch, slen, "#endif\n"); @@ -835,7 +835,7 @@ static char *glsl_patch_default_get() STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n"); STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n"); } - if (GLEW_ARB_conservative_depth) { + if (epoxy_has_gl_extension("GL_ARB_conservative_depth")) { STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n"); } if (GPU_shader_image_load_store_support()) { diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index 9c21d0c6230..2774b24cdbe 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" -#include "glew-mx.h" +#include <epoxy/gl.h> #include "gpu_shader_create_info.hh" #include "gpu_shader_private.hh" diff --git a/source/blender/gpu/opengl/gl_shader_interface.hh b/source/blender/gpu/opengl/gl_shader_interface.hh index e3dce31758b..e31879d4340 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.hh +++ b/source/blender/gpu/opengl/gl_shader_interface.hh @@ -16,8 +16,6 @@ #include "BLI_vector.hh" -#include "glew-mx.h" - #include "gpu_shader_create_info.hh" #include "gpu_shader_interface.hh" diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh index f29eefbca82..74c68e51755 100644 --- a/source/blender/gpu/opengl/gl_state.hh +++ b/source/blender/gpu/opengl/gl_state.hh @@ -13,7 +13,7 @@ #include "gpu_state_private.hh" -#include "glew-mx.h" +#include <epoxy/gl.h> namespace blender { namespace gpu { diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh index 96052fe0065..ffe2de12451 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.hh +++ b/source/blender/gpu/opengl/gl_storage_buffer.hh @@ -11,8 +11,6 @@ #include "gpu_storage_buffer_private.hh" -#include "glew-mx.h" - namespace blender { namespace gpu { diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index 22c21d360c7..b7d72455c25 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -13,8 +13,6 @@ #include "gpu_texture_private.hh" -#include "glew-mx.h" - struct GPUFrameBuffer; namespace blender { diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.hh b/source/blender/gpu/opengl/gl_uniform_buffer.hh index 8d945a8e7dc..e602532dc5a 100644 --- a/source/blender/gpu/opengl/gl_uniform_buffer.hh +++ b/source/blender/gpu/opengl/gl_uniform_buffer.hh @@ -11,8 +11,6 @@ #include "gpu_uniform_buffer_private.hh" -#include "glew-mx.h" - namespace blender { namespace gpu { diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index a3299fc3325..d836b73f5d8 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -21,7 +21,7 @@ namespace blender::gpu { /** \name Vertex Array Bindings * \{ */ -/* Returns enabled vertex pointers as a bitflag (one bit per attrib). */ +/** Returns enabled vertex pointers as a bit-flag (one bit per attribute). */ static uint16_t vbo_bind(const ShaderInterface *interface, const GPUVertFormat *format, uint v_first, diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh index d1d6c5604b5..4f417beed29 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.hh +++ b/source/blender/gpu/opengl/gl_vertex_array.hh @@ -7,8 +7,6 @@ #pragma once -#include "glew-mx.h" - #include "GPU_batch.h" #include "gl_shader_interface.hh" diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh index e0a21587b60..deb966961f2 100644 --- a/source/blender/gpu/opengl/gl_vertex_buffer.hh +++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh @@ -9,8 +9,6 @@ #include "MEM_guardedalloc.h" -#include "glew-mx.h" - #include "GPU_texture.h" #include "gpu_vertex_buffer_private.hh" diff --git a/source/blender/gpu/shaders/compositor/compositor_bilateral_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_bilateral_blur.glsl new file mode 100644 index 00000000000..c7c5ada7a9f --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_bilateral_blur.glsl @@ -0,0 +1,31 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + vec4 center_determinator = texture_load(determinator_tx, texel); + + /* Go over the pixels in the blur window of the specified radius around the center pixel, and for + * pixels whose determinator is close enough to the determinator of the center pixel, accumulate + * their color as well as their weights. */ + float accumulated_weight = 0.0; + vec4 accumulated_color = vec4(0.0); + for (int y = -radius; y <= radius; y++) { + for (int x = -radius; x <= radius; x++) { + vec4 determinator = texture_load(determinator_tx, texel + ivec2(x, y)); + float difference = dot(abs(center_determinator - determinator).rgb, vec3(1.0)); + + if (difference < threshold) { + accumulated_weight += 1.0; + accumulated_color += texture_load(input_tx, texel + ivec2(x, y)); + } + } + } + + /* Write the accumulated color divided by the accumulated weight if any pixel in the window was + * accumulated, otherwise, write a fallback black color. */ + vec4 fallback = vec4(vec3(0.0), 1.0); + vec4 color = (accumulated_weight != 0.0) ? (accumulated_color / accumulated_weight) : fallback; + imageStore(output_img, texel, color); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_bokeh_image.glsl b/source/blender/gpu/shaders/compositor/compositor_bokeh_image.glsl new file mode 100644 index 00000000000..6e98aa9fe17 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_bokeh_image.glsl @@ -0,0 +1,118 @@ +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +/* Get the 2D vertex position of the vertex with the given index in the regular polygon + * representing this bokeh. The polygon is rotated by the rotation amount and have a unit + * circumradius. The regular polygon is one whose vertices' exterior angles are given by + * exterior_angle. See the bokeh function for more information. */ +vec2 get_regular_polygon_vertex_position(int vertex_index) +{ + float angle = exterior_angle * vertex_index - rotation; + return vec2(cos(angle), sin(angle)); +} + +/* Find the closest point to the given point on the given line. This assumes the length of the + * given line is not zero. */ +vec2 closest_point_on_line(vec2 point, vec2 line_start, vec2 line_end) +{ + vec2 line_vector = line_end - line_start; + vec2 point_vector = point - line_start; + float line_length_squared = dot(line_vector, line_vector); + float parameter = dot(point_vector, line_vector) / line_length_squared; + return line_start + line_vector * parameter; +} + +/* Compute the value of the bokeh at the given point. The computed bokeh is essentially a regular + * polygon centered in space having the given circumradius. The regular polygon is one whose + * vertices' exterior angles are given by "exterior_angle", which relates to the number of vertices + * n through the equation "exterior angle = 2 pi / n". The regular polygon may additionally morph + * into a shape with the given properties: + * + * - The regular polygon may have a circular hole in its center whose radius is controlled by the + * "catadioptric" value. + * - The regular polygon is rotated by the "rotation" value. + * - The regular polygon can morph into a circle controlled by the "roundness" value, such that it + * becomes a full circle at unit roundness. + * + * The function returns 0 when the point lies inside the regular polygon and 1 otherwise. However, + * at the edges, it returns a narrow band gradient as a form of anti-aliasing. */ +float bokeh(vec2 point, float circumradius) +{ + /* Get the index of the vertex of the regular polygon whose polar angle is maximum but less than + * the polar angle of the given point, taking rotation into account. This essentially finds the + * vertex closest to the given point in the clock-wise direction. */ + float angle = mod(atan(point.y, point.x) + rotation, M_2PI); + int vertex_index = int(angle / exterior_angle); + + /* Compute the shortest distance between the origin and the polygon edge composed from the + * previously selected vertex and the one following it. */ + vec2 first_vertex = get_regular_polygon_vertex_position(vertex_index) * circumradius; + vec2 second_vertex = get_regular_polygon_vertex_position(vertex_index + 1) * circumradius; + vec2 closest_point = closest_point_on_line(point, first_vertex, second_vertex); + float distance_to_edge = length(closest_point); + + /* Mix the distance to the edge with the circumradius, making it tend to the distance to a + * circle when roundness tends to 1. */ + float distance_to_edge_round = mix(distance_to_edge, circumradius, roundness); + + /* The point is outside of the bokeh, so we return 0. */ + float distance = length(point); + if (distance > distance_to_edge_round) { + return 0.0; + } + + /* The point is inside the catadioptric hole and is not part of the bokeh, so we return 0. */ + float catadioptric_distance = distance_to_edge_round * catadioptric; + if (distance < catadioptric_distance) { + return 0.0; + } + + /* The point is very close to the edge of the bokeh, so we return the difference between the + * distance to the edge and the distance as a form of anti-aliasing. */ + if (distance_to_edge_round - distance < 1.0) { + return distance_to_edge_round - distance; + } + + /* The point is very close to the edge of the catadioptric hole, so we return the difference + * between the distance to the hole and the distance as a form of anti-aliasing. */ + if (catadioptric != 0.0 && distance - catadioptric_distance < 1.0) { + return distance - catadioptric_distance; + } + + /* Otherwise, the point is part of the bokeh and we return 1. */ + return 1.0; +} + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + /* Since we need the regular polygon to occupy the entirety of the output image, the circumradius + * of the regular polygon is half the width of the output image. */ + float circumradius = float(imageSize(output_img).x) / 2.0; + + /* Move the texel coordinates such that the regular polygon is centered. */ + vec2 point = vec2(texel) - circumradius; + + /* Each of the color channels of the output image contains a bokeh with a different circumradius. + * The largest one occupies the whole image as stated above, while the other two have circumradii + * that are shifted by an amount that is proportional to the "lens_shift" value. The alpha + * channel of the output is the average of all three values. */ + float min_shift = abs(lens_shift * circumradius); + float min = mix(bokeh(point, circumradius - min_shift), 0.0, min_shift == circumradius); + + float median_shift = min_shift / 2.0; + float median = bokeh(point, circumradius - median_shift); + + float max = bokeh(point, circumradius); + vec4 bokeh = vec4(min, median, max, (max + median + min) / 3.0); + + /* If the lens shift is negative, swap the min and max bokeh values, which are stored in the red + * and blue channels respectively. Note that we take the absolute value of the lens shift above, + * so the sign of the lens shift only controls this swap. */ + if (lens_shift < 0) { + bokeh = bokeh.zyxw; + } + + imageStore(output_img, texel, bokeh); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_despeckle.glsl b/source/blender/gpu/shaders/compositor/compositor_despeckle.glsl new file mode 100644 index 00000000000..e4743d69d17 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_despeckle.glsl @@ -0,0 +1,70 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +/* Returns true if the given color is close enough to the given reference color within the + * threshold supplied by the user, and returns false otherwise. */ +bool is_close(vec4 reference_color, vec4 color) +{ + return all(lessThan(abs(reference_color - color).rgb, vec3(threshold))); +} + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + /* A 3x3 weights kernel whose weights are the inverse of the distance to the center of the + * kernel. So the center weight is zero, the corners weights are (1 / sqrt(2)), and the rest + * of the weights are 1. The total sum of weights is 4 plus quadruple the corner weight. */ + float corner_weight = 1.0 / sqrt(2.0); + float sum_of_weights = 4.0 + corner_weight * 4.0; + mat3 weights = mat3(vec3(corner_weight, 1.0, corner_weight), + vec3(1.0, 0.0, 1.0), + vec3(corner_weight, 1.0, corner_weight)); + + vec4 center_color = texture_load(input_tx, texel); + + /* Go over the pixels in the 3x3 window around the center pixel and compute the total sum of + * their colors multiplied by their weights. Additionally, for pixels whose colors are not close + * enough to the color of the center pixel, accumulate their color as well as their weights. */ + vec4 sum_of_colors = vec4(0); + float accumulated_weight = 0.0; + vec4 accumulated_color = vec4(0); + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 3; i++) { + float weight = weights[j][i]; + vec4 color = texture_load(input_tx, texel + ivec2(i - 1, j - 1)) * weight; + sum_of_colors += color; + if (!is_close(center_color, color)) { + accumulated_color += color; + accumulated_weight += weight; + } + } + } + + /* If the accumulated weight is zero, that means all pixels in the 3x3 window are similar and no + * need to despeckle anything, so write the original center color and return. */ + if (accumulated_weight == 0.0) { + imageStore(output_img, texel, center_color); + return; + } + + /* If the ratio between the accumulated weights and the total sum of weights is not larger than + * the user specified neighbor threshold, then the number of pixels in the neighborhood that are + * not close enough to the center pixel is low, and no need to despeckle anything, so write the + * original center color and return. */ + if (accumulated_weight / sum_of_weights < neighbor_threshold) { + imageStore(output_img, texel, center_color); + return; + } + + /* If the weighted average color of the neighborhood is close enough to the center pixel, then no + * need to despeckle anything, so write the original center color and return. */ + if (is_close(center_color, sum_of_colors / sum_of_weights)) { + imageStore(output_img, texel, center_color); + return; + } + + /* We need to despeckle, so write the mean accumulated color. */ + float factor = texture_load(factor_tx, texel).x; + vec4 mean_color = accumulated_color / accumulated_weight; + imageStore(output_img, texel, mix(center_color, mean_color, factor)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_directional_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_directional_blur.glsl new file mode 100644 index 00000000000..1805cb5a7f5 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_directional_blur.glsl @@ -0,0 +1,21 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + ivec2 input_size = texture_size(input_tx); + + /* Add 0.5 to evaluate the input sampler at the center of the pixel. */ + vec2 coordinates = vec2(texel) + vec2(0.5); + + /* For each iteration, accumulate the input at the normalize coordinates, hence the divide by + * input size, then transform the coordinates for the next iteration. */ + vec4 accumulated_color = vec4(0.0); + for (int i = 0; i < iterations; i++) { + accumulated_color += texture(input_tx, coordinates / input_size); + coordinates = (mat3(inverse_transformation) * vec3(coordinates, 1.0)).xy; + } + + /* Write the accumulated color divided by the number of iterations. */ + imageStore(output_img, texel, accumulated_color / iterations); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_edge_filter.glsl b/source/blender/gpu/shaders/compositor/compositor_edge_filter.glsl new file mode 100644 index 00000000000..67e27c22602 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_edge_filter.glsl @@ -0,0 +1,31 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + /* Compute the dot product between the 3x3 window around the pixel and the edge detection kernel + * in the X direction and Y direction. The Y direction kernel is computed by transposing the + * given X direction kernel. */ + vec3 color_x = vec3(0); + vec3 color_y = vec3(0); + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 3; i++) { + vec3 color = texture_load(input_tx, texel + ivec2(i - 1, j - 1)).rgb; + color_x += color * kernel[j][i]; + color_y += color * kernel[i][j]; + } + } + + /* Compute the channel-wise magnitude of the 2D vector composed from the X and Y edge detection + * filter results. */ + vec3 magnitude = sqrt(color_x * color_x + color_y * color_y); + + /* Mix the channel-wise magnitude with the original color at the center of the kernel using the + * input factor. */ + vec4 color = texture_load(input_tx, texel); + magnitude = mix(color.rgb, magnitude, texture_load(factor_tx, texel).x); + + /* Store the channel-wise magnitude with the original alpha of the input. */ + imageStore(output_img, texel, vec4(magnitude, color.a)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_filter.glsl b/source/blender/gpu/shaders/compositor/compositor_filter.glsl new file mode 100644 index 00000000000..e501c563dda --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_filter.glsl @@ -0,0 +1,20 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + /* Compute the dot product between the 3x3 window around the pixel and the filter kernel. */ + vec4 color = vec4(0); + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 3; i++) { + color += texture_load(input_tx, texel + ivec2(i - 1, j - 1)) * kernel[j][i]; + } + } + + /* Mix with the original color at the center of the kernel using the input factor. */ + color = mix(texture_load(input_tx, texel), color, texture_load(factor_tx, texel).x); + + /* Store the color making sure it is not negative. */ + imageStore(output_img, texel, max(color, 0.0)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_realize_on_domain.glsl b/source/blender/gpu/shaders/compositor/compositor_realize_on_domain.glsl index b2961d07219..be984d81603 100644 --- a/source/blender/gpu/shaders/compositor/compositor_realize_on_domain.glsl +++ b/source/blender/gpu/shaders/compositor/compositor_realize_on_domain.glsl @@ -4,18 +4,22 @@ void main() { ivec2 texel = ivec2(gl_GlobalInvocationID.xy); - /* First, transform the input image by transforming the domain coordinates with the inverse of - * input image's transformation. The inverse transformation is an affine matrix and thus the + /* Add 0.5 to evaluate the input sampler at the center of the pixel. */ + vec2 coordinates = vec2(texel) + vec2(0.5); + + /* Transform the input image by transforming the domain coordinates with the inverse of input + * image's transformation. The inverse transformation is an affine matrix and thus the * coordinates should be in homogeneous coordinates. */ - vec2 coordinates = (mat3(inverse_transformation) * vec3(texel, 1.0)).xy; + coordinates = (mat3(inverse_transformation) * vec3(coordinates, 1.0)).xy; /* Since an input image with an identity transformation is supposed to be centered in the domain, * we subtract the offset between the lower left corners of the input image and the domain, which * is half the difference between their sizes, because the difference in size is on both sides of - * the centered image. */ + * the centered image. Additionally, we floor the offset to retain the 0.5 offset added above in + * case the difference in sizes was odd. */ ivec2 domain_size = imageSize(domain_img); ivec2 input_size = texture_size(input_tx); - vec2 offset = (domain_size - input_size) / 2.0; + vec2 offset = floor((domain_size - input_size) / 2.0); /* Subtract the offset and divide by the input image size to get the relevant coordinates into * the sampler's expected [0, 1] range. */ diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_bilateral_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_bilateral_blur_info.hh new file mode 100644 index 00000000000..301cd6acd9e --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_bilateral_blur_info.hh @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_bilateral_blur) + .local_group_size(16, 16) + .push_constant(Type::INT, "radius") + .push_constant(Type::FLOAT, "threshold") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .sampler(1, ImageType::FLOAT_2D, "determinator_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_bilateral_blur.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_bokeh_image_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_bokeh_image_info.hh new file mode 100644 index 00000000000..3541de53070 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_bokeh_image_info.hh @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_bokeh_image) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "exterior_angle") + .push_constant(Type::FLOAT, "rotation") + .push_constant(Type::FLOAT, "roundness") + .push_constant(Type::FLOAT, "catadioptric") + .push_constant(Type::FLOAT, "lens_shift") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_bokeh_image.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_despeckle_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_despeckle_info.hh new file mode 100644 index 00000000000..df86c3a8258 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_despeckle_info.hh @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_despeckle) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "threshold") + .push_constant(Type::FLOAT, "neighbor_threshold") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .sampler(1, ImageType::FLOAT_2D, "factor_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_despeckle.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_directional_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_directional_blur_info.hh new file mode 100644 index 00000000000..bb9199dcd26 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_directional_blur_info.hh @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_directional_blur) + .local_group_size(16, 16) + .push_constant(Type::INT, "iterations") + .push_constant(Type::MAT4, "inverse_transformation") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_directional_blur.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_edge_filter_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_edge_filter_info.hh new file mode 100644 index 00000000000..916ec62bdba --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_edge_filter_info.hh @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_edge_filter) + .local_group_size(16, 16) + .push_constant(Type::MAT4, "kernel") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .sampler(1, ImageType::FLOAT_2D, "factor_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_edge_filter.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_filter_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_filter_info.hh new file mode 100644 index 00000000000..9d565cf4b8a --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_filter_info.hh @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_filter) + .local_group_size(16, 16) + .push_constant(Type::MAT4, "kernel") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .sampler(1, ImageType::FLOAT_2D, "factor_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_filter.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl index 881e38ea11a..480334f9bbd 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl @@ -13,7 +13,6 @@ * + + | * @ + + + + @ @------> x * v0 v1 - * */ float bi_mix(float v0, float v1, float v2, float v3, float x, float y) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl index 961fe23e67e..7171c5f2b36 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl @@ -153,13 +153,12 @@ void node_tex_musgrave_hybrid_multi_fractal_1d(vec3 co, float lacunarity = max(lac, 1e-5); float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - float value = snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0; + float value = 0.0; + float weight = 1.0; - for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) { + for (int i = 0; (weight > 0.001f) && (i < int(octaves)); i++) { if (weight > 1.0) { weight = 1.0; } @@ -172,8 +171,12 @@ void node_tex_musgrave_hybrid_multi_fractal_1d(vec3 co, } float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((snoise(p) + offset) * pwr); + if ((rmd != 0.0) && (weight > 0.001f)) { + if (weight > 1.0) { + weight = 1.0; + } + float signal = (snoise(p) + offset) * pwr; + value += rmd * weight * signal; } fac = value; @@ -375,13 +378,12 @@ void node_tex_musgrave_hybrid_multi_fractal_2d(vec3 co, float lacunarity = max(lac, 1e-5); float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - float value = snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0; + float value = 0.0; + float weight = 1.0; - for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) { + for (int i = 0; (weight > 0.001f) && (i < int(octaves)); i++) { if (weight > 1.0) { weight = 1.0; } @@ -394,8 +396,12 @@ void node_tex_musgrave_hybrid_multi_fractal_2d(vec3 co, } float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((snoise(p) + offset) * pwr); + if ((rmd != 0.0) && (weight > 0.001f)) { + if (weight > 1.0) { + weight = 1.0; + } + float signal = (snoise(p) + offset) * pwr; + value += rmd * weight * signal; } fac = value; @@ -597,13 +603,12 @@ void node_tex_musgrave_hybrid_multi_fractal_3d(vec3 co, float lacunarity = max(lac, 1e-5); float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - float value = snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0; + float value = 0.0; + float weight = 1.0; - for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) { + for (int i = 0; (weight > 0.001f) && (i < int(octaves)); i++) { if (weight > 1.0) { weight = 1.0; } @@ -616,8 +621,12 @@ void node_tex_musgrave_hybrid_multi_fractal_3d(vec3 co, } float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((snoise(p) + offset) * pwr); + if ((rmd != 0.0) && (weight > 0.001f)) { + if (weight > 1.0) { + weight = 1.0; + } + float signal = (snoise(p) + offset) * pwr; + value += rmd * weight * signal; } fac = value; @@ -819,13 +828,12 @@ void node_tex_musgrave_hybrid_multi_fractal_4d(vec3 co, float lacunarity = max(lac, 1e-5); float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - float value = snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; + float pwr = 1.0; + float value = 0.0; + float weight = 1.0; - for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) { + for (int i = 0; (weight > 0.001f) && (i < int(octaves)); i++) { if (weight > 1.0) { weight = 1.0; } @@ -838,8 +846,12 @@ void node_tex_musgrave_hybrid_multi_fractal_4d(vec3 co, } float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((snoise(p) + offset) * pwr); + if ((rmd != 0.0) && (weight > 0.001f)) { + if (weight > 1.0) { + weight = 1.0; + } + float signal = (snoise(p) + offset) * pwr; + value += rmd * weight * signal; } fac = value; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl index 0fb8ef15f5f..aac3d98b43b 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl @@ -15,7 +15,6 @@ * * With optimization to change -2..2 scan window to -1..1 for better performance, * as explained in https://www.shadertoy.com/view/llG3zy. - * */ /* **** 1D Voronoi **** */ diff --git a/source/blender/gpu/tests/gpu_shader_test.cc b/source/blender/gpu/tests/gpu_shader_test.cc index ab1409dfcde..35ffc647c97 100644 --- a/source/blender/gpu/tests/gpu_shader_test.cc +++ b/source/blender/gpu/tests/gpu_shader_test.cc @@ -14,8 +14,6 @@ #include "gpu_testing.hh" -#include "GPU_glew.h" - namespace blender::gpu::tests { static void test_gpu_shader_compute_2d() diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 28125c006eb..6881916d1d2 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -50,7 +50,6 @@ extern "C" { #define IM_MAX_SPACE 64 /** - * * \attention defined in ??? */ struct ImBuf; @@ -58,7 +57,6 @@ struct rctf; struct rcti; /** - * * \attention defined in ??? */ struct anim; @@ -67,21 +65,18 @@ struct ColorManagedDisplay; struct GSet; /** - * * \attention defined in DNA_scene_types.h */ struct ImageFormatData; struct Stereo3dFormat; /** - * * \attention Defined in allocimbuf.c */ void IMB_init(void); void IMB_exit(void); /** - * * \attention Defined in readimage.c */ struct ImBuf *IMB_ibImageFromMemory(const unsigned char *mem, @@ -91,19 +86,16 @@ struct ImBuf *IMB_ibImageFromMemory(const unsigned char *mem, const char *descr); /** - * * \attention Defined in readimage.c */ struct ImBuf *IMB_testiffname(const char *filepath, int flags); /** - * * \attention Defined in readimage.c */ struct ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]); /** - * * \attention Defined in readimage.c */ struct ImBuf *IMB_thumb_load_image(const char *filepath, @@ -111,13 +103,11 @@ struct ImBuf *IMB_thumb_load_image(const char *filepath, char colorspace[IM_MAX_SPACE]); /** - * * \attention Defined in allocimbuf.c */ void IMB_freeImBuf(struct ImBuf *ibuf); /** - * * \attention Defined in allocimbuf.c */ struct ImBuf *IMB_allocImBuf(unsigned int x, @@ -154,7 +144,6 @@ struct ImBuf *IMB_allocFromBuffer(const unsigned int *rect, unsigned int channels); /** - * * Increase reference count to imbuf * (to delete an imbuf you have to call freeImBuf as many times as it * is referenced) @@ -166,13 +155,11 @@ void IMB_refImBuf(struct ImBuf *ibuf); struct ImBuf *IMB_makeSingleUser(struct ImBuf *ibuf); /** - * * \attention Defined in allocimbuf.c */ struct ImBuf *IMB_dupImBuf(const struct ImBuf *ibuf1); /** - * * \attention Defined in allocimbuf.c */ bool addzbufImBuf(struct ImBuf *ibuf); @@ -197,7 +184,6 @@ size_t IMB_get_size_in_memory(struct ImBuf *ibuf); size_t IMB_get_rect_len(const struct ImBuf *ibuf); /** - * * \attention Defined in rectop.c */ @@ -304,7 +290,6 @@ void IMB_rectblend_threaded(struct ImBuf *dbuf, bool accumulate); /** - * * \attention Defined in indexer.c */ @@ -399,7 +384,6 @@ double IMD_anim_get_offset(struct anim *anim); bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base); /** - * * \attention Defined in anim_movie.c */ struct anim *IMB_open_anim(const char *name, @@ -412,7 +396,6 @@ void IMB_close_anim_proxies(struct anim *anim); bool IMB_anim_can_produce_frames(const struct anim *anim); /** - * * \attention Defined in anim_movie.c */ @@ -422,7 +405,6 @@ int IMB_anim_get_image_height(struct anim *anim); bool IMB_get_gop_decode_time(struct anim *anim); /** - * * \attention Defined in anim_movie.c */ @@ -432,20 +414,17 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, IMB_Proxy_Size preview_size /* = 0 = IMB_PROXY_NONE */); /** - * * \attention Defined in anim_movie.c * fetches a define preview-frame, usually half way into the movie. */ struct ImBuf *IMB_anim_previewframe(struct anim *anim); /** - * * \attention Defined in anim_movie.c */ void IMB_free_anim(struct anim *anim); /** - * * \attention Defined in filter.c */ @@ -474,7 +453,6 @@ void IMB_remakemipmap(struct ImBuf *ibuf, int use_filter); struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level); /** - * * \attention Defined in cache.c */ @@ -486,19 +464,16 @@ unsigned int *IMB_gettile(struct ImBuf *ibuf, int tx, int ty, int thread); void IMB_tiles_to_rect(struct ImBuf *ibuf); /** - * * \attention Defined in filter.c */ void IMB_filtery(struct ImBuf *ibuf); /** - * * \attention Defined in scaling.c */ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1); /** - * * \attention Defined in scaling.c * * Return true if \a ibuf is modified. @@ -506,7 +481,6 @@ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1); bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); /** - * * \attention Defined in scaling.c */ /** @@ -515,19 +489,16 @@ bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); /** - * * \attention Defined in scaling.c */ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int newy); /** - * * \attention Defined in writeimage.c */ bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags); /** - * * \attention Defined in util.c */ bool IMB_ispic(const char *filepath); @@ -536,13 +507,11 @@ int IMB_ispic_type_from_memory(const unsigned char *buf, size_t buf_size); int IMB_ispic_type(const char *filepath); /** - * * \attention Defined in util.c */ bool IMB_isanim(const char *filepath); /** - * * \attention Defined in util.c */ int imb_get_anim_type(const char *filepath); @@ -667,7 +636,6 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height); void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf); /** - * * \attention defined in imageprocess.c */ @@ -718,50 +686,42 @@ void IMB_sampleImageAtLocation( struct ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]); /** - * * \attention defined in readimage.c */ struct ImBuf *IMB_loadifffile( int file, const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr); /** - * * \attention defined in scaling.c */ struct ImBuf *IMB_half_x(struct ImBuf *ibuf1); /** - * * \attention defined in scaling.c */ struct ImBuf *IMB_double_fast_x(struct ImBuf *ibuf1); /** - * * \attention defined in scaling.c */ struct ImBuf *IMB_double_x(struct ImBuf *ibuf1); /** - * * \attention defined in scaling.c */ struct ImBuf *IMB_half_y(struct ImBuf *ibuf1); /** - * * \attention defined in scaling.c */ struct ImBuf *IMB_double_fast_y(struct ImBuf *ibuf1); /** - * * \attention defined in scaling.c */ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1); /** - * * \attention Defined in rotate.c */ void IMB_flipx(struct ImBuf *ibuf); @@ -773,14 +733,12 @@ void IMB_premultiply_alpha(struct ImBuf *ibuf); void IMB_unpremultiply_alpha(struct ImBuf *ibuf); /** - * * \attention Defined in allocimbuf.c */ void IMB_freezbufImBuf(struct ImBuf *ibuf); void IMB_freezbuffloatImBuf(struct ImBuf *ibuf); /** - * * \attention Defined in rectop.c */ /** @@ -925,7 +883,6 @@ void IMB_ffmpeg_init(void); const char *IMB_ffmpeg_last_error(void); /** - * * \attention defined in util_gpu.c */ GPUTexture *IMB_create_gpu_texture(const char *name, @@ -933,14 +890,22 @@ GPUTexture *IMB_create_gpu_texture(const char *name, bool use_high_bitdepth, bool use_premult); -eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf, bool high_bitdepth); +eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf, + bool high_bitdepth, + bool use_grayscale); /** * 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(). */ -GPUTexture *IMB_touch_gpu_texture( - const char *name, struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth); +GPUTexture *IMB_touch_gpu_texture(const char *name, + struct ImBuf *ibuf, + int w, + int h, + int layers, + bool use_high_bitdepth, + bool use_grayscale); + /** * Will update a #GPUTexture using the content of the #ImBuf. Only one layer will be updated. * Will resize the ibuf if needed. @@ -954,6 +919,7 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex, int w, int h, bool use_high_bitdepth, + bool use_grayscale, bool use_premult); /** diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 5ad226a26f2..45d05e9b856 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -251,7 +251,7 @@ typedef struct ImBuf { int refcounter; /* some parameters to pass along for packing images */ - /** Compressed image only used with PNG and EXR currently */ + /** Compressed image only used with PNG and EXR currently. */ unsigned char *encodedbuffer; /** Size of data written to `encodedbuffer`. */ unsigned int encodedsize; diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c index 967cbd04813..af9b62f1a74 100644 --- a/source/blender/imbuf/intern/bmp.c +++ b/source/blender/imbuf/intern/bmp.c @@ -178,7 +178,6 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[ const char(*palette)[4] = (const char(*)[4])(mem + palette_offset); const int startmask = ((1 << depth) - 1) << 8; for (size_t i = y; i > 0; i--) { - int index; int bitoffs = 8; int bitmask = startmask; int nbytes = 0; @@ -189,7 +188,7 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[ for (size_t j = x; j > 0; j--) { bitoffs -= depth; bitmask >>= depth; - index = (bmp[0] & bitmask) >> bitoffs; + const int index = (bmp[0] & bitmask) >> bitoffs; pcol = palette[index]; /* intentionally BGR -> RGB */ rect[0] = pcol[2]; diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 0414fa1268d..eb6ce5df794 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -2008,7 +2008,7 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem, printf("Error: can't process EXR multilayer file\n"); } else { - const int is_alpha = exr_has_alpha(*file); + const bool is_alpha = exr_has_alpha(*file); ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0); ibuf->flags |= exr_is_half_float(*file) ? IB_halffloat : 0; diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index 4b433836767..b33e9dc4e0e 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -209,7 +209,7 @@ static void imb_cache_filename(char *filepath, const char *name, int flags) ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]) { ImBuf *ibuf; - int file, a; + int file; char filepath_tx[IMB_FILENAME_SIZE]; BLI_assert(!BLI_path_is_rel(filepath)); @@ -226,7 +226,7 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S if (ibuf) { BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name)); BLI_strncpy(ibuf->cachename, filepath_tx, sizeof(ibuf->cachename)); - for (a = 1; a < ibuf->miptot; a++) { + for (int a = 1; a < ibuf->miptot; a++) { BLI_strncpy(ibuf->mipmap[a - 1]->cachename, filepath_tx, sizeof(ibuf->cachename)); } } diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 2f13ef409e3..1989566fc32 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -460,7 +460,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) scanline_contig_16bit(tmpibuf->rect_float + ib_offset, sbuf, ibuf->x, spp); } } - /* separate channels: RRRGGGBBB */ + /* Separate channels: RRRGGGBBB. */ } else if (config == PLANARCONFIG_SEPARATE) { @@ -549,10 +549,8 @@ ImBuf *imb_loadtiff(const unsigned char *mem, ImbTIFFMemFile memFile; uint32_t width, height; char *format = NULL; - int level; short spp; int ib_depth; - int found; /* Check whether or not we have a TIFF file. */ if (imb_is_a_tiff(mem, size) == 0) { @@ -574,7 +572,7 @@ ImBuf *imb_loadtiff(const unsigned char *mem, TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); - ib_depth = (spp == 3) ? 24 : 32; + ib_depth = spp * 8; ibuf = IMB_allocImBuf(width, height, ib_depth, 0); if (ibuf) { @@ -592,8 +590,7 @@ ImBuf *imb_loadtiff(const unsigned char *mem, if (flags & IB_alphamode_detect) { if (spp == 4) { unsigned short extra, *extraSampleTypes; - - found = TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes); + const int found = TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes); if (found && (extraSampleTypes[0] == EXTRASAMPLE_ASSOCALPHA)) { ibuf->flags |= IB_alphamode_premul; @@ -617,7 +614,7 @@ ImBuf *imb_loadtiff(const unsigned char *mem, int numlevel = TIFFNumberOfDirectories(image); /* create empty mipmap levels in advance */ - for (level = 0; level < numlevel; level++) { + for (int level = 0; level < numlevel; level++) { if (!TIFFSetDirectory(image, level)) { break; } diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc index 1499c1071e3..d64a48569ae 100644 --- a/source/blender/imbuf/intern/transform.cc +++ b/source/blender/imbuf/intern/transform.cc @@ -259,7 +259,6 @@ class WrapRepeatUV : public BaseUVWrapping { * \brief Read a sample from an image buffer. * * A sampler can read from an image buffer. - * */ template< /** \brief Interpolation mode to use when sampling. */ diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index 727704e27e8..6f1275e1812 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -14,6 +14,7 @@ #include "BKE_global.h" #include "GPU_capabilities.h" +#include "GPU_state.h" #include "GPU_texture.h" #include "IMB_colormanagement.h" @@ -22,39 +23,62 @@ /* gpu ibuf utils */ +static bool imb_is_grayscale_texture_format_compatible(const ImBuf *ibuf) +{ + if (ibuf->planes > 8) { + return false; + } + /* Only imbufs with colorspace that do not modify the chrominance of the texture data relative + * to the scene color space can be uploaded as single channel textures. */ + if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) || + IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) || + IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) { + return true; + }; + return false; +} + static void imb_gpu_get_format(const ImBuf *ibuf, bool high_bitdepth, + bool use_grayscale, eGPUDataFormat *r_data_format, eGPUTextureFormat *r_texture_format) { const bool float_rect = (ibuf->rect_float != NULL); + const bool is_grayscale = use_grayscale && imb_is_grayscale_texture_format_compatible(ibuf); if (float_rect) { /* Float. */ const bool use_high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth); *r_data_format = GPU_DATA_FLOAT; - *r_texture_format = use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F; + *r_texture_format = is_grayscale ? (use_high_bitdepth ? GPU_R32F : GPU_R16F) : + (use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F); } else { if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) || IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) { /* Non-color data or scene linear, just store buffer as is. */ *r_data_format = GPU_DATA_UBYTE; - *r_texture_format = GPU_RGBA8; + *r_texture_format = (is_grayscale) ? GPU_R8 : GPU_RGBA8; } else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) { /* sRGB, store as byte texture that the GPU can decode directly. */ - *r_data_format = GPU_DATA_UBYTE; - *r_texture_format = GPU_SRGB8_A8; + *r_data_format = (is_grayscale) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE; + *r_texture_format = (is_grayscale) ? GPU_R16F : GPU_SRGB8_A8; } else { /* Other colorspace, store as half float texture to avoid precision loss. */ *r_data_format = GPU_DATA_FLOAT; - *r_texture_format = GPU_RGBA16F; + *r_texture_format = (is_grayscale) ? GPU_R16F : GPU_RGBA16F; } } } +static const char *imb_gpu_get_swizzle(const ImBuf *ibuf) +{ + return imb_is_grayscale_texture_format_compatible(ibuf) ? "rrra" : "rgba"; +} + /* Return false if no suitable format was found. */ #ifdef WITH_DDS static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format) @@ -90,7 +114,8 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, const bool store_premultiplied, bool *r_freedata) { - const bool is_float_rect = (ibuf->rect_float != NULL); + bool is_float_rect = (ibuf->rect_float != NULL); + const bool is_grayscale = imb_is_grayscale_texture_format_compatible(ibuf); void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect; bool freedata = false; @@ -121,7 +146,8 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) || IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) { /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */ - data_rect = MEM_mallocN(sizeof(uchar[4]) * ibuf->x * ibuf->y, __func__); + data_rect = MEM_mallocN( + (is_grayscale ? sizeof(float[4]) : sizeof(uchar[4])) * ibuf->x * ibuf->y, __func__); *r_freedata = freedata = true; if (data_rect == NULL) { @@ -133,8 +159,16 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, * this allows us to use sRGB texture formats and preserves color values in * zero alpha areas, and appears generally closer to what game engines that we * want to be compatible with do. */ - IMB_colormanagement_imbuf_to_byte_texture( - (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied); + if (is_grayscale) { + /* Convert to byte buffer to then pack as half floats reducing the buffer size by half. */ + IMB_colormanagement_imbuf_to_float_texture( + (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied); + is_float_rect = true; + } + else { + IMB_colormanagement_imbuf_to_byte_texture( + (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied); + } } else { /* Other colorspace, store as float texture to avoid precision loss. */ @@ -167,21 +201,52 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, } data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect; - *r_freedata = true; + *r_freedata = freedata = true; /* Steal the rescaled buffer to avoid double free. */ scale_ibuf->rect_float = NULL; scale_ibuf->rect = NULL; IMB_freeImBuf(scale_ibuf); } + + /* Pack first channel data manually at the start of the buffer. */ + if (is_grayscale) { + void *src_rect = data_rect; + + if (freedata == false) { + data_rect = MEM_mallocN((is_float_rect ? sizeof(float) : sizeof(uchar)) * ibuf->x * ibuf->y, + __func__); + *r_freedata = freedata = true; + } + + if (data_rect == NULL) { + return NULL; + } + + if (is_float_rect) { + for (uint64_t i = 0; i < ibuf->x * ibuf->y; i++) { + ((float *)data_rect)[i] = ((float *)src_rect)[i * 4]; + } + } + else { + for (uint64_t i = 0; i < ibuf->x * ibuf->y; i++) { + ((uchar *)data_rect)[i] = ((uchar *)src_rect)[i * 4]; + } + } + } return data_rect; } -GPUTexture *IMB_touch_gpu_texture( - const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth) +GPUTexture *IMB_touch_gpu_texture(const char *name, + ImBuf *ibuf, + int w, + int h, + int layers, + bool use_high_bitdepth, + bool use_grayscale) { eGPUDataFormat data_format; eGPUTextureFormat tex_format; - imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format); + imb_gpu_get_format(ibuf, use_high_bitdepth, use_grayscale, &data_format, &tex_format); GPUTexture *tex; if (layers > 0) { @@ -191,6 +256,7 @@ GPUTexture *IMB_touch_gpu_texture( tex = GPU_texture_create_2d(name, w, h, 9999, tex_format, NULL); } + GPU_texture_swizzle_set(tex, imb_gpu_get_swizzle(ibuf)); GPU_texture_anisotropic_filter(tex, true); return tex; } @@ -203,6 +269,7 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex, int w, int h, bool use_high_bitdepth, + bool use_grayscale, bool use_premult) { const bool do_rescale = (ibuf->x != w || ibuf->y != h); @@ -210,7 +277,7 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex, eGPUDataFormat data_format; eGPUTextureFormat tex_format; - imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format); + imb_gpu_get_format(ibuf, use_high_bitdepth, use_grayscale, &data_format, &tex_format); bool freebuf = false; @@ -266,7 +333,7 @@ GPUTexture *IMB_create_gpu_texture(const char *name, eGPUDataFormat data_format; eGPUTextureFormat tex_format; - imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format); + imb_gpu_get_format(ibuf, use_high_bitdepth, true, &data_format, &tex_format); bool freebuf = false; @@ -282,6 +349,7 @@ GPUTexture *IMB_create_gpu_texture(const char *name, void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf); GPU_texture_update(tex, data_format, data); + GPU_texture_swizzle_set(tex, imb_gpu_get_swizzle(ibuf)); GPU_texture_anisotropic_filter(tex, true); if (freebuf) { @@ -291,12 +359,14 @@ GPUTexture *IMB_create_gpu_texture(const char *name, return tex; } -eGPUTextureFormat IMB_gpu_get_texture_format(const ImBuf *ibuf, bool high_bitdepth) +eGPUTextureFormat IMB_gpu_get_texture_format(const ImBuf *ibuf, + bool high_bitdepth, + bool use_grayscale) { eGPUTextureFormat gpu_texture_format; eGPUDataFormat gpu_data_format; - imb_gpu_get_format(ibuf, high_bitdepth, &gpu_data_format, &gpu_texture_format); + imb_gpu_get_format(ibuf, high_bitdepth, use_grayscale, &gpu_data_format, &gpu_texture_format); return gpu_texture_format; } diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index ded3258ff18..05025861857 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -60,6 +60,28 @@ struct AlembicExportParams { float global_scale; }; +struct AlembicImportParams { + /* Multiplier for the cached data scale. Mostly useful if the data is stored in a different unit + * as what Blender expects (e.g. centimeters instead of meters). */ + float global_scale; + + /* Number of consecutive files to expect if the cached animation is split in a sequence. */ + int sequence_len; + /* Start frame of the sequence, offset from 0. */ + int sequence_offset; + /* True if the cache is split in multiple files. */ + bool is_sequence; + + /* True if the importer should set the current scene's start and end frame based on the start and + * end frames of the cached animation. */ + bool set_frame_range; + /* True if imported meshes should be validated. Error messages are sent to the console. */ + bool validate_meshes; + /* True if a cache reader should be added regardless of whether there is animated data in the + * cached file. */ + bool always_add_cache_reader; +}; + /* The ABC_export and ABC_import functions both take a as_background_job * parameter, and return a boolean. * @@ -78,13 +100,7 @@ bool ABC_export(struct Scene *scene, bool ABC_import(struct bContext *C, const char *filepath, - float scale, - bool is_sequence, - bool set_frame_range, - int sequence_len, - int offset, - bool validate_meshes, - bool always_add_cache_reader, + const struct AlembicImportParams *params, bool as_background_job); struct CacheArchiveHandle *ABC_create_handle(struct Main *bmain, diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index 27df23b38c6..86622719f6e 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -672,13 +672,7 @@ static void import_freejob(void *user_data) bool ABC_import(bContext *C, const char *filepath, - float scale, - bool is_sequence, - bool set_frame_range, - int sequence_len, - int offset, - bool validate_meshes, - bool always_add_cache_reader, + const AlembicImportParams *params, bool as_background_job) { /* Using new here since MEM_* functions do not call constructor to properly initialize data. */ @@ -691,13 +685,13 @@ bool ABC_import(bContext *C, job->import_ok = false; BLI_strncpy(job->filename, filepath, 1024); - job->settings.scale = scale; - job->settings.is_sequence = is_sequence; - job->settings.set_frame_range = set_frame_range; - job->settings.sequence_len = sequence_len; - job->settings.sequence_offset = offset; - job->settings.validate_meshes = validate_meshes; - job->settings.always_add_cache_reader = always_add_cache_reader; + job->settings.scale = params->global_scale; + job->settings.is_sequence = params->is_sequence; + job->settings.set_frame_range = params->set_frame_range; + job->settings.sequence_len = params->sequence_len; + job->settings.sequence_offset = params->sequence_offset; + job->settings.validate_meshes = params->validate_meshes; + job->settings.always_add_cache_reader = params->always_add_cache_reader; job->error_code = ABC_NO_ERROR; job->was_cancelled = false; job->archive = nullptr; diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 3c2e8f66160..501800b8374 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -896,11 +896,9 @@ static bool bc_has_same_material_configuration(Object *ob1, Object *ob2) } /** - * * Caution here: This code assumes that all materials are assigned to Object * and no material is assigned to Data. * That is true right after the objects have been imported. - * */ static void bc_copy_materials_to_data(Object *ob, Mesh *me) { @@ -911,9 +909,7 @@ static void bc_copy_materials_to_data(Object *ob, Mesh *me) } /** - * - * Remove all references to materials from the object - * + * Remove all references to materials from the object. */ static void bc_remove_materials_from_object(Object *ob, Mesh *me) { diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h index 416b5728b66..92b387a4bfe 100644 --- a/source/blender/io/collada/MeshImporter.h +++ b/source/blender/io/collada/MeshImporter.h @@ -203,7 +203,6 @@ class MeshImporter : public MeshImporterBase { * if the check is positive: * Add the materials of the first user to the geometry * adjust all other users accordingly. - * */ void optimize_material_assignements(); diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h index a67cfe6a9d6..966eb640264 100644 --- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h +++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h @@ -228,7 +228,7 @@ class AbstractHierarchyIterator { * writer is created it will also write the current iteration, to ensure the hierarchy is * complete. The `export_subset` option is only in effect when the writer already existed from a * previous iteration. */ - void set_export_subset(ExportSubset export_subset_); + void set_export_subset(ExportSubset export_subset); /* Convert the given name to something that is valid for the exported file format. * This base implementation is a no-op; override in a concrete subclass. */ @@ -267,7 +267,7 @@ class AbstractHierarchyIterator { /* These three functions create writers and call their write() method. */ void make_writers(const HierarchyContext *parent_context); void make_writer_object_data(const HierarchyContext *context); - void make_writers_particle_systems(const HierarchyContext *context); + void make_writers_particle_systems(const HierarchyContext *transform_context); /* Return the appropriate HierarchyContext for the data of the object represented by * object_context. */ @@ -332,7 +332,7 @@ class AbstractHierarchyIterator { virtual void release_writer(AbstractHierarchyWriter *writer) = 0; AbstractHierarchyWriter *get_writer(const std::string &export_path) const; - ExportChildren &graph_children(const HierarchyContext *parent_context); + ExportChildren &graph_children(const HierarchyContext *context); }; } // namespace blender::io diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index 9b050af0891..815163ad19e 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -47,7 +47,7 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj /* Since a new mesh been allocated, it needs to be freed in the destructor. */ mesh_eval_needs_free_ = true; } - if (export_params.export_triangulated_mesh && ELEM(export_object_eval_.type, OB_MESH, OB_SURF)) { + if (export_params.export_triangulated_mesh && export_object_eval_.type == OB_MESH) { std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval(); } set_world_axes_transform(export_params.forward_axis, export_params.up_axis); @@ -133,7 +133,7 @@ void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) copy_m3_m4(normal_matrix, world_and_axes_transform_); invert_m3_m3(world_and_axes_normal_transform_, normal_matrix); transpose_m3(world_and_axes_normal_transform_); - mirrored_transform_ = determinant_m3_array(world_and_axes_normal_transform_) < 0; + mirrored_transform_ = is_negative_m3(world_and_axes_normal_transform_); } int OBJMesh::tot_vertices() const diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index e62470588ec..a570b374231 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -157,17 +157,21 @@ void MeshFromGeometry::fixup_invalid_faces() void MeshFromGeometry::create_vertices(Mesh *mesh) { - int mi = 0; - for (int vi : mesh_geometry_.vertices_) { - if (vi < global_vertices_.vertices.size()) { - copy_v3_v3(mesh->mvert[mi].co, global_vertices_.vertices[vi]); - } - else { - std::cerr << "Vertex index:" << vi - << " larger than total vertices:" << global_vertices_.vertices.size() << " ." - << std::endl; + /* Go through all the global vertex indices from min to max, + * checking which ones are actually and building a global->local + * index mapping. Write out the used vertex positions into the Mesh + * data. */ + mesh_geometry_.global_to_local_vertices_.clear(); + mesh_geometry_.global_to_local_vertices_.reserve(mesh_geometry_.vertices_.size()); + for (int vi = mesh_geometry_.vertex_index_min_; vi <= mesh_geometry_.vertex_index_max_; ++vi) { + BLI_assert(vi >= 0 && vi < global_vertices_.vertices.size()); + if (!mesh_geometry_.vertices_.contains(vi)) { + continue; } - ++mi; + int local_vi = (int)mesh_geometry_.global_to_local_vertices_.size(); + BLI_assert(local_vi >= 0 && local_vi < mesh->totvert); + copy_v3_v3(mesh->mvert[local_vi].co, global_vertices_.vertices[vi]); + mesh_geometry_.global_to_local_vertices_.add_new(vi, local_vi); } } diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc index 02e09a77a5d..093cbec32fe 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc @@ -95,12 +95,8 @@ static Image *create_placeholder_image(Main *bmain, const std::string &path) return image; } -static Image *load_texture_image(Main *bmain, - const tex_map_XX &tex_map, - bNode *r_node, - bool relative_paths) +static Image *load_texture_image(Main *bmain, const tex_map_XX &tex_map, bool relative_paths) { - BLI_assert(r_node && r_node->type == SH_NODE_TEX_IMAGE); Image *image = nullptr; /* First try treating texture path as relative. */ @@ -371,7 +367,8 @@ void ShaderNodetreeWrap::add_image_textures(Main *bmain, Material *mat, bool rel } bNode *image_texture = add_node_to_tree(SH_NODE_TEX_IMAGE); - Image *image = load_texture_image(bmain, texture_map.value, image_texture, relative_paths); + BLI_assert(image_texture); + Image *image = load_texture_image(bmain, texture_map.value, relative_paths); if (image == nullptr) { continue; } diff --git a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh index f48b6dd55e8..04d9a665588 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh +++ b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh @@ -11,8 +11,8 @@ #include "BLI_map.hh" #include "BLI_math_base.hh" #include "BLI_math_vec_types.hh" +#include "BLI_set.hh" #include "BLI_vector.hh" -#include "BLI_vector_set.hh" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -93,9 +93,11 @@ struct Geometry { int vertex_index_min_ = INT_MAX; int vertex_index_max_ = -1; - VectorSet<int> vertices_; + /* Global vertex indices used by this geometry. */ + Set<int> vertices_; + /* Mapping from global vertex index to geometry-local vertex index. */ Map<int, int> global_to_local_vertices_; - /** Edges written in the file in addition to (or even without polygon) elements. */ + /* Loose edges in the file. */ Vector<MEdge> edges_; Vector<PolyCorner> face_corners_; @@ -112,19 +114,15 @@ struct Geometry { } void track_vertex_index(int index) { - if (vertices_.add(index)) { - global_to_local_vertices_.add_new(index, (int)vertices_.size() - 1); - } + vertices_.add(index); math::min_inplace(vertex_index_min_, index); math::max_inplace(vertex_index_max_, index); } void track_all_vertices(int count) { vertices_.reserve(count); - global_to_local_vertices_.reserve(count); for (int i = 0; i < count; ++i) { vertices_.add(i); - global_to_local_vertices_.add(i, i); } vertex_index_min_ = 0; vertex_index_max_ = count - 1; diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 6aec848573f..f582064e0c1 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -60,7 +60,7 @@ TEST_F(obj_exporter_test, filter_objects_curves_as_mesh) return; } auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; - EXPECT_EQ(objmeshes.size(), 20); + EXPECT_EQ(objmeshes.size(), 21); EXPECT_EQ(objcurves.size(), 0); } diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index 132bb03357f..bd9360548af 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -154,7 +154,7 @@ TEST_F(obj_importer_test, import_cube) 12, 6, 24, - float3(1, -1, 1), + float3(-1, -1, 1), float3(1, -1, -1), float3(-0.57735f, 0.57735f, -0.57735f)}, }; @@ -172,7 +172,7 @@ TEST_F(obj_importer_test, import_cube_o_after_verts) 12, 6, 24, - float3(1, -1, 1), + float3(-1, -1, 1), float3(1, -1, -1), float3(0, 0, 1), }, @@ -183,8 +183,8 @@ TEST_F(obj_importer_test, import_cube_o_after_verts) 3, 1, 3, + float3(1, -1, 1), float3(-2, -2, 2), - float3(-1, -1, -1), float3(-0.2357f, 0.9428f, 0.2357f), }, }; @@ -201,8 +201,8 @@ TEST_F(obj_importer_test, import_suzanne_all_data) 1005, 500, 1968, - float3(-0.5f, 0.09375f, 0.6875f), - float3(0.546875f, 0.054688f, 0.578125f), + float3(-0.4375f, 0.164062f, 0.765625f), + float3(0.4375f, 0.164062f, 0.765625f), float3(-0.6040f, -0.5102f, 0.6122f), float2(0.692094f, 0.40191f)}, }; @@ -307,7 +307,7 @@ TEST_F(obj_importer_test, import_materials) { Expectation expect[] = { {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, - {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(1, -1, 1), float3(1, -1, -1)}, + {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)}, }; import_and_check("materials.obj", expect, std::size(expect), 4, 8); } @@ -323,7 +323,7 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) 6, 24, float3(1, 1, -1), - float3(1, -1, -1), + float3(-1, -1, 1), float3(0, 1, 0), float2(0.9935f, 0.0020f)}, {"OBCubeTexMul", @@ -333,7 +333,7 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) 6, 24, float3(4, -2, -1), - float3(4, -4, -1), + float3(2, -4, 1), float3(0, 1, 0), float2(0.9935f, 0.0020f)}, {"OBCubeTiledTex", @@ -343,7 +343,7 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) 6, 24, float3(4, 1, -1), - float3(4, -1, -1), + float3(2, -1, 1), float3(0, 1, 0), float2(0.9935f, 0.0020f)}, {"OBCubeTiledTexFromAnotherFolder", @@ -353,7 +353,7 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) 6, 24, float3(7, 1, -1), - float3(7, -1, -1), + float3(5, -1, 1), float3(0, 1, 0), float2(0.9935f, 0.0020f)}, }; @@ -444,15 +444,15 @@ TEST_F(obj_importer_test, import_all_objects) {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, /* .obj file has empty EmptyText and EmptyMesh objects; these are ignored and skipped */ {"OBBezierCurve", OB_MESH, 13, 12, 0, 0, float3(-1, -2, 0), float3(1, -2, 0)}, - {"OBBlankCube", OB_MESH, 8, 13, 7, 26, float3(1, 1, 1), float3(-1, 1, -1), float3(0, 0, 1)}, + {"OBBlankCube", OB_MESH, 8, 13, 7, 26, float3(1, 1, -1), float3(-1, 1, 1), float3(0, 0, 1)}, {"OBMaterialCube", OB_MESH, 8, 13, 7, 26, - float3(26, -1, -1), - float3(28, -1, -1), + float3(28, 1, -1), + float3(26, 1, 1), float3(-1, 0, 0)}, {"OBNurbsCircle", OB_MESH, @@ -462,15 +462,15 @@ TEST_F(obj_importer_test, import_all_objects) 0, float3(3.292893f, -2.707107f, 0), float3(3.369084f, -2.77607f, 0)}, - {"OBNurbsCircle.001", OB_MESH, 4, 4, 0, 0, float3(3, -2, 0), float3(2, -1, 0)}, + {"OBNurbsCircle.001", OB_MESH, 4, 4, 0, 0, float3(2, -3, 0), float3(3, -2, 0)}, {"OBParticleCube", OB_MESH, 8, 13, 7, 26, - float3(22, 1, 1), - float3(20, 1, -1), + float3(22, 1, -1), + float3(20, 1, 1), float3(0, 0, 1)}, {"OBShapeKeyCube", OB_MESH, @@ -478,8 +478,8 @@ TEST_F(obj_importer_test, import_all_objects) 13, 7, 26, - float3(19, 1, 2), - float3(17, 1, -1), + float3(19, 1, -1), + float3(17, 1, 1), float3(-0.4082f, -0.4082f, 0.8165f)}, {"OBSmoothCube", OB_MESH, @@ -487,8 +487,8 @@ TEST_F(obj_importer_test, import_all_objects) 13, 7, 26, - float3(4, 1, 1), - float3(2, 1, -1), + float3(4, 1, -1), + float3(2, 1, 1), float3(0.5774f, 0.5773f, 0.5774f)}, {"OBSurface", OB_MESH, @@ -496,7 +496,7 @@ TEST_F(obj_importer_test, import_all_objects) 480, 224, 896, - float3(7.292893f, -2.707107f, -0.714285f), + float3(7.292893f, -2.707107f, -1), float3(7.525872f, -2.883338f, 1), float3(-0.7071f, -0.7071f, 0), float2(0, 0.142857f)}, @@ -506,7 +506,7 @@ TEST_F(obj_importer_test, import_all_objects) 480, 225, 900, - float3(12.56667f, -2.5f, 0.72037f), + float3(12.5f, -2.5f, 0.694444f), float3(13.5f, -1.5f, 0.694444f), float3(-0.3246f, -0.3531f, 0.8775f), float2(0, 0.066667f)}, @@ -527,7 +527,7 @@ TEST_F(obj_importer_test, import_all_objects) 1024, 4096, float3(5.34467f, -2.65533f, -0.176777f), - float3(5.158205f, -2.234695f, -0.220835f), + float3(5.232792f, -2.411795f, -0.220835f), float3(-0.5042f, -0.5042f, -0.7011f), float2(0, 1)}, {"OBTaperCube", @@ -536,8 +536,8 @@ TEST_F(obj_importer_test, import_all_objects) 208, 104, 416, - float3(24.316156f, 0.345556f, 0.796778f), - float3(23.551804f, 0.389113f, -0.639607f), + float3(24.444445f, 0.502543f, -0.753814f), + float3(23.790743f, 0.460522f, -0.766546f), float3(-0.0546f, 0.1716f, 0.9837f)}, {"OBText", OB_MESH, @@ -545,8 +545,8 @@ TEST_F(obj_importer_test, import_all_objects) 345, 171, 513, - float3(1.583f, -9.621f, 0), - float3(0.351f, -10.0f, 0), + float3(1.75f, -9.458f, 0), + float3(0.587f, -9.406f, 0), float3(0, 0, 1), float2(0.017544f, 0)}, {"OBUVCube", @@ -555,8 +555,8 @@ TEST_F(obj_importer_test, import_all_objects) 13, 7, 26, - float3(7, 1, 1), - float3(5, 1, -1), + float3(7, 1, -1), + float3(5, 1, 1), float3(0, 0, 1), float2(0.654526f, 0.579873f)}, {"OBUVImageCube", @@ -565,8 +565,8 @@ TEST_F(obj_importer_test, import_all_objects) 13, 7, 26, - float3(10, 1, 1), - float3(8, 1, -1), + float3(10, 1, -1), + float3(8, 1, 1), float3(0, 0, 1), float2(0.654526f, 0.579873f)}, {"OBVColCube", @@ -575,8 +575,8 @@ TEST_F(obj_importer_test, import_all_objects) 13, 7, 26, - float3(13, 1, 1), - float3(11, 1, -1), + float3(13, 1, -1), + float3(11, 1, 1), float3(0, 0, 1), float2(0, 0), float4(0.0f, 0.002125f, 1.0f, 1.0f)}, @@ -586,8 +586,8 @@ TEST_F(obj_importer_test, import_all_objects) 13, 7, 26, - float3(16, 1, 1), - float3(14, 1, -1), + float3(16, 1, -1), + float3(14, 1, 1), float3(0, 0, 1)}, }; import_and_check("all_objects.obj", expect, std::size(expect), 7); @@ -604,7 +604,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors) 6, 24, float3(1.0f, 1.0f, -3.812445f), - float3(1.0f, -1.0f, -3.812445f), + float3(-1.0f, -1.0f, -1.812445f), float3(0, 0, 0), float2(0, 0), float4(0.89627f, 0.036889f, 0.47932f, 1.0f)}, @@ -615,7 +615,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors) 6, 24, float3(3.481967f, 1.0f, -3.812445f), - float3(3.481967f, -1.0f, -3.812445f), + float3(1.481967f, -1.0f, -1.812445f), float3(0, 0, 0), float2(0, 0), float4(1.564582f, 0.039217f, 0.664309f, 1.0f)}, @@ -626,7 +626,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors) 6, 24, float3(-4.725068f, -1.0f, 1.0f), - float3(-2.725068f, -1.0f, 1.0f), + float3(-2.725068f, 1.0f, -1.0f), float3(0, 0, 0), float2(0, 0), float4(0.270498f, 0.47932f, 0.262251f, 1.0f)}, @@ -637,7 +637,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors) 6, 24, float3(-4.550208f, -1.0f, -1.918042f), - float3(-2.550208f, -1.0f, -1.918042f)}, + float3(-2.550208f, 1.0f, -3.918042f)}, {"OBCubeVertexByte", OB_MESH, 8, @@ -645,7 +645,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors) 6, 24, float3(1.0f, 1.0f, -1.0f), - float3(1.0f, -1.0f, -1.0f), + float3(-1.0f, -1.0f, 1.0f), float3(0, 0, 0), float2(0, 0), float4(0.846873f, 0.027321f, 0.982123f, 1.0f)}, @@ -656,7 +656,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors) 6, 24, float3(3.392028f, 1.0f, -1.0f), - float3(3.392028f, -1.0f, -1.0f), + float3(1.392028f, -1.0f, 1.0f), float3(0, 0, 0), float2(0, 0), float4(49.99467f, 0.027321f, 0.982123f, 1.0f)}, @@ -675,7 +675,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb) 6, 24, float3(4, 1, -1), - float3(4, -1, -1), + float3(2, -1, 1), float3(0, 0, 0), float2(0, 0), float4(0.8714f, 0.6308f, 0.5271f, 1.0f)}, @@ -686,7 +686,7 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb) 6, 24, float3(1, 1, -1), - float3(1, -1, -1), + float3(-1, -1, 1), float3(0, 0, 0), float2(0, 0), float4(0.6038f, 0.3185f, 0.1329f, 1.0f)}, diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h index 89deeec898b..6c38d316508 100644 --- a/source/blender/makesdna/DNA_curves_types.h +++ b/source/blender/makesdna/DNA_curves_types.h @@ -30,6 +30,7 @@ typedef enum CurveType { CURVE_TYPE_BEZIER = 2, CURVE_TYPE_NURBS = 3, } CurveType; +/* The number of supported curve types. */ #define CURVE_TYPES_NUM 4 typedef enum HandleType { diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 1a133127eaf..f35fa2699c6 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -112,7 +112,7 @@ typedef struct Mesh_Runtime { * (most #eModifierTypeType_NonGeometrical modifiers). Otherwise the edit-mesh * data will be used for drawing, missing changes from modifiers. See T79517. */ - char is_original; + char is_original_bmesh; /** #eMeshWrapperType and others. */ char wrapper_type; diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 209ffd3342d..580d867d697 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -38,6 +38,7 @@ typedef struct MVert { #ifdef DNA_DEPRECATED_ALLOW enum { /* SELECT = (1 << 0), */ + /** Deprecated hide status. Now stored in ".hide_vert" attribute. */ ME_HIDE = (1 << 4), }; #endif @@ -63,6 +64,7 @@ enum { /* SELECT = (1 << 0), */ ME_EDGEDRAW = (1 << 1), ME_SEAM = (1 << 2), + /** Deprecated hide status. Now stored in ".hide_edge" attribute. */ /* ME_HIDE = (1 << 4), */ ME_EDGERENDER = (1 << 5), ME_LOOSEEDGE = (1 << 7), @@ -88,6 +90,7 @@ typedef struct MPoly { enum { ME_SMOOTH = (1 << 0), ME_FACE_SEL = (1 << 1), + /** Deprecated hide status. Now stored in ".hide_poly" attribute. */ /* ME_HIDE = (1 << 4), */ }; diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h index 519dfb7e9b3..d0c09a0d6ab 100644 --- a/source/blender/makesdna/DNA_meta_types.h +++ b/source/blender/makesdna/DNA_meta_types.h @@ -92,8 +92,6 @@ typedef struct MetaBall { /* used in editmode */ // ListBase edit_elems; MetaElem *lastelem; - - void *batch_cache; } MetaBall; /* **************** METABALL ********************* */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b9161e918c0..3477105f519 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1881,6 +1881,18 @@ typedef enum CMPNodeFlipMode { CMP_NODE_FLIP_X_Y = 2, } CMPNodeFlipMode; +/* Filter Node. Stored in custom1. */ +typedef enum CMPNodeFilterMethod { + CMP_NODE_FILTER_SOFT = 0, + CMP_NODE_FILTER_SHARP_BOX = 1, + CMP_NODE_FILTER_LAPLACE = 2, + CMP_NODE_FILTER_SOBEL = 3, + CMP_NODE_FILTER_PREWITT = 4, + CMP_NODE_FILTER_KIRSCH = 5, + CMP_NODE_FILTER_SHADOW = 6, + CMP_NODE_FILTER_SHARP_DIAMOND = 7, +} CMPNodeFilterMethod; + /* Plane track deform node. */ enum { diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index cfb077748ef..cc65b615cb7 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -820,6 +820,7 @@ typedef struct RenderProfile { /** #ToolSettings.uv_relax_method */ #define UV_SCULPT_TOOL_RELAX_LAPLACIAN 1 #define UV_SCULPT_TOOL_RELAX_HC 2 +#define UV_SCULPT_TOOL_RELAX_COTAN 3 /* Stereo Flags */ #define STEREO_RIGHT_NAME "right" @@ -2037,8 +2038,8 @@ extern const char *RE_engine_id_CYCLES; (BASE_EDITABLE(v3d, base) && (((base)->flag & BASE_SELECTED) != 0)) /* deprecate this! */ -#define FIRSTBASE(_view_layer) ((_view_layer)->object_bases.first) -#define LASTBASE(_view_layer) ((_view_layer)->object_bases.last) +#define FIRSTBASE(_view_layer) ((struct Base *)(_view_layer)->object_bases.first) +#define LASTBASE(_view_layer) ((struct Base *)(_view_layer)->object_bases.last) #define BASACT(_view_layer) ((_view_layer)->basact) #define OBACT(_view_layer) (BASACT(_view_layer) ? BASACT(_view_layer)->object : NULL) @@ -2209,7 +2210,7 @@ enum { OB_DRAW_GROUPUSER_ALL = 2, }; -/* object_vgroup.c */ +/* object_vgroup.cc */ /** #ToolSettings.vgroupsubset */ typedef enum eVGroupSelect { diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index e9178c0cbf5..856d48e395b 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -628,7 +628,7 @@ enum { /* Bitflags affecting behavior of any kind of sorting. */ /** Special flag to indicate that order is locked (not user-changeable). */ UILST_FLT_SORT_LOCK = 1u << 30, - /** Special value, bitflag used to reverse order! */ + /** Special value, bit-flag used to reverse order! */ UILST_FLT_SORT_REVERSE = 1u << 31, }; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 1ea6fbbaf83..d13f3fad270 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -50,14 +50,19 @@ struct wmTimer; /** Defined in `buttons_intern.h`. */ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; -/** Defined in `node_intern.hh`. */ #ifdef __cplusplus namespace blender::ed::space_node { struct SpaceNode_Runtime; } // namespace blender::ed::space_node using SpaceNode_Runtime = blender::ed::space_node::SpaceNode_Runtime; + +namespace blender::ed::outliner { +struct SpaceOutliner_Runtime; +} // namespace blender::ed::outliner +using SpaceOutliner_Runtime = blender::ed::outliner::SpaceOutliner_Runtime; #else typedef struct SpaceNode_Runtime SpaceNode_Runtime; +typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime; #endif /** Defined in `file_intern.h`. */ @@ -252,9 +257,6 @@ typedef enum eSpaceButtons_OutlinerSync { /** \name Outliner * \{ */ -/** Defined in `outliner_intern.hh`. */ -typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime; - /** Outliner */ typedef struct SpaceOutliner { SpaceLink *next, *prev; @@ -278,9 +280,7 @@ typedef struct SpaceOutliner { */ struct BLI_mempool *treestore; - /* search stuff */ char search_string[64]; - struct TreeStoreElem search_tse; short flag; short outlinevis; @@ -407,8 +407,8 @@ typedef enum eSpaceOutliner_StoreFlag { /* cleanup tree */ SO_TREESTORE_CLEANUP = (1 << 0), SO_TREESTORE_UNUSED_1 = (1 << 1), /* cleared */ - /* rebuild the tree, similar to cleanup, - * but defer a call to BKE_outliner_treehash_rebuild_from_treestore instead */ + /** Rebuild the tree, similar to cleanup, but defer a call to + * bke::outliner::treehash::rebuild_from_treestore instead. */ SO_TREESTORE_REBUILD = (1 << 2), } eSpaceOutliner_StoreFlag; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index ac553c2655f..dc461502b10 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -637,11 +637,11 @@ typedef struct UserDef_Experimental { /* Debug options, always available. */ char use_undo_legacy; char no_override_auto_resync; - char use_override_new_fully_editable; char use_cycles_debug; char show_asset_debug_info; char no_asset_indexing; char SANITIZE_AFTER_HERE; + char _pad0; /* The following options are automatically sanitized (set to 0) * when the release cycle is not alpha. */ char use_new_curves_tools; @@ -1162,7 +1162,7 @@ typedef enum eUserpref_StatusBar_Flag { * #UserDef.autokey_mode */ typedef enum eAutokey_Mode { - /* AUTOKEY_ON is a bitflag */ + /* AUTOKEY_ON is a bit-flag. */ AUTOKEY_ON = 1, /** diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h index c8498f096ed..d08865cefb5 100644 --- a/source/blender/makesdna/DNA_view2d_types.h +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -29,7 +29,7 @@ typedef struct View2D { /** Allowable zoom factor range (only when (keepzoom & V2D_LIMITZOOM)) is set. */ float minzoom, maxzoom; - /** Scroll - scrollbars to display (bitflag). */ + /** Scroll - scrollbars to display (bit-flag). */ short scroll; /** Scroll_ui - temp settings used for UI drawing of scrollers. */ short scroll_ui; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 116ea4821cb..2586e13da39 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -151,6 +151,11 @@ typedef struct wmWindowManager { /** Refresh/redraw #wmNotifier structs. */ ListBase notifier_queue; + /** + * For duplicate detection. + * \note keep in sync with `notifier_queue` adding/removing elements must also update this set. + */ + struct GSet *notifier_queue_set; /** Information and error reports. */ struct ReportList reports; diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index c26696b4572..97198117a83 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -5,6 +5,11 @@ add_definitions(-DWITH_DNA_GHASH) +# Needed for `mallocn.c`. +if(HAVE_MALLOC_STATS_H) + add_definitions(-DHAVE_MALLOC_STATS_H) +endif() + blender_include_dirs( ../../../../intern/atomic ../../../../intern/guardedalloc diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index de9fa60aa5d..ddc010f27a1 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -430,6 +430,10 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr, PointerRNA *r_ptr); int RNA_property_collection_lookup_string_index( PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr, int *r_index); + +bool RNA_property_collection_lookup_int_has_fn(PropertyRNA *prop); +bool RNA_property_collection_lookup_string_has_fn(PropertyRNA *prop); + /** * Zero return is an assignment error. */ diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 8124804de2b..7e6e3bcf90e 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -6,6 +6,11 @@ if(CMAKE_COMPILER_IS_GNUCC) string(APPEND CMAKE_C_FLAGS " -Werror=implicit-function-declaration") endif() +# Needed for `mallocn.c`. +if(HAVE_MALLOC_STATS_H) + add_definitions(-DHAVE_MALLOC_STATS_H) +endif() + # files rna_access.c rna_define.c makesrna.c intentionally excluded. set(DEFSRC rna_ID.c @@ -387,7 +392,6 @@ blender_include_dirs( ../../render ../../../../intern/cycles/blender ../../../../intern/atomic - ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../../../intern/memutil ../../../../intern/mantaflow/extern @@ -450,8 +454,6 @@ set(LIB bf_editor_undo ) -add_definitions(${GL_DEFINITIONS}) - blender_add_lib(bf_rna "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # Needed so we can use dna_type_offsets.h for defaults initialization. diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 2b24bd0b39c..a7b8488c371 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -826,7 +826,23 @@ static char *rna_def_property_get_func( fprintf(f, "{\n"); if (manualfunc) { - fprintf(f, " %s(ptr, values);\n", manualfunc); + /* Assign `fn` to ensure function signatures match. */ + if (prop->type == PROP_BOOLEAN) { + fprintf(f, " PropBooleanArrayGetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, values);\n"); + } + else if (prop->type == PROP_INT) { + fprintf(f, " PropIntArrayGetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, values);\n"); + } + else if (prop->type == PROP_FLOAT) { + fprintf(f, " PropFloatArrayGetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, values);\n"); + } + else { + BLI_assert_unreachable(); /* Valid but should be handled by type checks. */ + fprintf(f, " %s(ptr, values);\n", manualfunc); + } } else { rna_print_data_get(f, dp); @@ -902,7 +918,27 @@ static char *rna_def_property_get_func( fprintf(f, "{\n"); if (manualfunc) { - fprintf(f, " return %s(ptr);\n", manualfunc); + /* Assign `fn` to ensure function signatures match. */ + if (prop->type == PROP_BOOLEAN) { + fprintf(f, " PropBooleanGetFunc fn = %s;\n", manualfunc); + fprintf(f, " return fn(ptr);\n"); + } + else if (prop->type == PROP_INT) { + fprintf(f, " PropIntGetFunc fn = %s;\n", manualfunc); + fprintf(f, " return fn(ptr);\n"); + } + else if (prop->type == PROP_FLOAT) { + fprintf(f, " PropFloatGetFunc fn = %s;\n", manualfunc); + fprintf(f, " return fn(ptr);\n"); + } + else if (prop->type == PROP_ENUM) { + fprintf(f, " PropEnumGetFunc fn = %s;\n", manualfunc); + fprintf(f, " return fn(ptr);\n"); + } + else { + BLI_assert_unreachable(); /* Valid but should be handled by type checks. */ + fprintf(f, " return %s(ptr);\n", manualfunc); + } } else { rna_print_data_get(f, dp); @@ -1197,7 +1233,23 @@ static char *rna_def_property_set_func( fprintf(f, "{\n"); if (manualfunc) { - fprintf(f, " %s(ptr, values);\n", manualfunc); + /* Assign `fn` to ensure function signatures match. */ + if (prop->type == PROP_BOOLEAN) { + fprintf(f, " PropBooleanArraySetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, values);\n"); + } + else if (prop->type == PROP_INT) { + fprintf(f, " PropIntArraySetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, values);\n"); + } + else if (prop->type == PROP_FLOAT) { + fprintf(f, " PropFloatArraySetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, values);\n"); + } + else { + BLI_assert_unreachable(); /* Valid but should be handled by type checks. */ + fprintf(f, " %s(ptr, values);\n", manualfunc); + } } else { rna_print_data_get(f, dp); @@ -1289,7 +1341,27 @@ static char *rna_def_property_set_func( fprintf(f, "{\n"); if (manualfunc) { - fprintf(f, " %s(ptr, value);\n", manualfunc); + /* Assign `fn` to ensure function signatures match. */ + if (prop->type == PROP_BOOLEAN) { + fprintf(f, " PropBooleanSetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, value);\n"); + } + else if (prop->type == PROP_INT) { + fprintf(f, " PropIntSetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, value);\n"); + } + else if (prop->type == PROP_FLOAT) { + fprintf(f, " PropFloatSetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, value);\n"); + } + else if (prop->type == PROP_ENUM) { + fprintf(f, " PropEnumSetFunc fn = %s;\n", manualfunc); + fprintf(f, " fn(ptr, value);\n"); + } + else { + BLI_assert_unreachable(); /* Valid but should be handled by type checks. */ + fprintf(f, " %s(ptr, value);\n", manualfunc); + } } else { rna_print_data_get(f, dp); diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index c59e45e1b01..d31a312816a 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -322,7 +322,7 @@ int rna_ID_name_full_length(PointerRNA *ptr) return strlen(name); } -static int rna_ID_is_evaluated_get(PointerRNA *ptr) +static bool rna_ID_is_evaluated_get(PointerRNA *ptr) { ID *id = (ID *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index ada73157026..c0104b1472c 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4080,6 +4080,20 @@ int RNA_property_collection_lookup_index(PointerRNA *ptr, return -1; } +bool RNA_property_collection_lookup_int_has_fn(PropertyRNA *prop) +{ + BLI_assert(RNA_property_type(prop) == PROP_COLLECTION); + CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop); + return cprop->lookupint != NULL; +} + +bool RNA_property_collection_lookup_string_has_fn(PropertyRNA *prop) +{ + BLI_assert(RNA_property_type(prop) == PROP_COLLECTION); + CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop); + return cprop->lookupstring != NULL; +} + int RNA_property_collection_lookup_int(PointerRNA *ptr, PropertyRNA *prop, int key, diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index e0d55050c63..82eb390df52 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -765,11 +765,11 @@ static void rna_Brush_set_size(PointerRNA *ptr, int value) brush->size = value; } -static void rna_Brush_use_gradient_set(PointerRNA *ptr, bool value) +static void rna_Brush_use_gradient_set(PointerRNA *ptr, int value) { Brush *br = (Brush *)ptr->data; - if (value) { + if (value & BRUSH_USE_GRADIENT) { br->flag |= BRUSH_USE_GRADIENT; } else { diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 2a85da42483..b68d87587e7 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -682,7 +682,6 @@ static void rna_ColorManagement_update(Main *UNUSED(bmain), Scene *UNUSED(scene) } if (GS(id->name) == ID_SCE) { - DEG_id_tag_update(id, 0); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL); } } @@ -1271,7 +1270,7 @@ static void rna_def_colormanage(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Use Curves", "Use RGB curved for pre-display transformation"); RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update"); - /* ** Colorspace ** */ + /* ** Color-space ** */ srna = RNA_def_struct(brna, "ColorManagedInputColorspaceSettings", NULL); RNA_def_struct_path_func(srna, "rna_ColorManagedInputColorspaceSettings_path"); RNA_def_struct_ui_text( diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index fff3f479a3f..3a90d631c63 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -67,7 +67,8 @@ const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = { */ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = { /* Interpolation. */ - RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_ACTION, "Interpolation"), + N_("Standard transitions between keyframes")), {BEZT_IPO_CONST, "CONSTANT", ICON_IPO_CONSTANT, @@ -85,9 +86,9 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = { "Smooth interpolation between A and B, with some control over curve shape"}, /* Easing. */ - RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"), - "Predefined inertial transitions, useful for motion graphics " - "(from least to most \"dramatic\")"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_ACTION, "Easing (by strength)"), + N_("Predefined inertial transitions, useful for motion graphics " + "(from least to most \"dramatic\")")), {BEZT_IPO_SINE, "SINE", ICON_IPO_SINE, @@ -104,7 +105,8 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = { "Circular", "Circular easing (strongest and most dynamic)"}, - RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_ACTION, "Dynamic Effects"), + N_("Simple physics-inspired easing effects")), {BEZT_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"}, {BEZT_IPO_BOUNCE, "BOUNCE", @@ -437,7 +439,7 @@ static void rna_Curve_bevelObject_set(PointerRNA *ptr, if (ob) { /* If bevel object has got the save curve, as object, for which it's set as bevobj, - * there could be infinity loop in #DispList calculation. */ + * there could be an infinite loop in curve evaluation. */ if (ob->type == OB_CURVES_LEGACY && ob->data != cu) { cu->bevobj = ob; id_lib_extern((ID *)ob); @@ -512,7 +514,7 @@ static void rna_Curve_taperObject_set(PointerRNA *ptr, if (ob) { /* If taper object has got the save curve, as object, for which it's set as bevobj, - * there could be infinity loop in #DispList calculation. */ + * there could be an infinite loop in curve evaluation. */ if (ob->type == OB_CURVES_LEGACY && ob->data != cu) { cu->taperobj = ob; id_lib_extern((ID *)ob); diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 6196f8d1ca0..ff107d0b833 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -43,23 +43,41 @@ /* **************** Object Instance **************** */ +typedef struct RNA_DepsgraphIterator { + BLI_Iterator iter; +# ifdef WITH_PYTHON + /** + * Store the Python instance so the #BPy_StructRNA can be set as invalid iteration is completed. + * Otherwise accessing from Python (console auto-complete for e.g.) crashes, see: T100286. */ + void *py_instance; +# endif +} RNA_DepsgraphIterator; + +# ifdef WITH_PYTHON +void **rna_DepsgraphIterator_instance(PointerRNA *ptr) +{ + RNA_DepsgraphIterator *di = ptr->data; + return &di->py_instance; +} +# endif + static PointerRNA rna_DepsgraphObjectInstance_object_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - return rna_pointer_inherit_refine(ptr, &RNA_Object, iterator->current); + RNA_DepsgraphIterator *di = ptr->data; + return rna_pointer_inherit_refine(ptr, &RNA_Object, di->iter.current); } -static int rna_DepsgraphObjectInstance_is_instance_get(PointerRNA *ptr) +static bool rna_DepsgraphObjectInstance_is_instance_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; return (deg_iter->dupli_object_current != NULL); } static PointerRNA rna_DepsgraphObjectInstance_instance_object_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; Object *instance_object = NULL; if (deg_iter->dupli_object_current != NULL) { instance_object = deg_iter->dupli_object_current->ob; @@ -69,24 +87,24 @@ static PointerRNA rna_DepsgraphObjectInstance_instance_object_get(PointerRNA *pt static bool rna_DepsgraphObjectInstance_show_self_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; - int ob_visibility = BKE_object_visibility(iterator->current, deg_iter->eval_mode); + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; + int ob_visibility = BKE_object_visibility(di->iter.current, deg_iter->eval_mode); return (ob_visibility & OB_VISIBLE_SELF) != 0; } static bool rna_DepsgraphObjectInstance_show_particles_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; - int ob_visibility = BKE_object_visibility(iterator->current, deg_iter->eval_mode); + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; + int ob_visibility = BKE_object_visibility(di->iter.current, deg_iter->eval_mode); return (ob_visibility & OB_VISIBLE_PARTICLES) != 0; } static PointerRNA rna_DepsgraphObjectInstance_parent_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; Object *dupli_parent = NULL; if (deg_iter->dupli_object_current != NULL) { dupli_parent = deg_iter->dupli_parent; @@ -96,8 +114,8 @@ static PointerRNA rna_DepsgraphObjectInstance_parent_get(PointerRNA *ptr) static PointerRNA rna_DepsgraphObjectInstance_particle_system_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; struct ParticleSystem *particle_system = NULL; if (deg_iter->dupli_object_current != NULL) { particle_system = deg_iter->dupli_object_current->particle_system; @@ -107,8 +125,8 @@ static PointerRNA rna_DepsgraphObjectInstance_particle_system_get(PointerRNA *pt static void rna_DepsgraphObjectInstance_persistent_id_get(PointerRNA *ptr, int *persistent_id) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; if (deg_iter->dupli_object_current != NULL) { memcpy(persistent_id, deg_iter->dupli_object_current->persistent_id, @@ -119,12 +137,12 @@ static void rna_DepsgraphObjectInstance_persistent_id_get(PointerRNA *ptr, int * } } -static unsigned int rna_DepsgraphObjectInstance_random_id_get(PointerRNA *ptr) +static int rna_DepsgraphObjectInstance_random_id_get(PointerRNA *ptr) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; if (deg_iter->dupli_object_current != NULL) { - return deg_iter->dupli_object_current->random_id; + return (int)deg_iter->dupli_object_current->random_id; } else { return 0; @@ -133,23 +151,23 @@ static unsigned int rna_DepsgraphObjectInstance_random_id_get(PointerRNA *ptr) static void rna_DepsgraphObjectInstance_matrix_world_get(PointerRNA *ptr, float *mat) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; if (deg_iter->dupli_object_current != NULL) { copy_m4_m4((float(*)[4])mat, deg_iter->dupli_object_current->mat); } else { /* We can return actual object's matrix here, no reason to return identity matrix * when this is not actually an instance... */ - Object *ob = (Object *)iterator->current; + Object *ob = (Object *)di->iter.current; copy_m4_m4((float(*)[4])mat, ob->obmat); } } static void rna_DepsgraphObjectInstance_orco_get(PointerRNA *ptr, float *orco) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; if (deg_iter->dupli_object_current != NULL) { copy_v3_v3(orco, deg_iter->dupli_object_current->orco); } @@ -160,8 +178,8 @@ static void rna_DepsgraphObjectInstance_orco_get(PointerRNA *ptr, float *orco) static void rna_DepsgraphObjectInstance_uv_get(PointerRNA *ptr, float *uv) { - BLI_Iterator *iterator = ptr->data; - DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; if (deg_iter->dupli_object_current != NULL) { copy_v2_v2(uv, deg_iter->dupli_object_current->uv); } @@ -321,7 +339,7 @@ static PointerRNA rna_Depsgraph_objects_get(CollectionPropertyIterator *iter) * so that previous one remains valid memory for python to access to. Yuck. */ typedef struct RNA_Depsgraph_Instances_Iterator { - BLI_Iterator iterators[2]; + RNA_DepsgraphIterator iterators[2]; DEGObjectIterData deg_data[2]; DupliObject dupli_object_current[2]; int counter; @@ -337,9 +355,9 @@ static void rna_Depsgraph_object_instances_begin(CollectionPropertyIterator *ite data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_DUPLI; - di_it->iterators[0].valid = true; - DEG_iterator_objects_begin(&di_it->iterators[0], data); - iter->valid = di_it->iterators[0].valid; + di_it->iterators[0].iter.valid = true; + DEG_iterator_objects_begin(&di_it->iterators[0].iter, data); + iter->valid = di_it->iterators[0].iter.valid; } static void rna_Depsgraph_object_instances_next(CollectionPropertyIterator *iter) @@ -348,12 +366,12 @@ static void rna_Depsgraph_object_instances_next(CollectionPropertyIterator *iter iter->internal.custom; /* We need to copy current iterator status to next one being worked on. */ - di_it->iterators[(di_it->counter + 1) % 2] = di_it->iterators[di_it->counter % 2]; + di_it->iterators[(di_it->counter + 1) % 2].iter = di_it->iterators[di_it->counter % 2].iter; di_it->deg_data[(di_it->counter + 1) % 2] = di_it->deg_data[di_it->counter % 2]; di_it->counter++; - di_it->iterators[di_it->counter % 2].data = &di_it->deg_data[di_it->counter % 2]; - DEG_iterator_objects_next(&di_it->iterators[di_it->counter % 2]); + di_it->iterators[di_it->counter % 2].iter.data = &di_it->deg_data[di_it->counter % 2]; + DEG_iterator_objects_next(&di_it->iterators[di_it->counter % 2].iter); /* Dupli_object_current is also temp memory generated during the iterations, * it may be freed when last item has been iterated, * so we have same issue as with the iterator itself: @@ -365,15 +383,24 @@ static void rna_Depsgraph_object_instances_next(CollectionPropertyIterator *iter di_it->deg_data[di_it->counter % 2].dupli_object_current = &di_it->dupli_object_current[di_it->counter % 2]; } - iter->valid = di_it->iterators[di_it->counter % 2].valid; + iter->valid = di_it->iterators[di_it->counter % 2].iter.valid; } static void rna_Depsgraph_object_instances_end(CollectionPropertyIterator *iter) { RNA_Depsgraph_Instances_Iterator *di_it = (RNA_Depsgraph_Instances_Iterator *) iter->internal.custom; - DEG_iterator_objects_end(&di_it->iterators[0]); - DEG_iterator_objects_end(&di_it->iterators[1]); + for (int i = 0; i < ARRAY_SIZE(di_it->iterators); i++) { + RNA_DepsgraphIterator *di = &di_it->iterators[i]; + DEG_iterator_objects_end(&di->iter); + +# ifdef WITH_PYTHON + if (di->py_instance) { + BPY_DECREF_RNA_INVALIDATE(di->py_instance); + } +# endif + } + MEM_freeN(di_it); } @@ -381,8 +408,8 @@ static PointerRNA rna_Depsgraph_object_instances_get(CollectionPropertyIterator { RNA_Depsgraph_Instances_Iterator *di_it = (RNA_Depsgraph_Instances_Iterator *) iter->internal.custom; - BLI_Iterator *iterator = &di_it->iterators[di_it->counter % 2]; - return rna_pointer_inherit_refine(&iter->parent, &RNA_DepsgraphObjectInstance, iterator); + RNA_DepsgraphIterator *di = &di_it->iterators[di_it->counter % 2]; + return rna_pointer_inherit_refine(&iter->parent, &RNA_DepsgraphObjectInstance, di); } /* Iteration over evaluated IDs */ @@ -498,6 +525,10 @@ static void rna_def_depsgraph_instance(BlenderRNA *brna) "Extended information about dependency graph object iterator " "(Warning: All data here is 'evaluated' one, not original .blend IDs)"); +# ifdef WITH_PYTHON + RNA_def_struct_register_funcs(srna, NULL, NULL, "rna_DepsgraphIterator_instance"); +# endif + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_ui_text(prop, "Object", "Evaluated object the iterator points to"); diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 3b22ae9d40f..384ce8f04fb 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -218,16 +218,22 @@ static void rna_Fluid_parts_create(Main *bmain, # else Object *ob = (Object *)ptr->owner_id; BKE_fluid_particle_system_create(bmain, ob, pset_name, parts_name, psys_name, psys_type); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); # endif } -static void rna_Fluid_parts_delete(PointerRNA *ptr, int ptype) +static void rna_Fluid_parts_delete(Main *bmain, PointerRNA *ptr, int ptype) { # ifndef WITH_FLUID - UNUSED_VARS(ptr, ptype); + UNUSED_VARS(bmain, ptr, ptype); # else Object *ob = (Object *)ptr->owner_id; BKE_fluid_particle_system_destroy(ob, ptype); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); # endif } @@ -254,7 +260,7 @@ static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *p /* Only create a particle system in liquid domain mode. * Remove any remaining data from a liquid sim when switching to gas. */ if (fmd->domain->type != FLUID_DOMAIN_TYPE_LIQUID) { - rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FLIP); fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP; rna_Fluid_domain_data_reset(bmain, scene, ptr); return; @@ -266,7 +272,7 @@ static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *p fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FLIP; } else { - rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FLIP); fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP; } rna_Fluid_update(bmain, scene, ptr); @@ -285,7 +291,7 @@ static void rna_Fluid_spray_parts_update(Main *bmain, Scene *UNUSED(scene), Poin fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY; } else { - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAY); fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY; } } @@ -307,7 +313,7 @@ static void rna_Fluid_bubble_parts_update(Main *bmain, Scene *UNUSED(scene), Poi fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; } else { - rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_BUBBLE); fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE; } } @@ -325,7 +331,7 @@ static void rna_Fluid_foam_parts_update(Main *bmain, Scene *UNUSED(scene), Point fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; } else { - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAM); fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM; } } @@ -347,7 +353,7 @@ static void rna_Fluid_tracer_parts_update(Main *bmain, Scene *UNUSED(scene), Poi fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_TRACER; } else { - rna_Fluid_parts_delete(ptr, PART_FLUID_TRACER); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_TRACER); fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_TRACER; } } @@ -359,10 +365,10 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR fmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); if (fmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_OFF) { - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAMBUBBLE); bool exists_spray = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY); bool exists_foam = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM); @@ -392,11 +398,11 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY; fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY); - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAY); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAMBUBBLE); /* Re-add spray if enabled and no particle system exists for it anymore. */ bool exists_bubble = rna_Fluid_parts_exists(ptr, PART_FLUID_BUBBLE); @@ -418,11 +424,11 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY; fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY); - rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM); - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAY); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_BUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAMBUBBLE); /* Re-add foam if enabled and no particle system exists for it anymore. */ bool exists_foam = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM); @@ -444,11 +450,11 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM); - rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_BUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAMBUBBLE); /* Re-add foam if enabled and no particle system exists for it anymore. */ bool exists_spray = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY); @@ -472,12 +478,12 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; fmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY); - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM); - rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM); - rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE); - rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAY); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_BUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYFOAM); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_SPRAYBUBBLE); + rna_Fluid_parts_delete(bmain, ptr, PART_FLUID_FOAMBUBBLE); } } else { diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 6854ce37c94..cf0ff546d41 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1807,6 +1807,7 @@ static void rna_def_gpencil_frame(BlenderRNA *brna) /* XXX NOTE: this cannot occur on the same frame as another sketch. */ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME); RNA_def_property_ui_text(prop, "Frame Number", "The frame on which this sketch appears"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "key_type"); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 370455302b6..3d5c1810558 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -355,7 +355,7 @@ void rna_FreestyleSettings_module_remove(struct ID *id, void rna_Scene_use_view_map_cache_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr); -void rna_Scene_glsl_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr); +void rna_Scene_render_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr); void rna_Scene_freestyle_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr); void rna_ViewLayer_name_set(struct PointerRNA *ptr, const char *value); void rna_ViewLayer_material_override_update(struct Main *bmain, diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index a9e33b8cea6..9cc4b52e637 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -212,6 +212,7 @@ static void rna_def_light_energy(StructRNA *srna, const short light_type) "Power", "The energy this light would emit over its entire area " "if it wasn't limited by the spot angle"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LIGHT); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); break; } @@ -224,6 +225,7 @@ static void rna_def_light_energy(StructRNA *srna, const short light_type) prop, "Power", "Light energy emitted over the entire area of the light in all directions"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LIGHT); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); break; } diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index 4aedb1fc611..e0128595b7f 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -169,7 +169,6 @@ void RNA_def_main(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - CollectionDefFunc *func; /* plural must match idtypes in readblenentry.c */ MainCollectionDef lists[] = { @@ -467,7 +466,7 @@ void RNA_def_main(BlenderRNA *brna) RNA_def_property_ui_text(prop, lists[i].name, lists[i].description); /* collection functions */ - func = lists[i].func; + CollectionDefFunc *func = lists[i].func; if (func) { func(brna, prop); } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 4a9bc608598..252d2e657b5 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -367,13 +367,13 @@ static char *rna_GpencilColorData_path(const PointerRNA *UNUSED(ptr)) return BLI_strdup("grease_pencil"); } -static int rna_GpencilColorData_is_stroke_visible_get(PointerRNA *ptr) +static bool rna_GpencilColorData_is_stroke_visible_get(PointerRNA *ptr) { MaterialGPencilStyle *pcolor = ptr->data; return (pcolor->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH); } -static int rna_GpencilColorData_is_fill_visible_get(PointerRNA *ptr) +static bool rna_GpencilColorData_is_fill_visible_get(PointerRNA *ptr) { MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data; return ((pcolor->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (pcolor->fill_style > 0)); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 719023697b6..f1dfd2dbc21 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -483,8 +483,8 @@ static void rna_MEdge_crease_set(PointerRNA *ptr, float value) static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values) { Mesh *me = rna_mesh(ptr); - MLoop *ml = (MLoop *)ptr->data; - const float(*vec)[3] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_NORMAL); + const int index = rna_MeshLoop_index_get(ptr); + const float(*vec)[3] = CustomData_get(&me->ldata, index, CD_NORMAL); if (!vec) { zero_v3(values); @@ -497,8 +497,8 @@ static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values) static void rna_MeshLoop_normal_set(PointerRNA *ptr, const float *values) { Mesh *me = rna_mesh(ptr); - MLoop *ml = (MLoop *)ptr->data; - float(*vec)[3] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_NORMAL); + const int index = rna_MeshLoop_index_get(ptr); + float(*vec)[3] = CustomData_get(&me->ldata, index, CD_NORMAL); if (vec) { normalize_v3_v3(*vec, values); @@ -508,8 +508,8 @@ static void rna_MeshLoop_normal_set(PointerRNA *ptr, const float *values) static void rna_MeshLoop_tangent_get(PointerRNA *ptr, float *values) { Mesh *me = rna_mesh(ptr); - MLoop *ml = (MLoop *)ptr->data; - const float(*vec)[4] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_MLOOPTANGENT); + const int index = rna_MeshLoop_index_get(ptr); + const float(*vec)[4] = CustomData_get(&me->ldata, index, CD_MLOOPTANGENT); if (!vec) { zero_v3(values); @@ -522,8 +522,8 @@ static void rna_MeshLoop_tangent_get(PointerRNA *ptr, float *values) static float rna_MeshLoop_bitangent_sign_get(PointerRNA *ptr) { Mesh *me = rna_mesh(ptr); - MLoop *ml = (MLoop *)ptr->data; - const float(*vec)[4] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_MLOOPTANGENT); + const int index = rna_MeshLoop_index_get(ptr); + const float(*vec)[4] = CustomData_get(&me->ldata, index, CD_MLOOPTANGENT); return (vec) ? (*vec)[3] : 0.0f; } @@ -531,9 +531,9 @@ static float rna_MeshLoop_bitangent_sign_get(PointerRNA *ptr) static void rna_MeshLoop_bitangent_get(PointerRNA *ptr, float *values) { Mesh *me = rna_mesh(ptr); - MLoop *ml = (MLoop *)ptr->data; - const float(*nor)[3] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_NORMAL); - const float(*vec)[4] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_MLOOPTANGENT); + const int index = rna_MeshLoop_index_get(ptr); + const float(*nor)[3] = CustomData_get(&me->ldata, index, CD_NORMAL); + const float(*vec)[4] = CustomData_get(&me->ldata, index, CD_MLOOPTANGENT); if (nor && vec) { cross_v3_v3v3(values, (const float *)nor, (const float *)vec); @@ -702,8 +702,8 @@ static void rna_MeshVertex_groups_begin(CollectionPropertyIterator *iter, Pointe Mesh *me = rna_mesh(ptr); if (me->dvert) { - MVert *mvert = (MVert *)ptr->data; - MDeformVert *dvert = me->dvert + (mvert - me->mvert); + const int index = rna_MeshVertex_index_get(ptr); + MDeformVert *dvert = &me->dvert[index]; rna_iterator_array_begin( iter, (void *)dvert->dw, sizeof(MDeformWeight), dvert->totweight, 0, NULL); @@ -720,11 +720,12 @@ static void rna_MeshVertex_undeformed_co_get(PointerRNA *ptr, float values[3]) const float(*orco)[3] = CustomData_get_layer(&me->vdata, CD_ORCO); if (orco) { + const int index = rna_MeshVertex_index_get(ptr); /* orco is normalized to 0..1, we do inverse to match mvert->co */ float loc[3], size[3]; BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size); - madd_v3_v3v3v3(values, loc, orco[(mvert - me->mvert)], size); + madd_v3_v3v3v3(values, loc, orco[index], size); } else { copy_v3_v3(values, mvert->co); @@ -784,9 +785,8 @@ static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, CustomData *data, int static bool rna_MEdge_freestyle_edge_mark_get(PointerRNA *ptr) { const Mesh *me = rna_mesh(ptr); - const MEdge *medge = (MEdge *)ptr->data; - const FreestyleEdge *fed = CustomData_get( - &me->edata, (int)(medge - me->medge), CD_FREESTYLE_EDGE); + const int index = rna_MeshEdge_index_get(ptr); + const FreestyleEdge *fed = CustomData_get(&me->edata, index, CD_FREESTYLE_EDGE); return fed && (fed->flag & FREESTYLE_EDGE_MARK) != 0; } @@ -794,8 +794,8 @@ static bool rna_MEdge_freestyle_edge_mark_get(PointerRNA *ptr) static void rna_MEdge_freestyle_edge_mark_set(PointerRNA *ptr, bool value) { Mesh *me = rna_mesh(ptr); - MEdge *medge = (MEdge *)ptr->data; - FreestyleEdge *fed = CustomData_get(&me->edata, (int)(medge - me->medge), CD_FREESTYLE_EDGE); + const int index = rna_MeshEdge_index_get(ptr); + FreestyleEdge *fed = CustomData_get(&me->edata, index, CD_FREESTYLE_EDGE); if (!fed) { fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_CALLOC, NULL, me->totedge); @@ -811,18 +811,17 @@ static void rna_MEdge_freestyle_edge_mark_set(PointerRNA *ptr, bool value) static bool rna_MPoly_freestyle_face_mark_get(PointerRNA *ptr) { const Mesh *me = rna_mesh(ptr); - const MPoly *mpoly = (MPoly *)ptr->data; - const FreestyleFace *ffa = CustomData_get( - &me->pdata, (int)(mpoly - me->mpoly), CD_FREESTYLE_FACE); + const int index = rna_MeshPolygon_index_get(ptr); + const FreestyleFace *ffa = CustomData_get(&me->pdata, index, CD_FREESTYLE_FACE); return ffa && (ffa->flag & FREESTYLE_FACE_MARK) != 0; } -static void rna_MPoly_freestyle_face_mark_set(PointerRNA *ptr, int value) +static void rna_MPoly_freestyle_face_mark_set(PointerRNA *ptr, bool value) { Mesh *me = rna_mesh(ptr); - MPoly *mpoly = (MPoly *)ptr->data; - FreestyleFace *ffa = CustomData_get(&me->pdata, (int)(mpoly - me->mpoly), CD_FREESTYLE_FACE); + const int index = rna_MeshPolygon_index_get(ptr); + FreestyleFace *ffa = CustomData_get(&me->pdata, index, CD_FREESTYLE_FACE); if (!ffa) { ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_CALLOC, NULL, me->totpoly); @@ -1350,7 +1349,7 @@ static char *rna_VertexGroupElement_path(const PointerRNA *ptr) static char *rna_MeshPolygon_path(const PointerRNA *ptr) { - return BLI_sprintfN("polygons[%d]", (int)((MPoly *)ptr->data - rna_mesh(ptr)->mpoly)); + return BLI_sprintfN("polygons[%d]", rna_MeshPolygon_index_get((PointerRNA *)ptr)); } static char *rna_MeshLoopTriangle_path(const PointerRNA *ptr) @@ -1361,17 +1360,17 @@ static char *rna_MeshLoopTriangle_path(const PointerRNA *ptr) static char *rna_MeshEdge_path(const PointerRNA *ptr) { - return BLI_sprintfN("edges[%d]", (int)((MEdge *)ptr->data - rna_mesh(ptr)->medge)); + return BLI_sprintfN("edges[%d]", rna_MeshEdge_index_get((PointerRNA *)ptr)); } static char *rna_MeshLoop_path(const PointerRNA *ptr) { - return BLI_sprintfN("loops[%d]", (int)((MLoop *)ptr->data - rna_mesh(ptr)->mloop)); + return BLI_sprintfN("loops[%d]", rna_MeshLoop_index_get((PointerRNA *)ptr)); } static char *rna_MeshVertex_path(const PointerRNA *ptr) { - return BLI_sprintfN("vertices[%d]", (int)((MVert *)ptr->data - rna_mesh(ptr)->mvert)); + return BLI_sprintfN("vertices[%d]", rna_MeshVertex_index_get((PointerRNA *)ptr)); } static char *rna_VertCustomData_data_path(const PointerRNA *ptr, const char *collection, int type) diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c index 6595c811abc..1f8748143e3 100644 --- a/source/blender/makesrna/intern/rna_meta_api.c +++ b/source/blender/makesrna/intern/rna_meta_api.c @@ -28,7 +28,7 @@ static void rna_Meta_transform(struct MetaBall *mb, float mat[16]) static void rna_Mball_update_gpu_tag(MetaBall *mb) { - BKE_mball_batch_cache_dirty_tag(mb, BKE_MBALL_BATCH_DIRTY_ALL); + DEG_id_tag_update(&mb->id, ID_RECALC_SHADING); } #else diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 7d2fa8022dd..0909621d70c 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1267,6 +1267,20 @@ static void rna_NodeTree_active_node_set(PointerRNA *ptr, if (node && BLI_findindex(&ntree->nodes, node) != -1) { nodeSetActive(ntree, node); + + /* Handle NODE_DO_OUTPUT as well. */ + if (node->typeinfo->nclass == NODE_CLASS_OUTPUT && node->type != CMP_NODE_OUTPUT_FILE) { + /* If this node becomes the active output, the others of the same type can't be the active + * output anymore. */ + LISTBASE_FOREACH (bNode *, other_node, &ntree->nodes) { + if (other_node->type == node->type) { + other_node->flag &= ~NODE_DO_OUTPUT; + } + } + node->flag |= NODE_DO_OUTPUT; + ntreeSetOutput(ntree); + BKE_ntree_update_tag_active_output_changed(ntree); + } } else { nodeClearActive(ntree); @@ -4840,6 +4854,7 @@ static void def_math(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_math_items); RNA_def_property_ui_text(prop, "Operation", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_NODETREE); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE); @@ -6737,7 +6752,7 @@ static void def_cmp_set_alpha(StructRNA *srna) "REPLACE_ALPHA", 0, "Replace Alpha", - "Replace the input image's alpha channels by the alpha input value"}, + "Replace the input image's alpha channel by the alpha input value"}, {0, NULL, 0, NULL, NULL}, }; @@ -12399,7 +12414,7 @@ static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop) prop, "rna_NodeTree_active_node_get", "rna_NodeTree_active_node_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); RNA_def_property_ui_text(prop, "Active Node", "Active node in this tree"); - RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, "rna_NodeTree_update"); } static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 103c77fa808..6cbc24db2d8 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -687,6 +687,11 @@ static void rna_Object_parent_type_set(PointerRNA *ptr, int value) { Object *ob = (Object *)ptr->data; + /* Skip if type did not change (otherwise we loose parent inverse in ED_object_parent). */ + if (ob->partype == value) { + return; + } + ED_object_parent(ob, ob->parent, value, ob->parsubstr); } @@ -2224,7 +2229,7 @@ bool rna_GPencil_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value) return ((Object *)value.owner_id)->type == OB_GPENCIL; } -int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr) +bool rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr) { SculptSession *ss = ((Object *)ptr->owner_id)->sculpt; return (ss && ss->bm); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 2ed539aa511..40000a49f03 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1276,7 +1276,7 @@ static void rna_def_effector_weight(BlenderRNA *brna) prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Collection"); RNA_def_property_pointer_sdna(prop, NULL, "group"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection"); RNA_def_property_update(prop, 0, "rna_EffectorWeight_dependency_update"); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 3fc98d769b6..e4bddd1f3c7 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1044,7 +1044,7 @@ static float rna_PartSetting_linelenhead_get(struct PointerRNA *ptr) return settings->draw_line[1]; } -static int rna_PartSettings_is_fluid_get(PointerRNA *ptr) +static bool rna_PartSettings_is_fluid_get(PointerRNA *ptr) { ParticleSettings *part = ptr->data; return (ELEM(part->type, @@ -2686,6 +2686,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_parent_particles", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_PARENT); RNA_def_property_ui_text(prop, "Parents", "Render parent particles"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_PARTICLESETTINGS); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "show_number", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_path.cc b/source/blender/makesrna/intern/rna_path.cc index f14e2113e13..99cb456027f 100644 --- a/source/blender/makesrna/intern/rna_path.cc +++ b/source/blender/makesrna/intern/rna_path.cc @@ -704,12 +704,16 @@ 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. */ - int64_t rna_path_len = (int64_t)strlen(rna_path); + if (UNLIKELY(rna_path[0] == '\0')) { + return NULL; + } + size_t rna_path_len = (size_t)strlen(rna_path) - 1; if (rna_path[rna_path_len] != ']') { return NULL; } + const char *last_valid_index_token_start = NULL; - for (rna_path_len--; rna_path_len >= 0; rna_path_len--) { + while (rna_path_len--) { switch (rna_path[rna_path_len]) { case '[': if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') { diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 0c1fd8cab3c..7a499d10d3a 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -865,7 +865,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna) prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Collection"); RNA_def_property_pointer_sdna(prop, NULL, "group"); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Collection", "Collection containing objects participating in this simulation"); @@ -873,7 +873,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna) prop = RNA_def_property(srna, "constraints", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Collection"); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Constraints", "Collection containing rigid body constraint objects"); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 16a4dfe71cf..fd1879b3df7 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1145,7 +1145,7 @@ static bool rna_Function_no_self_get(PointerRNA *ptr) return !(func->flag & FUNC_NO_SELF); } -static int rna_Function_use_self_type_get(PointerRNA *ptr) +static bool rna_Function_use_self_type_get(PointerRNA *ptr) { FunctionRNA *func = (FunctionRNA *)ptr->data; return 0 != (func->flag & FUNC_USE_SELF_TYPE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 2e78cc97099..be387efea93 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -88,6 +88,11 @@ static const EnumPropertyItem uv_sculpt_relaxation_items[] = { "Laplacian", "Use Laplacian method for relaxation"}, {UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"}, + {UV_SCULPT_TOOL_RELAX_COTAN, + "COTAN", + 0, + "Geometry", + "Use Geometry (cotangent) relaxation, making UV's follow the underlying 3D geometry"}, {0, NULL, 0, NULL, NULL}, }; #endif @@ -848,12 +853,12 @@ void rna_Scene_set_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) Scene *scene = (Scene *)ptr->owner_id; DEG_relations_tag_update(bmain); - DEG_id_tag_update_ex(bmain, &scene->id, 0); + DEG_id_tag_update_ex(bmain, &scene->id, ID_RECALC_BASE_FLAGS); if (scene->set != NULL) { /* Objects which are pulled into main scene's depsgraph needs to have * their base flags updated. */ - DEG_id_tag_update_ex(bmain, &scene->set->id, 0); + DEG_id_tag_update_ex(bmain, &scene->set->id, ID_RECALC_BASE_FLAGS); } } @@ -1675,18 +1680,18 @@ static bool rna_RenderSettings_use_spherical_stereo_get(PointerRNA *ptr) return BKE_scene_use_spherical_stereo(scene); } -void rna_Scene_glsl_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +void rna_Scene_render_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); } static void rna_Scene_world_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Scene *screen = (Scene *)ptr->owner_id; - rna_Scene_glsl_update(bmain, scene, ptr); + rna_Scene_render_update(bmain, scene, ptr); WM_main_add_notifier(NC_WORLD | ND_WORLD, &screen->id); DEG_relations_tag_update(bmain); } @@ -1702,21 +1707,21 @@ static void rna_Scene_mesh_quality_update(Main *bmain, Scene *UNUSED(scene), Poi } FOREACH_SCENE_OBJECT_END; - rna_Scene_glsl_update(bmain, scene, ptr); + rna_Scene_render_update(bmain, scene, ptr); } void rna_Scene_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); } void rna_Scene_use_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); if (scene->nodetree) { ntreeCompositUpdateRLayers(scene->nodetree); @@ -1756,7 +1761,7 @@ static void rna_SceneRenderView_name_set(PointerRNA *ptr, const char *value) void rna_ViewLayer_material_override_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - rna_Scene_glsl_update(bmain, scene, ptr); + rna_Scene_render_update(bmain, scene, ptr); DEG_relations_tag_update(bmain); } @@ -1793,7 +1798,7 @@ void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr) } } - rna_Scene_glsl_update(bmain, activescene, ptr); + rna_Scene_render_update(bmain, activescene, ptr); } static char *rna_ViewLayerEEVEE_path(const PointerRNA *ptr) @@ -1950,7 +1955,7 @@ static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), Poi WM_main_add_notifier(NC_GEOM | ND_DATA, NULL); WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); - DEG_id_tag_update(&sce->id, 0); + DEG_id_tag_update(&sce->id, ID_RECALC_COPY_ON_WRITE); } static void rna_Scene_simplify_update(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -2303,7 +2308,7 @@ FreestyleLineSet *rna_FreestyleSettings_lineset_add(ID *id, Scene *scene = (Scene *)id; FreestyleLineSet *lineset = BKE_freestyle_lineset_add(bmain, (FreestyleConfig *)config, name); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL); return lineset; @@ -2324,7 +2329,7 @@ void rna_FreestyleSettings_lineset_remove(ID *id, RNA_POINTER_INVALIDATE(lineset_ptr); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL); } @@ -2361,7 +2366,7 @@ FreestyleModuleConfig *rna_FreestyleSettings_module_add(ID *id, FreestyleSetting Scene *scene = (Scene *)id; FreestyleModuleConfig *module = BKE_freestyle_module_add((FreestyleConfig *)config); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL); return module; @@ -2390,7 +2395,7 @@ void rna_FreestyleSettings_module_remove(ID *id, RNA_POINTER_INVALIDATE(module_ptr); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL); } @@ -2421,7 +2426,7 @@ static ViewLayer *rna_ViewLayer_new(ID *id, Scene *UNUSED(sce), Main *bmain, con Scene *scene = (Scene *)id; ViewLayer *view_layer = BKE_view_layer_add(scene, name, NULL, VIEWLAYER_ADD_NEW); - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); @@ -2728,7 +2733,11 @@ static void rna_FFmpegSettings_codec_update(Main *UNUSED(bmain), PointerRNA *ptr) { FFMpegCodecData *codec_data = (FFMpegCodecData *)ptr->data; - if (!ELEM(codec_data->codec, AV_CODEC_ID_H264, AV_CODEC_ID_MPEG4, AV_CODEC_ID_VP9)) { + if (!ELEM(codec_data->codec, + AV_CODEC_ID_H264, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_VP9, + AV_CODEC_ID_DNXHD)) { /* Constant Rate Factor (CRF) setting is only available for H264, * MPEG4 and WEBM/VP9 codecs. So changing encoder quality mode to * CBR as CRF is not supported. @@ -3134,6 +3143,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "workspace_tool_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "workspace_tool_type"); RNA_def_property_enum_items(prop, workspace_tool_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_EDITOR_VIEW3D); RNA_def_property_ui_text(prop, "Drag", "Action when dragging in the viewport"); /* Transform */ @@ -4457,7 +4467,7 @@ void rna_def_view_layer_common(BlenderRNA *brna, StructRNA *srna, const bool sce RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_SKY); RNA_def_property_ui_text(prop, "Sky", "Render Sky in this Layer"); if (scene) { - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update"); } else { RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -4467,7 +4477,7 @@ void rna_def_view_layer_common(BlenderRNA *brna, StructRNA *srna, const bool sce RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_AO); RNA_def_property_ui_text(prop, "Ambient Occlusion", "Render Ambient Occlusion in this Layer"); if (scene) { - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update"); } else { RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -6344,7 +6354,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop, "Transparent", "World background is transparent, for compositing the render over another background"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update"); prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -6375,14 +6385,14 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "mode", R_MBLUR); RNA_def_property_ui_text(prop, "Motion Blur", "Use multi-sampled 3D scene motion blur"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update"); prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "blurfac"); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0.01f, 1.0f, 1, 2); RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update"); prop = RNA_def_property(srna, "motion_blur_shutter_curve", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "mblur_shutter_curve"); @@ -6394,13 +6404,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "hair_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, hair_shape_type_items); RNA_def_property_ui_text(prop, "Curves Shape Type", "Curves shape type"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update"); prop = RNA_def_property(srna, "hair_subdiv", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 0, 3); RNA_def_property_ui_text( prop, "Additional Subdivision", "Additional subdivision along the curves"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update"); /* Performance */ prop = RNA_def_property(srna, "use_high_quality_normals", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 3bcd9cd0441..aa40ee846bf 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -324,7 +324,7 @@ static int rna_Sequence_frame_final_end_get(PointerRNA *ptr) return SEQ_time_right_handle_frame_get(scene, (Sequence *)ptr->data); } -static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, float value) +static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; @@ -346,7 +346,7 @@ static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value) SEQ_relations_invalidate_cache_composite(scene, seq); } -static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value) +static void rna_Sequence_start_frame_set(PointerRNA *ptr, float value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index aab6174cab2..ae241c11522 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -63,7 +63,7 @@ static void rna_Sequence_swap_internal(ID *id, const char *error_msg; Scene *scene = (Scene *)id; - if (SEQ_edit_sequence_swap(scene, seq_self, seq_other, &error_msg) == 0) { + if (SEQ_edit_sequence_swap(scene, seq_self, seq_other, &error_msg) == false) { BKE_report(reports, RPT_ERROR, error_msg); } } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 502b0404764..65f5447f16a 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -88,7 +88,7 @@ const EnumPropertyItem rna_enum_space_type_items[] = { {SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""}, /* General. */ - RNA_ENUM_ITEM_HEADING("General", NULL), + RNA_ENUM_ITEM_HEADING(N_("General"), NULL), {SPACE_VIEW3D, "VIEW_3D", ICON_VIEW3D, @@ -108,7 +108,7 @@ const EnumPropertyItem rna_enum_space_type_items[] = { {SPACE_CLIP, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", "Motion tracking tools"}, /* Animation. */ - RNA_ENUM_ITEM_HEADING("Animation", NULL), + RNA_ENUM_ITEM_HEADING(N_("Animation"), NULL), #if 0 {SPACE_ACTION, "TIMELINE", @@ -125,7 +125,7 @@ const EnumPropertyItem rna_enum_space_type_items[] = { {SPACE_NLA, "NLA_EDITOR", ICON_NLA, "Nonlinear Animation", "Combine and layer Actions"}, /* Scripting. */ - RNA_ENUM_ITEM_HEADING("Scripting", NULL), + RNA_ENUM_ITEM_HEADING(N_("Scripting"), NULL), {SPACE_TEXT, "TEXT_EDITOR", ICON_TEXT, @@ -153,7 +153,7 @@ const EnumPropertyItem rna_enum_space_type_items[] = { "screen for general status information"}, /* Data. */ - RNA_ENUM_ITEM_HEADING("Data", NULL), + RNA_ENUM_ITEM_HEADING(N_("Data"), NULL), {SPACE_OUTLINER, "OUTLINER", ICON_OUTLINER, @@ -435,28 +435,28 @@ static const EnumPropertyItem rna_enum_studio_light_items[] = { }; static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] = { - RNA_ENUM_ITEM_HEADING("General", NULL), + RNA_ENUM_ITEM_HEADING(N_("General"), NULL), {EEVEE_RENDER_PASS_COMBINED, "COMBINED", 0, "Combined", ""}, {EEVEE_RENDER_PASS_EMIT, "EMISSION", 0, "Emission", ""}, {EEVEE_RENDER_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""}, {EEVEE_RENDER_PASS_AO, "AO", 0, "Ambient Occlusion", ""}, {EEVEE_RENDER_PASS_SHADOW, "SHADOW", 0, "Shadow", ""}, - RNA_ENUM_ITEM_HEADING("Light", NULL), + RNA_ENUM_ITEM_HEADING(N_("Light"), NULL), {EEVEE_RENDER_PASS_DIFFUSE_LIGHT, "DIFFUSE_LIGHT", 0, "Diffuse Light", ""}, {EEVEE_RENDER_PASS_DIFFUSE_COLOR, "DIFFUSE_COLOR", 0, "Diffuse Color", ""}, {EEVEE_RENDER_PASS_SPECULAR_LIGHT, "SPECULAR_LIGHT", 0, "Specular Light", ""}, {EEVEE_RENDER_PASS_SPECULAR_COLOR, "SPECULAR_COLOR", 0, "Specular Color", ""}, {EEVEE_RENDER_PASS_VOLUME_LIGHT, "VOLUME_LIGHT", 0, "Volume Light", ""}, - RNA_ENUM_ITEM_HEADING("Effects", NULL), + RNA_ENUM_ITEM_HEADING(N_("Effects"), NULL), {EEVEE_RENDER_PASS_BLOOM, "BLOOM", 0, "Bloom", ""}, - RNA_ENUM_ITEM_HEADING("Data", NULL), + RNA_ENUM_ITEM_HEADING(N_("Data"), NULL), {EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""}, {EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""}, - RNA_ENUM_ITEM_HEADING("Shader AOV", NULL), + RNA_ENUM_ITEM_HEADING(N_("Shader AOV"), NULL), {EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""}, {0, NULL, 0, NULL, NULL}, @@ -1100,7 +1100,7 @@ static bool rna_RegionView3D_is_orthographic_side_view_get(PointerRNA *ptr) return RV3D_VIEW_IS_AXIS(rv3d->view); } -static void rna_RegionView3D_is_orthographic_side_view_set(PointerRNA *ptr, int value) +static void rna_RegionView3D_is_orthographic_side_view_set(PointerRNA *ptr, bool value) { RegionView3D *rv3d = (RegionView3D *)(ptr->data); const bool was_axis_view = RV3D_VIEW_IS_AXIS(rv3d->view); @@ -1609,7 +1609,7 @@ static void rna_SpaceImageEditor_mode_update(Main *bmain, Scene *scene, PointerR } } -static void rna_SpaceImageEditor_show_stereo_set(PointerRNA *ptr, int value) +static void rna_SpaceImageEditor_show_stereo_set(PointerRNA *ptr, bool value) { SpaceImage *sima = (SpaceImage *)(ptr->data); @@ -5909,7 +5909,7 @@ static void rna_def_space_text(BlenderRNA *brna) prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "lheight"); - RNA_def_property_range(prop, 8, 32); + RNA_def_property_range(prop, 1, 256); /* Large range since Hi-DPI scales down size. */ RNA_def_property_ui_text(prop, "Font Size", "Font size to use for displaying the text"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL); @@ -6403,7 +6403,7 @@ static void rna_def_space_console(BlenderRNA *brna) /* display */ prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_NONE); /* copied from text editor */ RNA_def_property_int_sdna(prop, NULL, "lheight"); - RNA_def_property_range(prop, 8, 32); + RNA_def_property_range(prop, 1, 256); /* Large range since Hi-DPI scales down size. */ RNA_def_property_ui_text(prop, "Font Size", "Font size to use for displaying the text"); RNA_def_property_update(prop, 0, "rna_SpaceConsole_rect_update"); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index adb959944b5..9de32c24702 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -440,7 +440,7 @@ static PointerRNA rna_Panel_custom_data_get(PointerRNA *ptr) } /* UIList */ -static unsigned int rna_UIList_filter_const_FILTER_ITEM_get(PointerRNA *UNUSED(ptr)) +static int rna_UIList_filter_const_FILTER_ITEM_get(PointerRNA *UNUSED(ptr)) { return UILST_FLT_ITEM; } diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 438bac9b458..61e6ba892bc 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5565,8 +5565,8 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text( prop, "VBO Time Out", - "Time since last access of a GL Vertex buffer object in seconds after which it is freed " - "(set to 0 to keep vbo allocated)"); + "Time since last access of a GL vertex buffer object in seconds after which it is freed " + "(set to 0 to keep VBO allocated)"); prop = RNA_def_property(srna, "vbo_collection_rate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "vbocollectrate"); @@ -5574,7 +5574,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text( prop, "VBO Collection Rate", - "Number of seconds between each run of the GL Vertex buffer object garbage collector"); + "Number of seconds between each run of the GL vertex buffer object garbage collector"); /* Select */ @@ -6301,15 +6301,6 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "Enable library overrides automatic resync detection and process on file load. Disable when " "dealing with older .blend files that need manual Resync (Enforce) handling"); - prop = RNA_def_property(srna, "use_override_new_fully_editable", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "use_override_new_fully_editable", 1); - RNA_def_property_ui_text( - prop, - "Override New Fully Editable", - "Make all override of a hierarchy fully user-editable by default when creating a new " - "override (if that option is disabled, most overrides created as part of a hierarchy will " - "not be editable by the user by default)"); - prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index 4247b830efa..a4630415ccd 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -353,7 +353,7 @@ static PointerRNA rna_Gizmo_properties_get(PointerRNA *ptr) } # define RNA_GIZMO_FLAG_RO_DEF(func_id, member_id, flag_value) \ - static int rna_Gizmo_##func_id##_get(PointerRNA *ptr) \ + static bool rna_Gizmo_##func_id##_get(PointerRNA *ptr) \ { \ wmGizmo *gz = ptr->data; \ return (gz->member_id & flag_value) != 0; \ diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index a0d89b8b15a..2294c2c2b2d 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -193,7 +193,7 @@ static int rna_WorkSpaceTool_index_get(PointerRNA *ptr) return (tref->runtime) ? tref->runtime->index : 0; } -static int rna_WorkSpaceTool_has_datablock_get(PointerRNA *ptr) +static bool rna_WorkSpaceTool_has_datablock_get(PointerRNA *ptr) { bToolRef *tref = ptr->data; return (tref->runtime) ? (tref->runtime->data_block[0] != '\0') : false; diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 11bbe8dc83e..6c5baabe756 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -254,7 +254,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u } if (clmd->sim_parms && clmd->sim_parms->effector_weights) { - walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_CB_USER); } } diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 7cd6b829d37..7590318c52b 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -211,7 +211,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * dtmd->defgrp_name, invert_vgroup, &reports)) { - result->runtime.is_original = false; + result->runtime.is_original_bmesh = false; } if (BKE_reports_contain(&reports, RPT_ERROR)) { diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 4afb81c04a9..c23367f9b9b 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -158,7 +158,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u walk(userData, ob, (ID **)&surface->brush_group, IDWALK_CB_NOP); walk(userData, ob, (ID **)&surface->init_texture, IDWALK_CB_USER); if (surface->effector_weights) { - walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_CB_USER); } } } diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c index a3e9cd083d2..3ab6d08ee15 100644 --- a/source/blender/modifiers/intern/MOD_fluid.c +++ b/source/blender/modifiers/intern/MOD_fluid.c @@ -215,7 +215,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u } if (fmd->domain->effector_weights) { - walk(userData, ob, (ID **)&fmd->domain->effector_weights->group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&fmd->domain->effector_weights->group, IDWALK_CB_USER); } } diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.h b/source/blender/modifiers/intern/MOD_meshcache_util.h index 276bdf72bc3..2726f2d7efb 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_util.h +++ b/source/blender/modifiers/intern/MOD_meshcache_util.h @@ -8,12 +8,8 @@ /* MOD_meshcache_mdd.c */ -bool MOD_meshcache_read_mdd_index(FILE *fp, - float (*vertexCos)[3], - int vertex_tot, - int index, - float factor, - const char **err_str); +bool MOD_meshcache_read_mdd_index( + FILE *fp, float (*vertexCos)[3], int verts_tot, int index, float factor, const char **err_str); bool MOD_meshcache_read_mdd_frame(FILE *fp, float (*vertexCos)[3], int verts_tot, diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 94b48f65a66..5a92aac6cda 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -616,7 +616,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, MEM_SAFE_FREE(loopnors); - result->runtime.is_original = false; + result->runtime.is_original_bmesh = false; return result; } diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c index 56dd1fc50f8..3649a108ed4 100644 --- a/source/blender/modifiers/intern/MOD_shapekey.c +++ b/source/blender/modifiers/intern/MOD_shapekey.c @@ -49,11 +49,11 @@ static void deformMatrices(ModifierData *md, { Key *key = BKE_key_from_object(ctx->object); KeyBlock *kb = BKE_keyblock_from_object(ctx->object); - float scale[3][3]; (void)vertexCos; /* unused */ if (kb && kb->totelem == verts_num && kb != key->refkey) { + float scale[3][3]; int a; if (ctx->object->shapeflag & OB_SHAPE_LOCK) { @@ -95,15 +95,14 @@ static void deformMatricesEM(ModifierData *UNUSED(md), { Key *key = BKE_key_from_object(ctx->object); KeyBlock *kb = BKE_keyblock_from_object(ctx->object); - float scale[3][3]; (void)vertexCos; /* unused */ if (kb && kb->totelem == verts_num && kb != key->refkey) { - int a; + float scale[3][3]; scale_m3_fl(scale, kb->curval); - for (a = 0; a < verts_num; a++) { + for (int a = 0; a < verts_num; a++) { copy_m3_m3(defMats[a], scale); } } diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 3c0842a6e93..96e761e86b6 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1602,6 +1602,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, verts_num, false); } + /* TODO(@campbellbarton): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + surfacedeformModifier_do(md, ctx, vertexCos, verts_num, ctx->object, mesh_src); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index a318a82fe64..4646ba41a74 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -284,7 +284,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, } } - mesh->runtime.is_original = false; + mesh->runtime.is_original_bmesh = false; return mesh; } diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index 4178f1dd33e..0439f92ac57 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -220,7 +220,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * settings.use_threading = (polys_num > 1000); BLI_task_parallel_range(0, polys_num, &data, uv_warp_compute, &settings); - mesh->runtime.is_original = false; + mesh->runtime.is_original_bmesh = false; return mesh; } diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index af992c00097..039497b725b 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -660,7 +660,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_SAFE_FREE(wn_data.mode_pair); MEM_SAFE_FREE(wn_data.items_data); - result->runtime.is_original = false; + result->runtime.is_original_bmesh = false; return result; } diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 8ccf140e665..2a509ddf220 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -287,7 +287,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_freeN(new_w); MEM_freeN(dw); - mesh->runtime.is_original = false; + mesh->runtime.is_original_bmesh = false; /* Return the vgroup-modified mesh. */ return mesh; diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 701e30fbf57..aa648eaec97 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -444,7 +444,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_freeN(dw2); MEM_SAFE_FREE(indices); - mesh->runtime.is_original = false; + mesh->runtime.is_original_bmesh = false; /* Return the vgroup-modified mesh. */ return mesh; diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 70838bc5c4f..df2b494199e 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -640,7 +640,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * TIMEIT_END(perf); #endif - mesh->runtime.is_original = false; + mesh->runtime.is_original_bmesh = false; /* Return the vgroup-modified mesh. */ return mesh; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 386e5fe14c9..ae31fd7ff5f 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -29,7 +29,6 @@ set(INC ../makesrna ../render ../windowmanager - ../../../intern/glew-mx ../../../intern/guardedalloc # dna_type_offsets.h diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc index 66a321eb088..5aa810b61bb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc @@ -5,10 +5,15 @@ * \ingroup cmpnodes */ +#include "BLI_math_base.hh" + #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -18,8 +23,12 @@ namespace blender::nodes::node_composite_bilateralblur_cc { static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); - b.add_input<decl::Color>(N_("Determinator")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); + b.add_input<decl::Color>(N_("Determinator")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(1); b.add_output<decl::Color>(N_("Image")); } @@ -52,7 +61,51 @@ class BilateralBlurOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); + const Result &input_image = get_input("Image"); + /* Single value inputs can't be blurred and are returned as is. */ + if (input_image.is_single_value()) { + get_input("Image").pass_through(get_result("Image")); + return; + } + + GPUShader *shader = shader_manager().get("compositor_bilateral_blur"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1i(shader, "radius", get_blur_radius()); + GPU_shader_uniform_1f(shader, "threshold", get_threshold()); + + input_image.bind_as_texture(shader, "input_tx"); + + const Result &determinator_image = get_input("Determinator"); + determinator_image.bind_as_texture(shader, "determinator_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + determinator_image.unbind_as_texture(); + } + + int get_blur_radius() + { + return math::ceil(get_node_bilateral_blur_data().iter + + get_node_bilateral_blur_data().sigma_space); + } + + float get_threshold() + { + return get_node_bilateral_blur_data().sigma_color; + } + + NodeBilateralBlurData &get_node_bilateral_blur_data() + { + return *static_cast<NodeBilateralBlurData *>(bnode().storage); } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc index a11cba37191..13c3b793148 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc @@ -5,10 +5,16 @@ * \ingroup cmpnodes */ +#include "BLI_math_base.h" +#include "BLI_math_vec_types.hh" + #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -55,7 +61,50 @@ class BokehImageOperation : public NodeOperation { void execute() override { - get_result("Image").allocate_invalid(); + GPUShader *shader = shader_manager().get("compositor_bokeh_image"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "exterior_angle", get_exterior_angle()); + GPU_shader_uniform_1f(shader, "rotation", get_rotation()); + GPU_shader_uniform_1f(shader, "roundness", get_node_bokeh_image().rounding); + GPU_shader_uniform_1f(shader, "catadioptric", get_node_bokeh_image().catadioptric); + GPU_shader_uniform_1f(shader, "lens_shift", get_node_bokeh_image().lensshift); + + Result &output = get_result("Image"); + const Domain domain = compute_domain(); + output.allocate_texture(domain); + output.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + output.unbind_as_image(); + GPU_shader_unbind(); + } + + Domain compute_domain() override + { + return Domain(int2(512)); + } + + NodeBokehImage &get_node_bokeh_image() + { + return *static_cast<NodeBokehImage *>(bnode().storage); + } + + /* The exterior angle is the angle between each two consecutive vertices of the regular polygon + * from its center. */ + float get_exterior_angle() + { + return (M_PI * 2.0f) / get_node_bokeh_image().flaps; + } + + float get_rotation() + { + /* Offset the rotation such that the second vertex of the regular polygon lies on the positive + * y axis, which is 90 degrees minus the angle that it makes with the positive x axis assuming + * the first vertex lies on the positive x axis. */ + const float offset = M_PI_2 - get_exterior_angle(); + return get_node_bokeh_image().angle - offset; } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc index 0b9f9c8f76d..aa6725b8750 100644 --- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc +++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc @@ -8,7 +8,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -18,8 +21,15 @@ namespace blender::nodes::node_composite_despeckle_cc { static void cmp_node_despeckle_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Fac")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR) + .compositor_domain_priority(1); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); } @@ -46,7 +56,45 @@ class DespeckleOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); + const Result &input_image = get_input("Image"); + /* Single value inputs can't be despeckled and are returned as is. */ + if (input_image.is_single_value()) { + get_input("Image").pass_through(get_result("Image")); + return; + } + + GPUShader *shader = shader_manager().get("compositor_despeckle"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "threshold", get_threshold()); + GPU_shader_uniform_1f(shader, "neighbor_threshold", get_neighbor_threshold()); + + input_image.bind_as_texture(shader, "input_tx"); + + const Result &factor_image = get_input("Fac"); + factor_image.bind_as_texture(shader, "factor_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + factor_image.unbind_as_texture(); + } + + float get_threshold() + { + return bnode().custom3; + } + + float get_neighbor_threshold() + { + return bnode().custom4; } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc index eacba5ad12d..028dd6bfbf0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc @@ -5,10 +5,18 @@ * \ingroup cmpnodes */ +#include "BLI_float3x3.hh" +#include "BLI_math_base.hh" +#include "BLI_math_vec_types.hh" +#include "BLI_math_vector.hh" + #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -16,7 +24,9 @@ namespace blender::nodes::node_composite_directionalblur_cc { static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); } @@ -61,7 +71,119 @@ class DirectionalBlurOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); + if (is_identity()) { + get_input("Image").pass_through(get_result("Image")); + return; + } + + GPUShader *shader = shader_manager().get("compositor_directional_blur"); + GPU_shader_bind(shader); + + /* The number of iterations does not cover the original image, that is, the image with no + * transformation. So add an extra iteration for the original image and put that into + * consideration in the shader. */ + GPU_shader_uniform_1i(shader, "iterations", get_iterations() + 1); + GPU_shader_uniform_mat3_as_mat4(shader, "inverse_transformation", get_transformation().ptr()); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + GPU_texture_filter_mode(input_image.texture(), true); + GPU_texture_wrap_mode(input_image.texture(), false, false); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + } + + /* Get the amount of translation that will be applied on each iteration. The translation is in + * the negative x direction rotated in the clock-wise direction, hence the negative sign for the + * rotation and translation vector. */ + float2 get_translation() + { + const float diagonal_length = math::length(float2(get_input("Image").domain().size)); + const float translation_amount = diagonal_length * get_node_directional_blur_data().distance; + const float3x3 rotation = float3x3::from_rotation(-get_node_directional_blur_data().angle); + return rotation * float2(-translation_amount / get_iterations(), 0.0f); + } + + /* Get the amount of rotation that will be applied on each iteration. */ + float get_rotation() + { + return get_node_directional_blur_data().spin / get_iterations(); + } + + /* Get the amount of scale that will be applied on each iteration. The scale is identity when the + * user supplies 0, so we add 1. */ + float2 get_scale() + { + return float2(1.0f + get_node_directional_blur_data().zoom / get_iterations()); + } + + float2 get_origin() + { + const float2 center = float2(get_node_directional_blur_data().center_x, + get_node_directional_blur_data().center_y); + return float2(get_input("Image").domain().size) * center; + } + + float3x3 get_transformation() + { + /* Construct the transformation that will be applied on each iteration. */ + const float3x3 transformation = float3x3::from_translation_rotation_scale( + get_translation(), get_rotation(), get_scale()); + /* Change the origin of the transformation to the user-specified origin. */ + const float3x3 origin_transformation = float3x3::from_origin_transformation(transformation, + get_origin()); + /* The shader will transform the coordinates, not the image itself, so take the inverse. */ + return origin_transformation.inverted(); + } + + /* The actual number of iterations is 2 to the power of the user supplied iterations. The power + * is implemented using a bit shift. But also make sure it doesn't exceed the upper limit which + * is the number of diagonal pixels. */ + int get_iterations() + { + const int iterations = 2 << (get_node_directional_blur_data().iter - 1); + const int upper_limit = math::ceil(math::length(float2(get_input("Image").domain().size))); + return math::min(iterations, upper_limit); + } + + /* Returns true if the operation does nothing and the input can be passed through. */ + bool is_identity() + { + const Result &input = get_input("Image"); + /* Single value inputs can't be blurred and are returned as is. */ + if (input.is_single_value()) { + return true; + } + + /* If any of the following options are non-zero, then the operation is not an identity. */ + if (get_node_directional_blur_data().distance != 0.0f) { + return false; + } + + if (get_node_directional_blur_data().spin != 0.0f) { + return false; + } + + if (get_node_directional_blur_data().zoom != 0.0f) { + return false; + } + + return true; + } + + NodeDBlurData &get_node_directional_blur_data() + { + return *static_cast<NodeDBlurData *>(bnode().storage); } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc index 854cf684806..bd7b443e17e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_filter.cc +++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc @@ -5,10 +5,13 @@ * \ingroup cmpnodes */ +#include "BLI_float3x3.hh" + #include "UI_interface.h" #include "UI_resources.h" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -18,8 +21,15 @@ namespace blender::nodes::node_composite_filter_cc { static void cmp_node_filter_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Fac")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR) + .compositor_domain_priority(1); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); } @@ -36,7 +46,103 @@ class FilterOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); + GPUShader *shader = shader_manager().get(get_shader_name()); + GPU_shader_bind(shader); + + GPU_shader_uniform_mat3_as_mat4(shader, "kernel", get_filter_kernel().ptr()); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Result &factor = get_input("Fac"); + factor.bind_as_texture(shader, "factor_tx"); + + const Domain domain = compute_domain(); + + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + input_image.unbind_as_texture(); + factor.unbind_as_texture(); + output_image.unbind_as_image(); + GPU_shader_unbind(); + } + + CMPNodeFilterMethod get_filter_method() + { + return (CMPNodeFilterMethod)bnode().custom1; + } + + float3x3 get_filter_kernel() + { + /* Initialize the kernels as arrays of rows with the top row first. Edge detection kernels + * return the kernel in the X direction, while the kernel in the Y direction will be computed + * inside the shader by transposing the kernel in the X direction. */ + switch (get_filter_method()) { + case CMP_NODE_FILTER_SOFT: { + const float kernel[3][3] = {{1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f}, + {2.0f / 16.0f, 4.0f / 16.0f, 2.0f / 16.0f}, + {1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f}}; + return float3x3(kernel); + } + case CMP_NODE_FILTER_SHARP_BOX: { + const float kernel[3][3] = { + {-1.0f, -1.0f, -1.0f}, {-1.0f, 9.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}}; + return float3x3(kernel); + } + case CMP_NODE_FILTER_LAPLACE: { + const float kernel[3][3] = {{-1.0f / 8.0f, -1.0f / 8.0f, -1.0f / 8.0f}, + {-1.0f / 8.0f, 1.0f, -1.0f / 8.0f}, + {-1.0f / 8.0f, -1.0f / 8.0f, -1.0f / 8.0f}}; + return float3x3(kernel); + } + case CMP_NODE_FILTER_SOBEL: { + const float kernel[3][3] = {{1.0f, 0.0f, -1.0f}, {2.0f, 0.0f, -2.0f}, {1.0f, 0.0f, -1.0f}}; + return float3x3(kernel); + } + case CMP_NODE_FILTER_PREWITT: { + const float kernel[3][3] = {{1.0f, 0.0f, -1.0f}, {1.0f, 0.0f, -1.0f}, {1.0f, 0.0f, -1.0f}}; + return float3x3(kernel); + } + case CMP_NODE_FILTER_KIRSCH: { + const float kernel[3][3] = { + {5.0f, -3.0f, -2.0f}, {5.0f, -3.0f, -2.0f}, {5.0f, -3.0f, -2.0f}}; + return float3x3(kernel); + } + case CMP_NODE_FILTER_SHADOW: { + const float kernel[3][3] = {{1.0f, 2.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {-1.0f, -2.0f, -1.0f}}; + return float3x3(kernel); + } + case CMP_NODE_FILTER_SHARP_DIAMOND: { + const float kernel[3][3] = { + {0.0f, -1.0f, 0.0f}, {-1.0f, 5.0f, -1.0f}, {0.0f, -1.0f, 0.0f}}; + return float3x3(kernel); + } + default: { + const float kernel[3][3] = {{0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}; + return float3x3(kernel); + } + } + } + + const char *get_shader_name() + { + switch (get_filter_method()) { + case CMP_NODE_FILTER_LAPLACE: + case CMP_NODE_FILTER_SOBEL: + case CMP_NODE_FILTER_PREWITT: + case CMP_NODE_FILTER_KIRSCH: + return "compositor_edge_filter"; + case CMP_NODE_FILTER_SOFT: + case CMP_NODE_FILTER_SHARP_BOX: + case CMP_NODE_FILTER_SHADOW: + case CMP_NODE_FILTER_SHARP_DIAMOND: + default: + return "compositor_filter"; + } } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc index ec95de3da18..7c1a61cedc4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc +++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc @@ -247,7 +247,9 @@ class MovieClipOperation : public NodeOperation { void free_movie_clip_texture() { MovieClip *movie_clip = get_movie_clip(); - return BKE_movieclip_free_gputexture(movie_clip); + if (movie_clip) { + BKE_movieclip_free_gputexture(movie_clip); + } } MovieClip *get_movie_clip() diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc index b98541e3446..5901d310df4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc @@ -143,8 +143,8 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry Array<float> lengths = accumulated_lengths_curve_domain(curves); const int last_index = curves.curves_num() - 1; - const int total_length = lengths.last() + curves.evaluated_length_total_for_curve( - last_index, cyclic[last_index]); + const float total_length = lengths.last() + curves.evaluated_length_total_for_curve( + last_index, cyclic[last_index]); if (total_length > 0.0f) { const float factor = 1.0f / total_length; for (float &value : lengths) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index 992470e8279..5cc4d6e6dbc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -47,9 +47,6 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh, BMeshFromMeshParams from_mesh_params{}; from_mesh_params.calc_face_normal = true; from_mesh_params.calc_vert_normal = true; - from_mesh_params.add_key_index = true; - from_mesh_params.use_shapekey = true; - from_mesh_params.active_shapekey = 1; from_mesh_params.cd_mask_extra = cd_mask_extra; BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params); diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index e8be093c606..ddab455509d 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -200,7 +200,7 @@ void node_math_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *la if (!enum_label) { name = "Unknown"; } - BLI_strncpy(label, IFACE_(name), maxlen); + BLI_strncpy(label, CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, name), maxlen); } void node_vector_math_label(const bNodeTree *UNUSED(ntree), diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 8a2b18d7d76..73ee6fb3f85 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -61,8 +61,9 @@ static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams ¶ms) ELEM(item->value, NODE_MATH_COMPARE, NODE_MATH_GREATER_THAN, NODE_MATH_LESS_THAN)) ? -1 : weight; - params.add_item( - IFACE_(item->name), SocketSearchOp{"Value", (NodeMathOperation)item->value}, gn_weight); + params.add_item(CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, item->name), + SocketSearchOp{"Value", (NodeMathOperation)item->value}, + gn_weight); } } } diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 8075e4ecd22..aecefa97423 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -34,7 +34,7 @@ void BPY_pyconstraint_exec(struct bPythonConstraint *con, // void BPY_pyconstraint_settings(void *arg1, void *arg2); void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct); void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con); -int BPY_is_pyconstraint(struct Text *text); +bool BPY_is_pyconstraint(struct Text *text); // void BPY_free_pyconstraint_links(struct Text *text); /* global interpreter lock */ diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt index 69bcfdfae4e..27b7ad28943 100644 --- a/source/blender/python/generic/CMakeLists.txt +++ b/source/blender/python/generic/CMakeLists.txt @@ -7,12 +7,11 @@ set(INC ../../gpu ../../makesdna ../../makesrna - ../../../../intern/glew-mx ../../../../intern/guardedalloc ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${Epoxy_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} ) @@ -41,11 +40,9 @@ set(SRC ) set(LIB - ${GLEW_LIBRARY} + ${Epoxy_LIBRARIES} ${PYTHON_LINKFLAGS} ${PYTHON_LIBRARIES} ) -add_definitions(${GL_DEFINITIONS}) - blender_add_lib(bf_python_ext "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index f5c1f060e80..197af75e5d7 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -19,7 +19,7 @@ #include "../generic/py_capi_utils.h" -#include "glew-mx.h" +#include <epoxy/gl.h> #include "bgl.h" diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index ecb6db2b82c..91ebef8d0b0 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -215,7 +215,6 @@ int PyC_CheckArgs_DeepCopy(PyObject *args); /* Integer parsing (with overflow checks), -1 on error. */ /** - * * Comparison with #PyObject_IsTrue * ================================ * diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt index 8ccb29beb13..e9db5c8716b 100644 --- a/source/blender/python/gpu/CMakeLists.txt +++ b/source/blender/python/gpu/CMakeLists.txt @@ -8,12 +8,11 @@ set(INC ../../gpu ../../imbuf ../../makesdna - ../../../../intern/glew-mx ../../../../intern/guardedalloc ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${Epoxy_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} ) @@ -59,10 +58,9 @@ set(SRC ) set(LIB + ${Epoxy_LIBRARIES} ${PYTHON_LINKFLAGS} ${PYTHON_LIBRARIES} ) -add_definitions(${GL_DEFINITIONS}) - blender_add_lib(bf_python_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index e3f789aa58d..216f98202d4 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -600,14 +600,14 @@ static PyObject *pygpu_shader_attr_from_name(BPyGPUShader *self, PyObject *arg) return PyLong_FromLong(attr); } -PyDoc_STRVAR(pygpu_shader_calc_format_doc, - ".. method:: calc_format()\n" +PyDoc_STRVAR(pygpu_shader_format_calc_doc, + ".. method:: format_calc()\n" "\n" " Build a new format based on the attributes of the shader.\n" "\n" " :return: vertex attribute format for the shader\n" " :rtype: :class:`gpu.types.GPUVertFormat`\n"); -static PyObject *pygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg)) +static PyObject *pygpu_shader_format_calc(BPyGPUShader *self, PyObject *UNUSED(arg)) { BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL); GPU_vertformat_from_shader(&ret->fmt, self->shader); @@ -657,9 +657,9 @@ static struct PyMethodDef pygpu_shader__tp_methods[] = { METH_O, pygpu_shader_attr_from_name_doc}, {"format_calc", - (PyCFunction)pygpu_shader_calc_format, + (PyCFunction)pygpu_shader_format_calc, METH_NOARGS, - pygpu_shader_calc_format_doc}, + pygpu_shader_format_calc_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 939fa475344..23fc0bcaeda 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -585,6 +585,11 @@ void BPY_python_use_system_env(void) void BPY_python_backtrace(FILE *fp) { fputs("\n# Python backtrace\n", fp); + + /* Can happen in rare cases. */ + if (!_PyThreadState_UncheckedGet()) { + return; + } PyFrameObject *frame; if (!(frame = PyEval_GetFrame())) { return; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 179a0250688..56de0bfc18e 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -2213,6 +2213,26 @@ static int pyrna_prop_collection_bool(BPy_PropertyRNA *self) } \ (void)0 +/** + * \param result: The result of calling a subscription operation on a collection (never NULL). + */ +static int pyrna_prop_collection_subscript_is_valid_or_error(const PyObject *value) +{ + if (value != Py_None) { + BLI_assert(BPy_StructRNA_Check(value)); + const BPy_StructRNA *value_pyrna = (const BPy_StructRNA *)value; + if (UNLIKELY(value_pyrna->ptr.type == NULL)) { + /* It's important to use a `TypeError` as that is what's returned when `__getitem__` is + * called on an object that doesn't support item access. */ + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not subscriptable (only iteration is supported)", + Py_TYPE(value)->tp_name); + return -1; + } + } + return 0; +} + /* Internal use only. */ static PyObject *pyrna_prop_collection_subscript_int(BPy_PropertyRNA *self, Py_ssize_t keynum) { @@ -2223,8 +2243,35 @@ static PyObject *pyrna_prop_collection_subscript_int(BPy_PropertyRNA *self, Py_s PYRNA_PROP_COLLECTION_ABS_INDEX(NULL); - if (RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum_abs, &newptr)) { - return pyrna_struct_CreatePyObject(&newptr); + if (RNA_property_collection_lookup_int_has_fn(self->prop)) { + if (RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum_abs, &newptr)) { + return pyrna_struct_CreatePyObject(&newptr); + } + } + else { + /* No callback defined, just iterate and find the nth item. */ + const int key = (int)keynum_abs; + PyObject *result = NULL; + bool found = false; + CollectionPropertyIterator iter; + RNA_property_collection_begin(&self->ptr, self->prop, &iter); + for (int i = 0; iter.valid; RNA_property_collection_next(&iter), i++) { + if (i == key) { + result = pyrna_struct_CreatePyObject(&iter.ptr); + found = true; + break; + } + } + /* It's important to end the iterator after `result` has been created + * so iterators may optionally invalidate items that were iterated over, see: T100286. */ + RNA_property_collection_end(&iter); + if (found) { + if (result && (pyrna_prop_collection_subscript_is_valid_or_error(result) == -1)) { + Py_DECREF(result); + result = NULL; /* The exception has been set. */ + } + return result; + } } const int len = RNA_property_collection_length(&self->ptr, self->prop); @@ -2306,8 +2353,45 @@ static PyObject *pyrna_prop_collection_subscript_str(BPy_PropertyRNA *self, cons PYRNA_PROP_CHECK_OBJ(self); - if (RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr)) { - return pyrna_struct_CreatePyObject(&newptr); + if (RNA_property_collection_lookup_string_has_fn(self->prop)) { + if (RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr)) { + return pyrna_struct_CreatePyObject(&newptr); + } + } + else { + /* No callback defined, just iterate and find the nth item. */ + const int keylen = strlen(keyname); + char name[256]; + int namelen; + PyObject *result = NULL; + bool found = false; + CollectionPropertyIterator iter; + RNA_property_collection_begin(&self->ptr, self->prop, &iter); + for (int i = 0; iter.valid; RNA_property_collection_next(&iter), i++) { + PropertyRNA *nameprop = RNA_struct_name_property(iter.ptr.type); + char *nameptr = RNA_property_string_get_alloc( + &iter.ptr, nameprop, name, sizeof(name), &namelen); + if ((keylen == namelen) && STREQ(nameptr, keyname)) { + found = true; + } + if ((char *)&name != nameptr) { + MEM_freeN(nameptr); + } + if (found) { + result = pyrna_struct_CreatePyObject(&iter.ptr); + break; + } + } + /* It's important to end the iterator after `result` has been created + * so iterators may optionally invalidate items that were iterated over, see: T100286. */ + RNA_property_collection_end(&iter); + if (found) { + if (result && (pyrna_prop_collection_subscript_is_valid_or_error(result) == -1)) { + Py_DECREF(result); + result = NULL; /* The exception has been set. */ + } + return result; + } } PyErr_Format(PyExc_KeyError, "bpy_prop_collection[key]: key \"%.200s\" not found", keyname); diff --git a/source/blender/python/intern/stubs.c b/source/blender/python/intern/stubs.c index c29f9188eea..f860bdc36ee 100644 --- a/source/blender/python/intern/stubs.c +++ b/source/blender/python/intern/stubs.c @@ -25,7 +25,7 @@ void BPY_pyconstraint_exec(struct bPythonConstraint *con, void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct) { } -int BPY_is_pyconstraint(struct Text *text) +bool BPY_is_pyconstraint(struct Text *text) { return 0; } diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 1e85ece124d..8405b966a4e 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1244,12 +1244,11 @@ static PyObject *Matrix_to_quaternion(MatrixObject *self) return NULL; } if (self->row_num == 3) { - mat3_to_quat(quat, (float(*)[3])self->matrix); + mat3_to_quat(quat, (const float(*)[3])self->matrix); } else { mat4_to_quat(quat, (const float(*)[4])self->matrix); } - return Quaternion_CreatePyObject(quat, NULL); } @@ -1888,7 +1887,7 @@ static PyObject *Matrix_decompose(MatrixObject *self) } mat4_to_loc_rot_size(loc, rot, size, (const float(*)[4])self->matrix); - mat3_to_quat(quat, rot); + mat3_normalized_to_quat_fast(quat, rot); ret = PyTuple_New(3); PyTuple_SET_ITEMS(ret, diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 6994a313237..a5ea09bef48 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -543,7 +543,6 @@ static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value) length = normalize_qt_qt(tquat, self->quat); quat_to_mat3(self_rmat, tquat); mul_m3_m3m3(rmat, other_rmat, self_rmat); - mat3_to_quat(self->quat, rmat); mul_qt_fl(self->quat, length); /* maintain length after rotating */ diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index 3386a74daba..4cd31fa3bc1 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -990,6 +990,8 @@ void render_result_exr_file_cache_write(Render *re) char str[FILE_MAXFILE + FILE_MAXFILE + MAX_ID_NAME + 100]; char *root = U.render_cachedir; + render_result_passes_allocated_ensure(rr); + render_result_exr_file_cache_path(re->scene, root, str); printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str); diff --git a/source/blender/render/intern/texture_common.h b/source/blender/render/intern/texture_common.h index 0057779bda6..028b3d22f01 100644 --- a/source/blender/render/intern/texture_common.h +++ b/source/blender/render/intern/texture_common.h @@ -73,8 +73,8 @@ int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], - const float dxt[2], - const float dyt[2], + const float DXT[2], + const float DYT[2], struct TexResult *texres, struct ImagePool *pool, bool skip_load_image); diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c index 7da9e7c3d58..3c12742f52c 100644 --- a/source/blender/render/intern/texture_image.c +++ b/source/blender/render/intern/texture_image.c @@ -1620,7 +1620,6 @@ int imagewraposa(Tex *tex, /* Choice: */ if (tex->imaflag & TEX_MIPMAP) { ImBuf *previbuf, *curibuf; - float bumpscale; dx = minx; dy = miny; @@ -1631,14 +1630,6 @@ int imagewraposa(Tex *tex, pixsize = 1.0f / (float)MIN2(ibuf->x, ibuf->y); - bumpscale = pixsize / maxd; - if (bumpscale > 1.0f) { - bumpscale = 1.0f; - } - else { - bumpscale *= bumpscale; - } - curmap = 0; previbuf = curibuf = ibuf; while (curmap < IMB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) { diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h index ff9c387e527..afe35d20c2b 100644 --- a/source/blender/sequencer/SEQ_edit.h +++ b/source/blender/sequencer/SEQ_edit.h @@ -16,10 +16,10 @@ struct Main; struct Scene; struct Sequence; -int SEQ_edit_sequence_swap(struct Scene *scene, - struct Sequence *seq_a, - struct Sequence *seq_b, - const char **error_str); +bool SEQ_edit_sequence_swap(struct Scene *scene, + struct Sequence *seq_a, + struct Sequence *seq_b, + const char **error_str); /** * Move sequence to seqbase. * diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h index 9678ac1cc1c..1b8d9db347d 100644 --- a/source/blender/sequencer/SEQ_relations.h +++ b/source/blender/sequencer/SEQ_relations.h @@ -31,7 +31,7 @@ bool SEQ_relations_check_scene_recursion(struct Scene *scene, struct ReportList * Check if "seq_main" (indirectly) uses strip "seq". */ bool SEQ_relations_render_loop_check(struct Sequence *seq_main, struct Sequence *seq); -void SEQ_relations_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); +void SEQ_relations_free_imbuf(struct Scene *scene, struct ListBase *seqbase, bool for_render); void SEQ_relations_invalidate_cache_raw(struct Scene *scene, struct Sequence *seq); void SEQ_relations_invalidate_cache_preprocessed(struct Scene *scene, struct Sequence *seq); void SEQ_relations_invalidate_cache_composite(struct Scene *scene, struct Sequence *seq); diff --git a/source/blender/sequencer/SEQ_select.h b/source/blender/sequencer/SEQ_select.h index 92fb508372e..52d0bcc120e 100644 --- a/source/blender/sequencer/SEQ_select.h +++ b/source/blender/sequencer/SEQ_select.h @@ -15,9 +15,9 @@ struct Scene; struct Sequence; struct Sequence *SEQ_select_active_get(struct Scene *scene); -int SEQ_select_active_get_pair(struct Scene *scene, - struct Sequence **r_seq_act, - struct Sequence **r_seq_other); +bool SEQ_select_active_get_pair(struct Scene *scene, + struct Sequence **r_seq_act, + struct Sequence **r_seq_other); void SEQ_select_active_set(struct Scene *scene, struct Sequence *seq); #ifdef __cplusplus diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h index 8bc7733861c..c27a9dc4409 100644 --- a/source/blender/sequencer/SEQ_transform.h +++ b/source/blender/sequencer/SEQ_transform.h @@ -30,7 +30,7 @@ bool SEQ_transform_test_overlap(const struct Scene *scene, bool SEQ_transform_test_overlap_seq_seq(const struct Scene *scene, struct Sequence *seq1, struct Sequence *seq2); -void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta); +void SEQ_transform_translate_sequence(struct Scene *evil_scene, struct Sequence *seq, int delta); /** * \return 0 if there weren't enough space. */ diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 15c472dd5a7..c35138b280a 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -37,32 +37,32 @@ #include "SEQ_transform.h" #include "SEQ_utils.h" -int SEQ_edit_sequence_swap(Scene *scene, Sequence *seq_a, Sequence *seq_b, const char **error_str) +bool SEQ_edit_sequence_swap(Scene *scene, Sequence *seq_a, Sequence *seq_b, const char **error_str) { char name[sizeof(seq_a->name)]; if (SEQ_time_strip_length_get(scene, seq_a) != SEQ_time_strip_length_get(scene, seq_b)) { *error_str = N_("Strips must be the same length"); - return 0; + return false; } /* type checking, could be more advanced but disallow sound vs non-sound copy */ if (seq_a->type != seq_b->type) { if (seq_a->type == SEQ_TYPE_SOUND_RAM || seq_b->type == SEQ_TYPE_SOUND_RAM) { *error_str = N_("Strips were not compatible"); - return 0; + return false; } /* disallow effects to swap with non-effects strips */ if ((seq_a->type & SEQ_TYPE_EFFECT) != (seq_b->type & SEQ_TYPE_EFFECT)) { *error_str = N_("Strips were not compatible"); - return 0; + return false; } if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) { if (SEQ_effect_get_num_inputs(seq_a->type) != SEQ_effect_get_num_inputs(seq_b->type)) { *error_str = N_("Strips must have the same number of inputs"); - return 0; + return false; } } } @@ -87,27 +87,26 @@ int SEQ_edit_sequence_swap(Scene *scene, Sequence *seq_a, Sequence *seq_b, const seq_time_effect_range_set(scene, seq_a); seq_time_effect_range_set(scene, seq_b); - return 1; + return true; } static void seq_update_muting_recursive(ListBase *channels, ListBase *seqbasep, Sequence *metaseq, - int mute) + const bool mute) { Sequence *seq; - int seqmute; /* For sound we go over full meta tree to update muted state, * since sound is played outside of evaluating the imbufs. */ for (seq = seqbasep->first; seq; seq = seq->next) { - seqmute = (mute || SEQ_render_is_muted(channels, seq)); + bool seqmute = (mute || SEQ_render_is_muted(channels, seq)); if (seq->type == SEQ_TYPE_META) { /* if this is the current meta sequence, unmute because * all sequences above this were set to mute */ if (seq == metaseq) { - seqmute = 0; + seqmute = false; } seq_update_muting_recursive(&seq->channels, &seq->seqbase, metaseq, seqmute); @@ -127,10 +126,10 @@ void SEQ_edit_update_muting(Editing *ed) MetaStack *ms = ed->metastack.last; if (ms) { - seq_update_muting_recursive(&ed->channels, &ed->seqbase, ms->parseq, 1); + seq_update_muting_recursive(&ed->channels, &ed->seqbase, ms->parseq, true); } else { - seq_update_muting_recursive(&ed->channels, &ed->seqbase, NULL, 0); + seq_update_muting_recursive(&ed->channels, &ed->seqbase, NULL, false); } } } diff --git a/source/blender/sequencer/intern/strip_select.c b/source/blender/sequencer/intern/strip_select.c index 69b4ce1f7c7..1a4ad4d997e 100644 --- a/source/blender/sequencer/intern/strip_select.c +++ b/source/blender/sequencer/intern/strip_select.c @@ -37,14 +37,14 @@ void SEQ_select_active_set(Scene *scene, Sequence *seq) ed->act_seq = seq; } -int SEQ_select_active_get_pair(Scene *scene, Sequence **r_seq_act, Sequence **r_seq_other) +bool SEQ_select_active_get_pair(Scene *scene, Sequence **r_seq_act, Sequence **r_seq_other) { Editing *ed = SEQ_editing_get(scene); *r_seq_act = SEQ_select_active_get(scene); if (*r_seq_act == NULL) { - return 0; + return false; } Sequence *seq; @@ -54,7 +54,7 @@ int SEQ_select_active_get_pair(Scene *scene, Sequence **r_seq_act, Sequence **r_ for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && (seq != (*r_seq_act))) { if (*r_seq_other) { - return 0; + return false; } *r_seq_other = seq; diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 68b30c9ce19..a7361cbb1f9 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -84,7 +84,7 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase) void SEQ_transform_fix_single_image_seq_offsets(const Scene *scene, Sequence *seq) { - int left, start, offset; + int left, start; if (!SEQ_transform_single_image_check(seq)) { return; } @@ -94,7 +94,7 @@ void SEQ_transform_fix_single_image_seq_offsets(const Scene *scene, Sequence *se left = SEQ_time_left_handle_frame_get(scene, seq); start = seq->start; if (start != left) { - offset = left - start; + const int offset = left - start; SEQ_time_left_handle_frame_set( scene, seq, SEQ_time_left_handle_frame_get(scene, seq) - offset); SEQ_time_right_handle_frame_set( diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index c434638549c..9da150e0b7a 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -23,7 +23,6 @@ set(INC ../sequencer ../../../intern/clog ../../../intern/ghost - ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/memutil ../bmesh diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 44c5b86857d..0393be93bb5 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -134,7 +134,24 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm, const int pos[2], float r_col[3]); +/** + * Read pixels from the front-buffer (fast). + * + * \note Internally this depends on the front-buffer state, + * for a slower but more reliable method of reading pixels, use #WM_window_pixels_read_offscreen. + * Fast pixel access may be preferred for file-save thumbnails. + * + * \warning Drawing (swap-buffers) immediately before calling this function causes + * the front-buffer state to be invalid under some EGL configurations. + */ uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]); +/** + * Draw the window & read pixels from an off-screen buffer (slower than #WM_window_pixels_read). + * + * \note This is needed because the state of the front-buffer may be damaged + * (see in-line code comments for details). + */ +uint *WM_window_pixels_read_offscreen(struct bContext *C, struct wmWindow *win, int r_size[2]); /** * Support for native pixel size diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index e7cbe936607..9d9e0fe8fee 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -669,7 +669,6 @@ typedef struct wmTabletData { * * - Mouse-wheel events are excluded even though they generate #KM_PRESS * as clicking and dragging don't make sense for mouse wheel events. - * */ typedef struct wmEvent { struct wmEvent *next, *prev; diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index e30ea618fa4..cbdcb76d9aa 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -180,7 +180,7 @@ typedef enum eWM_GizmoFlagMapTypeUpdateFlag { /** * \brief Gizmo tweak flag. - * Bitflag passed to gizmo while tweaking. + * Bit-flag passed to gizmo while tweaking. * * \note Gizmos are responsible for handling this #wmGizmo.modal callback. */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 0d74bc259f4..9b3a0d39dfa 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -15,6 +15,7 @@ #include <stddef.h> #include <string.h> +#include "BLI_ghash.h" #include "BLI_sys_types.h" #include "DNA_windowmanager_types.h" @@ -193,6 +194,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id) BLI_listbase_clear(&wm->operators); BLI_listbase_clear(&wm->paintcursors); BLI_listbase_clear(&wm->notifier_queue); + wm->notifier_queue_set = NULL; BKE_reports_init(&wm->reports, RPT_STORE); BLI_listbase_clear(&wm->keyconfigs); @@ -580,6 +582,10 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) } BLI_freelistN(&wm->notifier_queue); + if (wm->notifier_queue_set) { + BLI_gset_free(wm->notifier_queue_set, NULL); + wm->notifier_queue_set = NULL; + } if (wm->message_bus != NULL) { WM_msgbus_destroy(wm->message_bus); diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 1bb405d1abc..48743c2649f 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -1191,6 +1191,39 @@ static void wm_draw_surface(bContext *C, wmSurface *surface) wm_surface_clear_drawable(); } +uint *WM_window_pixels_read_offscreen(bContext *C, wmWindow *win, int r_size[2]) +{ + /* NOTE(@campbellbarton): There is a problem reading the windows front-buffer after redrawing + * the window in some cases (typically to clear UI elements such as menus or search popup). + * With EGL `eglSurfaceAttrib(..)` may support setting the `EGL_SWAP_BEHAVIOR` attribute to + * `EGL_BUFFER_PRESERVED` however not all implementations support this. + * Requesting the ability with `EGL_SWAP_BEHAVIOR_PRESERVED_BIT` can even cause the EGL context + * not to initialize at all. + * Confusingly there are some cases where this *does* work, depending on the state of the window + * and prior calls to swap-buffers, however ensuring the state exactly as needed to satisfy a + * particular GPU back-end is fragile, see T98462. + * + * So provide an alternative to #WM_window_pixels_read that avoids using the front-buffer. */ + + /* Draw into an off-screen buffer and read it's contents. */ + r_size[0] = WM_window_pixels_x(win); + r_size[1] = WM_window_pixels_y(win); + + GPUOffScreen *offscreen = GPU_offscreen_create(r_size[0], r_size[1], false, GPU_RGBA8, NULL); + if (UNLIKELY(!offscreen)) { + return NULL; + } + + const uint rect_len = r_size[0] * r_size[1]; + uint *rect = MEM_mallocN(sizeof(*rect) * rect_len, __func__); + GPU_offscreen_bind(offscreen, false); + wm_draw_window_onscreen(C, win, -1); + GPU_offscreen_unbind(offscreen, false); + GPU_offscreen_read_pixels(offscreen, GPU_DATA_UBYTE, rect); + GPU_offscreen_free(offscreen); + return rect; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 77f6b3c861f..d6368e73f5a 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -27,6 +27,7 @@ #include "BLI_blenlib.h" #include "BLI_dynstr.h" +#include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_timer.h" #include "BLI_utildefines.h" @@ -252,36 +253,56 @@ void wm_event_init_from_window(wmWindow *win, wmEvent *event) /** \name Notifiers & Listeners * \{ */ -static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference) +/** + * Hash for #wmWindowManager.notifier_queue_set, ignores `window`. + */ +static uint note_hash_for_queue_fn(const void *ptr) { - LISTBASE_FOREACH (wmNotifier *, note, &wm->notifier_queue) { - if ((note->category | note->data | note->subtype | note->action) == type && - note->reference == reference) { - return true; - } - } + const wmNotifier *note = static_cast<const wmNotifier *>(ptr); + return (BLI_ghashutil_ptrhash(note->reference) ^ + (note->category | note->data | note->subtype | note->action)); +} - return false; +/** + * Comparison for #wmWindowManager.notifier_queue_set + * + * \note This is not an exact equality function as the `window` is ignored. + */ +static bool note_cmp_for_queue_fn(const void *a, const void *b) +{ + const wmNotifier *note_a = static_cast<const wmNotifier *>(a); + const wmNotifier *note_b = static_cast<const wmNotifier *>(b); + return !(((note_a->category | note_a->data | note_a->subtype | note_a->action) == + (note_b->category | note_b->data | note_b->subtype | note_b->action)) && + (note_a->reference == note_b->reference)); } void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference) { - if (wm_test_duplicate_notifier(wm, type, reference)) { - return; - } + wmNotifier note_test = {nullptr}; - wmNotifier *note = MEM_cnew<wmNotifier>(__func__); + note_test.window = win; - BLI_addtail(&wm->notifier_queue, note); + note_test.category = type & NOTE_CATEGORY; + note_test.data = type & NOTE_DATA; + note_test.subtype = type & NOTE_SUBTYPE; + note_test.action = type & NOTE_ACTION; - note->window = win; + note_test.reference = reference; - note->category = type & NOTE_CATEGORY; - note->data = type & NOTE_DATA; - note->subtype = type & NOTE_SUBTYPE; - note->action = type & NOTE_ACTION; + if (wm->notifier_queue_set == nullptr) { + wm->notifier_queue_set = BLI_gset_new_ex( + note_hash_for_queue_fn, note_cmp_for_queue_fn, __func__, 1024); + } - note->reference = reference; + void **note_p; + if (BLI_gset_ensure_p_ex(wm->notifier_queue_set, ¬e_test, ¬e_p)) { + return; + } + wmNotifier *note = MEM_new<wmNotifier>(__func__); + *note = note_test; + *note_p = note; + BLI_addtail(&wm->notifier_queue, note); } /* XXX: in future, which notifiers to send to other windows? */ @@ -295,20 +316,7 @@ void WM_main_add_notifier(unsigned int type, void *reference) Main *bmain = G_MAIN; wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); - if (!wm || wm_test_duplicate_notifier(wm, type, reference)) { - return; - } - - wmNotifier *note = MEM_cnew<wmNotifier>(__func__); - - BLI_addtail(&wm->notifier_queue, note); - - note->category = type & NOTE_CATEGORY; - note->data = type & NOTE_DATA; - note->subtype = type & NOTE_SUBTYPE; - note->action = type & NOTE_ACTION; - - note->reference = reference; + WM_event_add_notifier_ex(wm, nullptr, type, reference); } void WM_main_remove_notifier_reference(const void *reference) @@ -319,6 +327,9 @@ void WM_main_remove_notifier_reference(const void *reference) if (wm) { LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) { if (note->reference == reference) { + const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr); + BLI_assert(removed); + UNUSED_VARS_NDEBUG(removed); /* Don't remove because this causes problems for #wm_event_do_notifiers * which may be looping on the data (deleting screens). */ wm_notifier_clear(note); @@ -567,6 +578,9 @@ void wm_event_do_notifiers(bContext *C) /* The notifiers are sent without context, to keep it clean. */ wmNotifier *note; while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) { + const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr); + BLI_assert(removed); + UNUSED_VARS_NDEBUG(removed); LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { Scene *scene = WM_window_get_active_scene(win); bScreen *screen = WM_window_get_active_screen(win); @@ -657,7 +671,7 @@ void wm_event_do_notifiers(bContext *C) wm_test_autorun_warning(C); } -static int wm_event_always_pass(const wmEvent *event) +static bool wm_event_always_pass(const wmEvent *event) { /* Some events we always pass on, to ensure proper communication. */ return ISTIMER(event->type) || (event->type == WINDEACTIVATE); @@ -667,14 +681,23 @@ static int wm_event_always_pass(const wmEvent *event) * Debug only sanity check for the return value of event handlers. Checks that "always pass" events * don't cause non-passing handler return values, and thus actually pass. * - * Can't be executed if the handler just loaded a file (typically identified by `CTX_wm_window(C)` - * returning `nullptr`), because the event will have been freed then. + * \param C: Pass in the context to check if it's "window" was cleared. + * The event check can't be executed if the handler just loaded a file or closed the window. + * (typically identified by `CTX_wm_window(C)` returning null), + * because the event will have been freed then. + * When null, always check the event (assume the caller knows the event was not freed). */ -BLI_INLINE void wm_event_handler_return_value_check(const wmEvent *event, const int action) +BLI_INLINE void wm_event_handler_return_value_check(const bContext *C, + const wmEvent *event, + const int action) { - BLI_assert_msg(!wm_event_always_pass(event) || (action != WM_HANDLER_BREAK), - "Return value for events that should always pass should never be BREAK."); - UNUSED_VARS_NDEBUG(event, action); +#ifndef NDEBUG + if (C == nullptr || CTX_wm_window(C)) { + BLI_assert_msg(!wm_event_always_pass(event) || (action != WM_HANDLER_BREAK), + "Return value for events that should always pass should never be BREAK."); + } +#endif + UNUSED_VARS_NDEBUG(C, event, action); } /** \} */ @@ -2731,7 +2754,7 @@ static int wm_handler_fileselect_call(bContext *C, return wm_handler_fileselect_do(C, handlers, handler, event->val); } -static int wm_action_not_handled(int action) +static bool wm_action_not_handled(int action) { return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL); } @@ -3101,7 +3124,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis int action = WM_HANDLER_CONTINUE; if (handlers == nullptr) { - wm_event_handler_return_value_check(event, action); + wm_event_handler_return_value_check(C, event, action); return action; } @@ -3267,9 +3290,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis } /* Do some extra sanity checking before returning the action. */ - if (CTX_wm_window(C) != nullptr) { - wm_event_handler_return_value_check(event, action); - } + wm_event_handler_return_value_check(C, event, action); return action; } @@ -3440,7 +3461,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } - wm_event_handler_return_value_check(event, action); + wm_event_handler_return_value_check(C, event, action); return action; } @@ -3717,7 +3738,7 @@ static int wm_event_do_handlers_area_regions(bContext *C, wmEvent *event, ScrAre action |= wm_event_do_region_handlers(C, event, region); } - wm_event_handler_return_value_check(event, action); + wm_event_handler_return_value_check(C, event, action); return action; } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 1819ed13be3..fb3da9dc7ec 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -296,6 +296,12 @@ static void wm_window_match_keep_current_wm(const bContext *C, } } + /* we'll be using the current wm list directly; make sure + * the names are validated and in the name map. */ + LISTBASE_FOREACH (wmWindowManager *, wm_item, current_wm_list) { + BKE_main_namemap_get_name(bmain, &wm_item->id, wm_item->id.name + 2); + } + *r_new_wm_list = *current_wm_list; } @@ -699,6 +705,14 @@ static void wm_file_read_post(bContext *C, const struct wmFileReadPost_Params *p } } + if (is_factory_startup && BLT_translate_new_dataname()) { + /* Translate workspace names */ + LISTBASE_FOREACH_MUTABLE (WorkSpace *, workspace, &bmain->workspaces) { + BKE_libblock_rename( + bmain, &workspace->id, CTX_DATA_(BLT_I18NCONTEXT_ID_WORKSPACE, workspace->id.name + 2)); + } + } + if (use_data) { /* important to do before NULL'ing the context */ BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE); @@ -1768,9 +1782,11 @@ static bool wm_file_write(bContext *C, /* Enforce full override check/generation on file save. */ BKE_lib_override_library_main_operations_create(bmain, true); - /* NOTE: Ideally we would call `WM_redraw_windows` here to remove any open menus. But we - * can crash if saving from a script, see T92704 & T97627. Just checking `!G.background - * && BLI_thread_is_main()` is not sufficient to fix this. */ + /* NOTE: Ideally we would call `WM_redraw_windows` here to remove any open menus. + * But we can crash if saving from a script, see T92704 & T97627. + * Just checking `!G.background && BLI_thread_is_main()` is not sufficient to fix this. + * Additionally some some EGL configurations don't support reading the front-buffer + * immediately after drawing, see: T98462. In that case off-screen drawing is necessary. */ /* don't forget not to return without! */ WM_cursor_wait(true); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 624e434e784..8163b39b3dd 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -166,7 +166,7 @@ void WM_init_opengl(void) if (G.background) { /* Ghost is still not initialized elsewhere in background mode. */ - wm_ghost_init(NULL); + wm_ghost_init_background(); } if (!GPU_backend_supported()) { diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 2e04a629308..8fca3deef92 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -78,50 +78,51 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) { uchar *rct = (uchar *)ibuf->rect; + if (!rct) { + return; + } - if (rct) { - bTheme *btheme = UI_GetTheme(); - const float roundness = btheme->tui.wcol_menu_back.roundness * U.dpi_fac; - const int size = roundness * 20; - - if (size < ibuf->x && size < ibuf->y) { - /* Y-axis initial offset. */ - rct += 4 * (ibuf->y - size) * ibuf->x; - - for (int y = 0; y < size; y++) { - for (int x = 0; x < size; x++, rct += 4) { - const float pixel = 1.0 / size; - const float u = pixel * x; - const float v = pixel * y; - const float distance = sqrt(u * u + v * v); - - /* Pointer offset to the alpha value of pixel. */ - /* NOTE: the left corner is flipped in the X-axis. */ - const int offset_l = 4 * (size - x - x - 1) + 3; - const int offset_r = 4 * (ibuf->x - size) + 3; - - if (distance > 1.0) { - rct[offset_l] = 0; - rct[offset_r] = 0; - } - else { - /* Create a single pixel wide transition for anti-aliasing. - * Invert the distance and map its range [0, 1] to [0, pixel]. */ - const float fac = (1.0 - distance) * size; - - if (fac > 1.0) { - continue; - } - - const uchar alpha = unit_float_to_uchar_clamp(fac); - rct[offset_l] = alpha; - rct[offset_r] = alpha; - } + bTheme *btheme = UI_GetTheme(); + const float roundness = btheme->tui.wcol_menu_back.roundness * U.dpi_fac; + const int size = roundness * 20; + + if (size < ibuf->x && size < ibuf->y) { + /* Y-axis initial offset. */ + rct += 4 * (ibuf->y - size) * ibuf->x; + + for (int y = 0; y < size; y++) { + for (int x = 0; x < size; x++, rct += 4) { + const float pixel = 1.0 / size; + const float u = pixel * x; + const float v = pixel * y; + const float distance = sqrt(u * u + v * v); + + /* Pointer offset to the alpha value of pixel. */ + /* NOTE: the left corner is flipped in the X-axis. */ + const int offset_l = 4 * (size - x - x - 1) + 3; + const int offset_r = 4 * (ibuf->x - size) + 3; + + if (distance > 1.0) { + rct[offset_l] = 0; + rct[offset_r] = 0; } + else { + /* Create a single pixel wide transition for anti-aliasing. + * Invert the distance and map its range [0, 1] to [0, pixel]. */ + const float fac = (1.0 - distance) * size; - /* X-axis offset to the next row. */ - rct += 4 * (ibuf->x - size); + if (fac > 1.0) { + continue; + } + + const uchar alpha = unit_float_to_uchar_clamp(fac); + rct[offset_l] = alpha; + rct[offset_r] = alpha; + } } + + /* X-axis offset to the next row. */ + rct += 4 * (ibuf->x - size); } } } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 0c31ff87fdd..661db1b62e7 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -155,28 +155,30 @@ static void wm_window_check_size(rcti *rect) static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win) { - if (win->ghostwin) { - /* Prevents non-drawable state of main windows (bugs T22967, - * T25071 and possibly T22477 too). Always clear it even if - * this window was not the drawable one, because we mess with - * drawing context to discard the GW context. */ - wm_window_clear_drawable(wm); + if (UNLIKELY(!win->ghostwin)) { + return; + } - if (win == wm->winactive) { - wm->winactive = NULL; - } + /* Prevents non-drawable state of main windows (bugs T22967, + * T25071 and possibly T22477 too). Always clear it even if + * this window was not the drawable one, because we mess with + * drawing context to discard the GW context. */ + wm_window_clear_drawable(wm); - /* We need this window's opengl context active to discard it. */ - GHOST_ActivateWindowDrawingContext(win->ghostwin); - GPU_context_active_set(win->gpuctx); + if (win == wm->winactive) { + wm->winactive = NULL; + } + + /* We need this window's opengl context active to discard it. */ + GHOST_ActivateWindowDrawingContext(win->ghostwin); + GPU_context_active_set(win->gpuctx); - /* Delete local GPU context. */ - GPU_context_discard(win->gpuctx); + /* Delete local GPU context. */ + GPU_context_discard(win->gpuctx); - GHOST_DisposeWindow(g_system, win->ghostwin); - win->ghostwin = NULL; - win->gpuctx = NULL; - } + GHOST_DisposeWindow(g_system, win->ghostwin); + win->ghostwin = NULL; + win->gpuctx = NULL; } void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) @@ -968,8 +970,8 @@ typedef enum { OS = 'C', } modifierKeyType; -/* check if specified modifier key type is pressed */ -static int query_qual(modifierKeyType qual) +/** Check if specified modifier key type is pressed. */ +static bool query_qual(modifierKeyType qual) { GHOST_TModifierKey left, right; switch (qual) { @@ -1558,36 +1560,55 @@ void wm_window_process_events(const bContext *C) void wm_ghost_init(bContext *C) { - if (!g_system) { - GHOST_EventConsumerHandle consumer; + if (g_system) { + return; + } - if (C != NULL) { - consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); - } + BLI_assert(C != NULL); + BLI_assert_msg(!G.background, "Use wm_ghost_init_background instead"); - GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); + GHOST_EventConsumerHandle consumer; - g_system = GHOST_CreateSystem(); + consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); - GHOST_Debug debug = {0}; - if (G.debug & G_DEBUG_GHOST) { - debug.flags |= GHOST_kDebugDefault; - } - if (G.debug & G_DEBUG_WINTAB) { - debug.flags |= GHOST_kDebugWintab; - } - GHOST_SystemInitDebug(g_system, debug); + GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); - if (C != NULL) { - GHOST_AddEventConsumer(g_system, consumer); - } + g_system = GHOST_CreateSystem(); - if (wm_init_state.native_pixels) { - GHOST_UseNativePixels(); - } + GHOST_Debug debug = {0}; + if (G.debug & G_DEBUG_GHOST) { + debug.flags |= GHOST_kDebugDefault; + } + if (G.debug & G_DEBUG_WINTAB) { + debug.flags |= GHOST_kDebugWintab; + } + GHOST_SystemInitDebug(g_system, debug); + + GHOST_AddEventConsumer(g_system, consumer); + + if (wm_init_state.native_pixels) { + GHOST_UseNativePixels(); + } + + GHOST_UseWindowFocus(wm_init_state.window_focus); +} - GHOST_UseWindowFocus(wm_init_state.window_focus); +/* TODO move this to wm_init_exit.c. */ +void wm_ghost_init_background(void) +{ + if (g_system) { + return; } + + GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); + + g_system = GHOST_CreateSystemBackground(); + + GHOST_Debug debug = {0}; + if (G.debug & G_DEBUG_GHOST) { + debug.flags |= GHOST_kDebugDefault; + } + GHOST_SystemInitDebug(g_system, debug); } void wm_ghost_exit(void) @@ -1932,6 +1953,9 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm, uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2]) { + /* WARNING: Reading from the front-buffer immediately after drawing may fail, + * for a slower but more reliable version of this function #WM_window_pixels_read_offscreen + * should be preferred. See it's comments for details on why it's needed, see also T98462. */ bool setup_context = wm->windrawable != win; if (setup_context) { @@ -2013,36 +2037,40 @@ void WM_init_native_pixels(bool do_it) void WM_init_tablet_api(void) { - if (g_system) { - switch (U.tablet_api) { - case USER_TABLET_NATIVE: - GHOST_SetTabletAPI(g_system, GHOST_kTabletWinPointer); - break; - case USER_TABLET_WINTAB: - GHOST_SetTabletAPI(g_system, GHOST_kTabletWintab); - break; - case USER_TABLET_AUTOMATIC: - default: - GHOST_SetTabletAPI(g_system, GHOST_kTabletAutomatic); - break; - } + if (UNLIKELY(!g_system)) { + return; + } + + switch (U.tablet_api) { + case USER_TABLET_NATIVE: + GHOST_SetTabletAPI(g_system, GHOST_kTabletWinPointer); + break; + case USER_TABLET_WINTAB: + GHOST_SetTabletAPI(g_system, GHOST_kTabletWintab); + break; + case USER_TABLET_AUTOMATIC: + default: + GHOST_SetTabletAPI(g_system, GHOST_kTabletAutomatic); + break; } } void WM_cursor_warp(wmWindow *win, int x, int y) { - if (win && win->ghostwin) { - int oldx = x, oldy = y; + if (!(win && win->ghostwin)) { + return; + } - wm_cursor_position_to_ghost_client_coords(win, &x, &y); - GHOST_SetCursorPosition(g_system, win->ghostwin, x, y); + int oldx = x, oldy = y; - win->eventstate->prev_xy[0] = oldx; - win->eventstate->prev_xy[1] = oldy; + wm_cursor_position_to_ghost_client_coords(win, &x, &y); + GHOST_SetCursorPosition(g_system, win->ghostwin, x, y); - win->eventstate->xy[0] = oldx; - win->eventstate->xy[1] = oldy; - } + win->eventstate->prev_xy[0] = oldx; + win->eventstate->prev_xy[1] = oldy; + + win->eventstate->xy[0] = oldx; + win->eventstate->xy[1] = oldy; } /** \} */ diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h index 1bc983f20ad..1558fe4004e 100644 --- a/source/blender/windowmanager/message_bus/wm_message_bus.h +++ b/source/blender/windowmanager/message_bus/wm_message_bus.h @@ -66,7 +66,7 @@ typedef struct wmMsg { } wmMsg; typedef struct wmMsgSubscribeKey { - /** Linked list for predicable ordering, otherwise we would depend on #GHash bucketing. */ + /** Linked list for predictable ordering, otherwise we would depend on #GHash bucketing. */ struct wmMsgSubscribeKey *next, *prev; ListBase values; /* over-alloc, eg: wmMsgSubscribeKey_RNA */ diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 3644aa085f7..036a34a5140 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -20,6 +20,7 @@ extern "C" { * need to event handling. */ void wm_ghost_init(bContext *C); +void wm_ghost_init_background(void); void wm_ghost_exit(void); /** diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index b9912929a54..0e9c3a853aa 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -3,7 +3,6 @@ blender_include_dirs( ../../intern/clog - ../../intern/glew-mx ../../intern/guardedalloc ../blender/blenkernel ../blender/blenlib @@ -22,6 +21,10 @@ set(LIB bf_windowmanager ) +if(HAVE_FEENABLEEXCEPT) + add_definitions(-DHAVE_FEENABLEEXCEPT) +endif() + if(WITH_TBB) # Force TBB libraries to be in front of MKL (part of OpenImageDenoise), so # that it is initialized before MKL and static library initialization order @@ -298,47 +301,53 @@ set(BLENDER_TEXT_FILES # ----------------------------------------------------------------------------- -# Platform Specific Var: TARGETDIR_VER +# Platform specific target destinations for version dir, libs, bpy, text files. if(UNIX AND NOT APPLE) if(WITH_PYTHON_MODULE) if(WITH_INSTALL_PORTABLE) + set(TARGETDIR_BPY .) set(TARGETDIR_VER ${BLENDER_VERSION}) + set(TARGETDIR_LIB lib) else() + set(TARGETDIR_BPY ${PYTHON_SITE_PACKAGES}) set(TARGETDIR_VER ${PYTHON_SITE_PACKAGES}/${BLENDER_VERSION}) + set(TARGETDIR_LIB ${PYTHON_SITE_PACKAGES}/lib) endif() else() if(WITH_INSTALL_PORTABLE) set(TARGETDIR_VER ${BLENDER_VERSION}) + set(TARGETDIR_TEXT .) + set(TARGETDIR_LIB lib) else() set(TARGETDIR_VER share/blender/${BLENDER_VERSION}) + set(TARGETDIR_TEXT share/doc/blender) endif() endif() elseif(WIN32) set(TARGETDIR_VER ${BLENDER_VERSION}) + set(TARGETDIR_TEXT .) + set(TARGETDIR_LIB .) elseif(APPLE) if(WITH_PYTHON_MODULE) if(WITH_INSTALL_PORTABLE) - set(BPY_INSTALL_DIR) set(TARGETDIR_VER $<TARGET_FILE_DIR:blender>/../Resources/${BLENDER_VERSION}) - # Keep the `BLENDER_VERSION` folder and bpy.so in the build folder. - set(INSTALL_BPY_TO_SITE_PACKAGES OFF) + set(TARGETDIR_LIB lib) else() - # Parent directory of bpy.so for installation. - set(BPY_INSTALL_DIR ${PYTHON_LIBPATH}/site-packages) - # Defined in terms of site-packages since the site-packages + # Paths defined in terms of site-packages since the site-packages # directory can be a symlink (brew for example). - set(TARGETDIR_VER "${BPY_INSTALL_DIR}/../Resources/${BLENDER_VERSION}") - set(INSTALL_BPY_TO_SITE_PACKAGES ON) + set(TARGETDIR_BPY ${PYTHON_LIBPATH}/site-packages) + set(TARGETDIR_VER ${TARGETDIR_BPY}/../Resources/${BLENDER_VERSION}) + set(TARGETDIR_LIB ${TARGETDIR_BPY}/lib) endif() else() set(TARGETDIR_VER Blender.app/Contents/Resources/${BLENDER_VERSION}) + set(TARGETDIR_LIB Blender.app/Contents/Resources/lib) + set(TARGETDIR_TEXT Blender.app/Contents/Resources/text) endif() - # License, copyright, readme files. - set(BLENDER_TEXT_FILES_DESTINATION "${TARGETDIR_VER}/../text") - set(MAC_BLENDER_TARGET_DYLIBS_DIR "${TARGETDIR_VER}/lib") + # Skip relinking on cpack / install set_target_properties(blender PROPERTIES BUILD_WITH_INSTALL_RPATH true) endif() @@ -472,17 +481,24 @@ if(UNIX AND NOT APPLE) endif() endif() + if(PLATFORM_BUNDLED_LIBRARIES AND TARGETDIR_LIB) + install( + FILES ${PLATFORM_BUNDLED_LIBRARIES} + DESTINATION ${TARGETDIR_LIB} + ) + endif() + # there are a few differences between portable and system install if(WITH_PYTHON_MODULE) if(WITH_INSTALL_PORTABLE) install( TARGETS blender - DESTINATION "." + DESTINATION ${TARGETDIR_BPY} ) else() install( TARGETS blender - LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES} + LIBRARY DESTINATION ${TARGETDIR_BPY} ) endif() # none of the other files are needed currently @@ -521,9 +537,23 @@ if(UNIX AND NOT APPLE) ${CMAKE_SOURCE_DIR}/release/bin/blender-softwaregl DESTINATION "." ) - endif() - set(BLENDER_TEXT_FILES_DESTINATION ".") + # Remove from old location, so existing builds don't start with software + # OpenGL now that the lib/ folder is used for other libraries. + install( + CODE + "file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libGL.so)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libGL.so.1)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libGL.so.1.5.0)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libGLU.so)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libGLU.so.1)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libGLU.so.1.3.1)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libglapi.so)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libglapi.so.0)\n + file(REMOVE ${CMAKE_BINARY_DIR}/bin/lib/libglapi.so.0.0.0)\n + " + ) + endif() else() # main blender binary install( @@ -557,7 +587,6 @@ if(UNIX AND NOT APPLE) DESTINATION bin ) endif() - set(BLENDER_TEXT_FILES_DESTINATION share/doc/blender) endif() if(WITH_PYTHON) @@ -717,20 +746,22 @@ if(UNIX AND NOT APPLE) ) endif() elseif(WIN32) - - set(BLENDER_TEXT_FILES_DESTINATION ".") + install( + FILES ${LIBDIR}/epoxy/bin/epoxy-0.dll + DESTINATION ${TARGETDIR_LIB} + ) if(WITH_OPENMP AND MSVC_CLANG) install( FILES ${CLANG_OPENMP_DLL} - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) endif() if(WITH_FFTW3) install( FILES ${LIBDIR}/fftw3/lib/libfftw3-3.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) endif() if(MSVC_ASAN) @@ -742,12 +773,12 @@ elseif(WIN32) endif() install( FILES ${ASAN_DLL} - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( FILES ${ASAN_DEBUG_DLL} - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Debug ) unset(ASAN_DLL) @@ -757,16 +788,16 @@ elseif(WIN32) if(WITH_GMP) install( FILES ${LIBDIR}/gmp/lib/libgmp-10.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) install( FILES ${LIBDIR}/gmp/lib/libgmpxx.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( FILES ${LIBDIR}/gmp/lib/libgmpxx_d.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Debug ) endif() @@ -785,12 +816,12 @@ elseif(WIN32) if(WITH_OPENVDB) install( FILES ${LIBDIR}/openvdb/bin/openvdb.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( FILES ${LIBDIR}/openvdb/bin/openvdb_d.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Debug ) endif() @@ -802,14 +833,14 @@ elseif(WIN32) install( FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python${_PYTHON_VERSION_NO_DOTS}.dll ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python3.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python${_PYTHON_VERSION_NO_DOTS}_d.dll ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python3_d.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Debug ) endif() @@ -871,13 +902,13 @@ elseif(WIN32) if(WINDOWS_PYTHON_DEBUG) install( FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/libs/python${_PYTHON_VERSION_NO_DOTS}.pdb - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/libs/python${_PYTHON_VERSION_NO_DOTS}_d.pdb - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Debug ) endif() @@ -886,18 +917,6 @@ elseif(WIN32) unset(_PYTHON_VERSION_NO_DOTS) endif() - # EGL Runtime Components - if(WITH_GL_EGL) - if(WIN32) - install(FILES "${OPENGLES_DLL}" DESTINATION ".") - install(FILES "${OPENGLES_EGL_DLL}" DESTINATION ".") - - if(WITH_GL_ANGLE) - install(FILES "${D3DCOMPILER_DLL}" DESTINATION ".") - endif() - endif() - endif() - if(WITH_CODEC_FFMPEG) # Filenames change slightly between ffmpeg versions # check both 5.0 and fallback to 4.4 to ease the transition @@ -911,7 +930,7 @@ elseif(WIN32) ${LIBDIR}/ffmpeg/lib/avutil-57.dll ${LIBDIR}/ffmpeg/lib/swscale-6.dll ${LIBDIR}/ffmpeg/lib/swresample-4.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) else() install( @@ -922,7 +941,7 @@ elseif(WIN32) ${LIBDIR}/ffmpeg/lib/avutil-56.dll ${LIBDIR}/ffmpeg/lib/swscale-5.dll ${LIBDIR}/ffmpeg/lib/swresample-3.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) endif() endif() @@ -930,13 +949,13 @@ elseif(WIN32) install( FILES ${LIBDIR}/tbb/bin/tbb.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( FILES ${LIBDIR}/tbb/bin/tbb_debug.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Debug ) endif() @@ -945,14 +964,14 @@ elseif(WIN32) FILES ${LIBDIR}/tbb/bin/tbbmalloc.dll ${LIBDIR}/tbb/bin/tbbmalloc_proxy.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( FILES ${LIBDIR}/tbb/bin/tbbmalloc_debug.dll ${LIBDIR}/tbb/bin/tbbmalloc_proxy_debug.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} CONFIGURATIONS Debug ) list(APPEND LIB ${TBB_MALLOC_LIBRARIES}) @@ -961,7 +980,7 @@ elseif(WIN32) if(WITH_CODEC_SNDFILE) install( FILES ${LIBDIR}/sndfile/lib/libsndfile-1.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) endif() @@ -969,14 +988,14 @@ elseif(WIN32) install( FILES ${LIBDIR}/openal/lib/OpenAL32.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) endif() if(WITH_SDL) install( FILES ${LIBDIR}/sdl/lib/SDL2.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) endif() @@ -986,7 +1005,7 @@ elseif(WIN32) ${LIBDIR}/audaspace/lib/audaspace.dll ${LIBDIR}/audaspace/lib/audaspace-c.dll ${LIBDIR}/audaspace/lib/audaspace-py.dll - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) endif() @@ -998,7 +1017,7 @@ elseif(WIN32) ${CMAKE_SOURCE_DIR}/release/windows/batch/blender_factory_startup.cmd ${CMAKE_SOURCE_DIR}/release/windows/batch/blender_oculus.cmd ${CMAKE_SOURCE_DIR}/release/windows/batch/oculus.json - DESTINATION "." + DESTINATION ${TARGETDIR_LIB} ) if(WITH_BLENDER_THUMBNAILER) @@ -1096,17 +1115,10 @@ elseif(APPLE) ) endif() - if(WITH_OPENMP AND OPENMP_CUSTOM) + if(PLATFORM_BUNDLED_LIBRARIES AND TARGETDIR_LIB) install( - FILES "${OpenMP_LIBRARY}" - DESTINATION "${MAC_BLENDER_TARGET_DYLIBS_DIR}" - ) - endif() - - if(WITH_COMPILER_ASAN) - install( - FILES "${COMPILER_ASAN_LIBRARY}" - DESTINATION "${MAC_BLENDER_TARGET_DYLIBS_DIR}" + FILES ${PLATFORM_BUNDLED_LIBRARIES} + DESTINATION ${TARGETDIR_LIB} ) endif() @@ -1118,6 +1130,7 @@ elseif(APPLE) ${TARGETDIR_VER}/python/lib ) + # Install Python executable. install( PROGRAMS ${PYTHON_EXECUTABLE} DESTINATION ${TARGETDIR_VER}/python/bin @@ -1133,13 +1146,11 @@ elseif(APPLE) unset(_py_inc_suffix) endif() - if(WITH_PYTHON_MODULE) - if(INSTALL_BPY_TO_SITE_PACKAGES) - install( - TARGETS blender - LIBRARY DESTINATION ${BPY_INSTALL_DIR} - ) - endif() + if(WITH_PYTHON_MODULE AND TARGETDIR_BPY) + install( + TARGETS blender + LIBRARY DESTINATION ${TARGETDIR_BPY} + ) endif() if(WITH_DRACO) @@ -1153,7 +1164,7 @@ endif() # ----------------------------------------------------------------------------- # Generic Install, for all targets -if(DEFINED BLENDER_TEXT_FILES_DESTINATION) +if(DEFINED TARGETDIR_TEXT) configure_file( ${CMAKE_SOURCE_DIR}/release/text/readme.html @@ -1166,13 +1177,13 @@ if(DEFINED BLENDER_TEXT_FILES_DESTINATION) install( FILES ${BLENDER_TEXT_FILES} - DESTINATION "${BLENDER_TEXT_FILES_DESTINATION}" + DESTINATION "${TARGETDIR_TEXT}" ) install( DIRECTORY ${CMAKE_SOURCE_DIR}/release/license - DESTINATION "${BLENDER_TEXT_FILES_DESTINATION}" + DESTINATION "${TARGETDIR_TEXT}" ) endif() @@ -1180,7 +1191,7 @@ endif() delayed_do_install(${TARGETDIR_VER}) unset(BLENDER_TEXT_FILES) -unset(BLENDER_TEXT_FILES_DESTINATION) +unset(TARGETDIR_TEXT) # ----------------------------------------------------------------------------- diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 76423d7ba43..c016372e6b0 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -69,11 +69,10 @@ static void sig_handle_fpe(int UNUSED(sig)) # if !defined(WITH_HEADLESS) static void sig_handle_blender_esc(int sig) { - static int count = 0; - G.is_break = true; /* forces render loop to read queue, not sure if its needed */ if (sig == 2) { + static int count = 0; if (count) { printf("\nBlender killed\n"); exit(2); @@ -244,11 +243,9 @@ void main_signal_setup_background(void) /* for all platforms, even windows has it! */ BLI_assert(G.background); -# if !defined(WITH_HEADLESS) /* Support pressing `Ctrl-C` to close Blender in background-mode. * Useful to be able to cancel a render operation. */ signal(SIGINT, sig_handle_blender_esc); -# endif } void main_signal_setup_fpe(void) @@ -258,7 +255,7 @@ void main_signal_setup_fpe(void) * set breakpoints on sig_handle_fpe */ signal(SIGFPE, sig_handle_fpe); -# if defined(__linux__) && defined(__GNUC__) +# if defined(__linux__) && defined(__GNUC__) && defined(HAVE_FEENABLEEXCEPT) feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); # endif /* defined(__linux__) && defined(__GNUC__) */ # if defined(OSX_SSE_FPE) diff --git a/source/tools b/source/tools -Subproject da8bdd7244c7b6c2eadf4c949ff391d0cc43027 +Subproject 2a541f164a222ef7bcd036d37687738acee8d94 |