diff options
author | Hans Goudey <h.goudey@me.com> | 2022-06-24 00:59:05 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-06-24 00:59:49 +0300 |
commit | 18f78ba33cfe4e369135e1c9c80f88bb24a90f2e (patch) | |
tree | 2257aee06794617595229a012a4fd4211488decb /source | |
parent | 547139c59c27dba585777a2c66e86e3e4cb92425 (diff) | |
parent | 7a05b5d2aaf6854a34c8eb796011a9ec90cc0281 (diff) |
Merge branch 'temp-legacy-mesh-format-option' into refactor-mesh-bevel-weight-generic
Diffstat (limited to 'source')
999 files changed, 22359 insertions, 14113 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index efa2be9e48c..8ba6e7318bb 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -96,15 +96,15 @@ set(SRC_DNA_DEFAULTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_collection_defaults.h - ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_defaults.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lattice_defaults.h - ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lightprobe_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_defaults.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lightprobe_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_linestyle_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_material_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mesh_defaults.h diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index e5e2b1711b1..83ca9158efc 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -14,6 +14,15 @@ extern "C" { #endif +/* Name of subfolder inside BLENDER_DATAFILES that contains font files. */ +#define BLF_DATAFILES_FONTS_DIR "fonts" + +/* File name of the default variable-width font. */ +#define BLF_DEFAULT_PROPORTIONAL_FONT "droidsans.ttf" + +/* File name of the default fixed-pitch font. */ +#define BLF_DEFAULT_MONOSPACED_FONT "bmonofont-i18n.ttf" + /* enable this only if needed (unused circa 2016) */ #define BLF_BLUR_ENABLE 0 @@ -37,12 +46,14 @@ void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void)); */ int BLF_load(const char *name) ATTR_NONNULL(); int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL(); +bool BLF_is_loaded(const char *name) ATTR_NONNULL(); int BLF_load_unique(const char *name) ATTR_NONNULL(); int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL(); void BLF_unload(const char *name) ATTR_NONNULL(); void BLF_unload_id(int fontid); +void BLF_unload_all(void); char *BLF_display_name_from_file(const char *filepath); @@ -312,25 +323,35 @@ int BLF_set_default(void); int BLF_load_default(bool unique); int BLF_load_mono_default(bool unique); +void BLF_load_font_stack(void); #ifdef DEBUG void BLF_state_print(int fontid); #endif -/* font->flags. */ -#define BLF_ROTATION (1 << 0) -#define BLF_CLIPPING (1 << 1) -#define BLF_SHADOW (1 << 2) -// #define BLF_FLAG_UNUSED_3 (1 << 3) /* dirty */ -#define BLF_MATRIX (1 << 4) -#define BLF_ASPECT (1 << 5) -#define BLF_WORD_WRAP (1 << 6) -#define BLF_MONOCHROME (1 << 7) /* no-AA */ -#define BLF_HINTING_NONE (1 << 8) -#define BLF_HINTING_SLIGHT (1 << 9) -#define BLF_HINTING_FULL (1 << 10) -#define BLF_BOLD (1 << 11) -#define BLF_ITALIC (1 << 12) +/** #FontBLF.flags. */ +enum { + BLF_ROTATION = 1 << 0, + BLF_CLIPPING = 1 << 1, + BLF_SHADOW = 1 << 2, + // BLF_FLAG_UNUSED_3 = 1 << 3, /* dirty */ + BLF_MATRIX = 1 << 4, + BLF_ASPECT = 1 << 5, + BLF_WORD_WRAP = 1 << 6, + /** No anti-aliasing. */ + BLF_MONOCHROME = 1 << 7, + BLF_HINTING_NONE = 1 << 8, + BLF_HINTING_SLIGHT = 1 << 9, + BLF_HINTING_FULL = 1 << 10, + BLF_BOLD = 1 << 11, + BLF_ITALIC = 1 << 12, + /** Intended USE is monospaced, regardless of font type. */ + BLF_MONOSPACED = 1 << 13, + /** A font within the default stack of fonts. */ + BLF_DEFAULT = 1 << 14, + /** Must only be used as last font in the stack. */ + BLF_LAST_RESORT = 1 << 15, +}; #define BLF_DRAW_STR_DUMMY_MAX 1024 diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index a944ab332bd..a1fcc17ca3f 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -34,13 +34,6 @@ #include "blf_internal.h" #include "blf_internal_types.h" -/* Max number of font in memory. - * Take care that now every font have 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 16 - #define BLF_RESULT_CHECK_INIT(r_info) \ if (r_info) { \ memset(r_info, 0, sizeof(*(r_info))); \ @@ -48,7 +41,7 @@ ((void)0) /* Font array. */ -static FontBLF *global_font[BLF_MAX_FONT] = {NULL}; +FontBLF *global_font[BLF_MAX_FONT] = {NULL}; /* XXX: should these be made into global_font_'s too? */ @@ -134,6 +127,11 @@ bool BLF_has_glyph(int fontid, unsigned int unicode) return false; } +bool BLF_is_loaded(const char *name) +{ + return blf_search(name) >= 0; +} + int BLF_load(const char *name) { /* check if we already load this font. */ @@ -255,6 +253,20 @@ void BLF_unload_id(int fontid) } } +void BLF_unload_all(void) +{ + for (int i = 0; i < BLF_MAX_FONT; i++) { + FontBLF *font = global_font[i]; + if (font) { + blf_font_free(font); + global_font[i] = NULL; + } + } + blf_mono_font = -1; + blf_mono_font_render = -1; + BLF_default_set(-1); +} + void BLF_enable(int fontid, int option) { FontBLF *font = blf_get(fontid); diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index a170f27d247..3e2927d581e 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -18,6 +18,7 @@ #include FT_FREETYPE_H #include FT_GLYPH_H +#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */ #include "MEM_guardedalloc.h" @@ -1288,6 +1289,25 @@ FontBLF *blf_font_new(const char *name, const char *filepath) font->filepath = BLI_strdup(filepath); blf_font_fill(font); + /* Save TrueType table with bits to quickly test most unicode block coverage. */ + TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2); + if (os2_table) { + 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; + } + + /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ + if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU && + font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) { + font->flags |= BLF_LAST_RESORT; + } + + if (FT_IS_FIXED_WIDTH(font->face)) { + font->flags |= BLF_MONOSPACED; + } + if (FT_HAS_KERNING(font->face)) { /* Create kerning cache table and fill with value indicating "unset". */ font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__); diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index 3a68423e64e..1bde25b5776 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -11,13 +11,14 @@ #include "BLF_api.h" +#include "BLI_fileops.h" #include "BLI_path_util.h" #include "BKE_appdir.h" static int blf_load_font_default(const char *filename, const bool unique) { - const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "fonts"); + const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR); if (dir == NULL) { fprintf(stderr, "%s: 'fonts' data path not found for '%s', will not be able to display text\n", @@ -34,10 +35,46 @@ static int blf_load_font_default(const char *filename, const bool unique) int BLF_load_default(const bool unique) { - return blf_load_font_default("droidsans.ttf", unique); + int font_id = blf_load_font_default(BLF_DEFAULT_PROPORTIONAL_FONT, unique); + BLF_enable(font_id, BLF_DEFAULT); + return font_id; } int BLF_load_mono_default(const bool unique) { - return blf_load_font_default("bmonofont-i18n.ttf", unique); + int font_id = blf_load_font_default(BLF_DEFAULT_MONOSPACED_FONT, unique); + BLF_enable(font_id, BLF_MONOSPACED | BLF_DEFAULT); + return font_id; +} + +void BLF_load_font_stack() +{ + /* Load these if not already, might have been replaced by user custom. */ + 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)) { + struct direntry *dir; + uint num_files = BLI_filelist_dir_contents(path, &dir); + for (int f = 0; f < num_files; f++) { + if (!FILENAME_IS_CURRPAR(dir[f].relname) && !BLI_is_dir(dir[f].path)) { + if (!BLF_is_loaded(dir[f].path)) { + int font_id = BLF_load(dir[f].path); + if (font_id == -1) { + fprintf(stderr, "Unable to load font: %s\n", dir[f].path); + } + else { + BLF_enable(font_id, BLF_DEFAULT); + /* TODO: FontBLF will later load FT_Face on demand. When this is in + * place we can drop this face now since we have all needed data. */ + } + } + } + } + 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 2694b179a11..ed30cca4da2 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -39,6 +39,7 @@ #include "BLI_math_vector.h" #include "BLI_strict_flags.h" +#include "BLI_string_utf8.h" /* -------------------------------------------------------------------- */ /** \name Internal Utilities @@ -222,6 +223,335 @@ 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. */ + +typedef struct eUnicodeBlock { + unsigned int first; + unsigned int 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[] = { + /* Must be in ascending order by start of range. */ + {0x0, 0x7F, 0}, /* Basic Latin. */ + {0x80, 0xFF, 1}, /* Latin-1 Supplement. */ + {0x100, 0x17F, 2}, /* Latin Extended-A. */ + {0x180, 0x24F, 3}, /* Latin Extended-B. */ + {0x250, 0x2AF, 4}, /* IPA Extensions. */ + {0x2B0, 0x2FF, 5}, /* Spacing Modifier Letters. */ + {0x300, 0x36F, 6}, /* Combining Diacritical Marks. */ + {0x370, 0x3FF, 7}, /* Greek. */ + {0x400, 0x52F, 9}, /* Cyrillic. */ + {0x530, 0x58F, 10}, /* Armenian. */ + {0x590, 0x5FF, 11}, /* Hebrew. */ + {0x600, 0x6FF, 13}, /* Arabic. */ + {0x700, 0x74F, 71}, /* Syriac. */ + {0x750, 0x77F, 13}, /* Arabic Supplement. */ + {0x780, 0x7BF, 72}, /* Thaana. */ + {0x7C0, 0x7FF, 14}, /* NKo. */ + {0x800, 0x83F, -1}, /* Samaritan. */ + {0x840, 0x85F, -1}, /* Mandaic. */ + {0x900, 0x97F, 15}, /* Devanagari. */ + {0x980, 0x9FF, 16}, /* Bengali. */ + {0xA00, 0xA7F, 17}, /* Gurmukhi. */ + {0xA80, 0xAFF, 18}, /* Gujarati. */ + {0xB00, 0xB7F, 19}, /* Oriya. */ + {0xB80, 0xBFF, 20}, /* Tamil. */ + {0xC00, 0xC7F, 21}, /* Telugu. */ + {0xC80, 0xCFF, 22}, /* Kannada. */ + {0xD00, 0xD7F, 23}, /* Malayalam. */ + {0xD80, 0xDFF, 73}, /* Sinhala. */ + {0xE00, 0xE7F, 24}, /* Thai. */ + {0xE80, 0xEFF, 25}, /* Lao. */ + {0xF00, 0xFFF, 70}, /* Tibetan. */ + {0x1000, 0x109F, 74}, /* Myanmar. */ + {0x10A0, 0x10FF, 26}, /* Georgian. */ + {0x1100, 0x11FF, 28}, /* Hangul Jamo. */ + {0x1200, 0x139F, 75}, /* Ethiopic. */ + {0x13A0, 0x13FF, 76}, /* Cherokee. */ + {0x1400, 0x167F, 77}, /* Canadian Aboriginal. */ + {0x1680, 0x169F, 78}, /* Ogham. */ + {0x16A0, 0x16FF, 79}, /* unic. */ + {0x1700, 0x171F, 84}, /* Tagalog. */ + {0x1720, 0x173F, 84}, /* Hanunoo. */ + {0x1740, 0x175F, 84}, /* Buhid. */ + {0x1760, 0x177F, 84}, /* Tagbanwa. */ + {0x1780, 0x17FF, 80}, /* Khmer. */ + {0x1800, 0x18AF, 81}, /* Mongolian. */ + {0x1900, 0x194F, 93}, /* Limbu. */ + {0x1950, 0x197F, 94}, /* Tai Le. */ + {0x1980, 0x19DF, 95}, /* New Tai Lue". */ + {0x19E0, 0x19FF, 80}, /* Khmer. */ + {0x1A00, 0x1A1F, 96}, /* Buginese. */ + {0x1A20, 0x1AAF, -1}, /* Tai Tham. */ + {0x1B00, 0x1B7F, 27}, /* Balinese. */ + {0x1B80, 0x1BBF, 112}, /* Sundanese. */ + {0x1BC0, 0x1BFF, -1}, /* Batak. */ + {0x1C00, 0x1C4F, 113}, /* Lepcha. */ + {0x1C50, 0x1C7F, 114}, /* Ol Chiki. */ + {0x1D00, 0x1DBF, 4}, /* IPA Extensions. */ + {0x1DC0, 0x1DFF, 6}, /* Combining Diacritical Marks. */ + {0x1E00, 0x1EFF, 29}, /* Latin Extended Additional. */ + {0x1F00, 0x1FFF, 30}, /* Greek Extended. */ + {0x2000, 0x206F, 31}, /* General Punctuation. */ + {0x2070, 0x209F, 32}, /* Superscripts And Subscripts. */ + {0x20A0, 0x20CF, 33}, /* Currency Symbols. */ + {0x20D0, 0x20FF, 34}, /* Combining Diacritical Marks For Symbols. */ + {0x2100, 0x214F, 35}, /* Letterlike Symbols. */ + {0x2150, 0x218F, 36}, /* Number Forms. */ + {0x2190, 0x21FF, 37}, /* Arrows. */ + {0x2200, 0x22FF, 38}, /* Mathematical Operators. */ + {0x2300, 0x23FF, 39}, /* Miscellaneous Technical. */ + {0x2400, 0x243F, 40}, /* Control Pictures. */ + {0x2440, 0x245F, 41}, /* Optical Character Recognition. */ + {0x2460, 0x24FF, 42}, /* Enclosed Alphanumerics. */ + {0x2500, 0x257F, 43}, /* Box Drawing. */ + {0x2580, 0x259F, 44}, /* Block Elements. */ + {0x25A0, 0x25FF, 45}, /* Geometric Shapes. */ + {0x2600, 0x26FF, 46}, /* Miscellaneous Symbols. */ + {0x2700, 0x27BF, 47}, /* Dingbats. */ + {0x27C0, 0x27EF, 38}, /* Mathematical Operators. */ + {0x27F0, 0x27FF, 37}, /* Arrows. */ + {0x2800, 0x28FF, 82}, /* Braille. */ + {0x2900, 0x297F, 37}, /* Arrows. */ + {0x2980, 0x2AFF, 38}, /* Mathematical Operators. */ + {0x2B00, 0x2BFF, 37}, /* Arrows. */ + {0x2C00, 0x2C5F, 97}, /* Glagolitic. */ + {0x2C60, 0x2C7F, 29}, /* Latin Extended Additional. */ + {0x2C80, 0x2CFF, 8}, /* Coptic. */ + {0x2D00, 0x2D2F, 26}, /* Georgian. */ + {0x2D30, 0x2D7F, 98}, /* Tifinagh. */ + {0x2D80, 0x2DDF, 75}, /* Ethiopic. */ + {0x2DE0, 0x2DFF, 9}, /* Cyrillic. */ + {0x2E00, 0x2E7F, 31}, /* General Punctuation. */ + {0x2E80, 0x2FFF, 59}, /* CJK Unified Ideographs. */ + {0x3000, 0x303F, 48}, /* CJK Symbols And Punctuation. */ + {0x3040, 0x309F, 49}, /* Hiragana. */ + {0x30A0, 0x30FF, 50}, /* Katakana. */ + {0x3100, 0x312F, 51}, /* Bopomofo. */ + {0x3130, 0x318F, 52}, /* Hangul Compatibility Jamo. */ + {0x3190, 0x319F, 59}, /* CJK Unified Ideographs. */ + {0x31A0, 0x31BF, 51}, /* Bopomofo. */ + {0x31C0, 0x31EF, 59}, /* CJK Unified Ideographs. */ + {0x31F0, 0x31FF, 50}, /* Katakana. */ + {0x3200, 0x32FF, 54}, /* Enclosed CJK Letters And Months. */ + {0x3300, 0x33FF, 55}, /* CJK Compatibility. */ + {0x3400, 0x4DBF, 59}, /* CJK Unified Ideographs. */ + {0x4DC0, 0x4DFF, 99}, /* Yijing. */ + {0x4E00, 0x9FFF, 59}, /* CJK Unified Ideographs. */ + {0xA000, 0xA4CF, 83}, /* Yi. */ + {0xA4D0, 0xA4FF, -1}, /* Lisu. */ + {0xA500, 0xA63F, 12}, /* Vai. */ + {0xA640, 0xA69F, 9}, /* Cyrillic. */ + {0xA6A0, 0xA6FF, -1}, /* Bamum. */ + {0xA700, 0xA71F, 5}, /* Spacing Modifier Letters. */ + {0xA720, 0xA7FF, 29}, /* Latin Extended Additional. */ + {0xA800, 0xA82F, 100}, /* Syloti Nagri. */ + {0xA840, 0xA87F, 53}, /* Phags-pa. */ + {0xA880, 0xA8DF, 115}, /* Saurashtra. */ + {0xA900, 0xA92F, 116}, /* Kayah Li. */ + {0xA930, 0xA95F, 117}, /* Rejang. */ + {0xA960, 0xA97F, 56}, /* Hangul Syllables. */ + {0xA980, 0xA9DF, -1}, /* Javanese. */ + {0xA9E0, 0xA9FF, 74}, /* Myanmar. */ + {0xAA00, 0xAA5F, 118}, /* Cham. */ + {0xAA60, 0xAA7F, 74}, /* Myanmar. */ + {0xAA80, 0xAADF, -1}, /* Tai Viet. */ + {0xAAE0, 0xAAFF, -1}, /* Meetei Mayek. */ + {0xAB00, 0xAB2F, 75}, /* Ethiopic. */ + {0xAB70, 0xABBF, 76}, /* Cherokee. */ + {0xABC0, 0xABFF, -1}, /* Meetei Mayek. */ + {0xAC00, 0xD7AF, 56}, /* Hangul Syllables. */ + {0xD800, 0xDFFF, 57}, /* Non-Plane 0. */ + {0xE000, 0xF6FF, 60}, /* Private Use Area. */ + {0xE700, 0xEFFF, -1}, /* MS Wingdings. */ + {0xF000, 0xF8FF, -1}, /* MS Symbols. */ + {0xF900, 0xFAFF, 61}, /* CJK Compatibility Ideographs. */ + {0xFB00, 0xFB4F, 62}, /* Alphabetic Presentation Forms. */ + {0xFB50, 0xFDFF, 63}, /* Arabic Presentation Forms-A. */ + {0xFE00, 0xFE0F, 91}, /* Variation Selectors. */ + {0xFE10, 0xFE1F, 65}, /* CJK Compatibility Forms. */ + {0xFE20, 0xFE2F, 64}, /* Combining Half Marks. */ + {0xFE30, 0xFE4F, 65}, /* CJK Compatibility Forms. */ + {0xFE50, 0xFE6F, 66}, /* Small Form Variants. */ + {0xFE70, 0xFEFF, 67}, /* Arabic Presentation Forms-B. */ + {0xFF00, 0xFFEF, 68}, /* Halfwidth And Fullwidth Forms. */ + {0xFFF0, 0xFFFF, 69}, /* Specials. */ + {0x10000, 0x1013F, 101}, /* Linear B. */ + {0x10140, 0x1018F, 102}, /* Ancient Greek Numbers. */ + {0x10190, 0x101CF, 119}, /* Ancient Symbols. */ + {0x101D0, 0x101FF, 120}, /* Phaistos Disc. */ + {0x10280, 0x1029F, 121}, /* Lycian. */ + {0x102A0, 0x102DF, 121}, /* Carian. */ + {0x10300, 0x1032F, 85}, /* Old Italic. */ + {0x10330, 0x1034F, 86}, /* Gothic. */ + {0x10350, 0x1037F, -1}, /* Old Permic. */ + {0x10380, 0x1039F, 103}, /* Ugaritic. */ + {0x103A0, 0x103DF, 104}, /* Old Persian. */ + {0x10400, 0x1044F, 87}, /* Deseret. */ + {0x10450, 0x1047F, 105}, /* Shavian. */ + {0x10480, 0x104AF, 106}, /* Osmanya. */ + {0x104B0, 0x104FF, -1}, /* Osage. */ + {0x10500, 0x1052F, -1}, /* Elbasan. */ + {0x10530, 0x1056F, -1}, /* Caucasian Albanian. */ + {0x10570, 0x105BF, -1}, /* Vithkuqi. */ + {0x10600, 0x1077F, -1}, /* Linear A. */ + {0x10780, 0x107BF, 3}, /* Latin Extended-B. */ + {0x10800, 0x1083F, 107}, /* Cypriot Syllabary. */ + {0x10840, 0x1085F, -1}, /* Imperial Aramaic. */ + {0x10860, 0x1087F, -1}, /* Palmyrene. */ + {0x10880, 0x108AF, -1}, /* Nabataean. */ + {0x108E0, 0x108FF, -1}, /* Hatran. */ + {0x10900, 0x1091F, 58}, /* Phoenician. */ + {0x10920, 0x1093F, 121}, /* Lydian. */ + {0x10980, 0x1099F, -1}, /* Meroitic Hieroglyphs. */ + {0x109A0, 0x109FF, -1}, /* Meroitic Cursive. */ + {0x10A00, 0x10A5F, 108}, /* Kharoshthi. */ + {0x10A60, 0x10A7F, -1}, /* Old South Arabian. */ + {0x10A80, 0x10A9F, -1}, /* Old North Arabian. */ + {0x10AC0, 0x10AFF, -1}, /* Manichaean. */ + {0x10B00, 0x10B3F, -1}, /* Avestan. */ + {0x10B40, 0x10B5F, -1}, /* Inscriptional Parthian. */ + {0x10B60, 0x10B7F, -1}, /* Inscriptional Pahlavi. */ + {0x10B80, 0x10BAF, -1}, /* Psalter Pahlavi. */ + {0x10C00, 0x10C4F, -1}, /* Old Turkic. */ + {0x10C80, 0x10CFF, -1}, /* Old Hungarian. */ + {0x10D00, 0x10D3F, -1}, /* Hanifi Rohingya. */ + {0x108E0, 0x10E7F, -1}, /* Rumi Numeral Symbols. */ + {0x10E80, 0x10EBF, -1}, /* Yezidi. */ + {0x10F00, 0x10F2F, -1}, /* Old Sogdian. */ + {0x10F30, 0x10F6F, -1}, /* Sogdian. */ + {0x10F70, 0x10FAF, -1}, /* Old Uyghur. */ + {0x10FB0, 0x10FDF, -1}, /* Chorasmian. */ + {0x10FE0, 0x10FFF, -1}, /* Elymaic. */ + {0x11000, 0x1107F, -1}, /* Brahmi. */ + {0x11080, 0x110CF, -1}, /* Kaithi. */ + {0x110D0, 0x110FF, -1}, /* Sora Sompeng. */ + {0x11100, 0x1114F, -1}, /* Chakma. */ + {0x11150, 0x1117F, -1}, /* Mahajani. */ + {0x11180, 0x111DF, -1}, /* Sharada. */ + {0x111E0, 0x111FF, -1}, /* Sinhala Archaic Numbers. */ + {0x11200, 0x1124F, -1}, /* Khojki. */ + {0x11280, 0x112AF, -1}, /* Multani. */ + {0x112B0, 0x112FF, -1}, /* Khudawadi. */ + {0x11300, 0x1137F, -1}, /* Grantha. */ + {0x11400, 0x1147F, -1}, /* Newa. */ + {0x11480, 0x114DF, -1}, /* Tirhuta. */ + {0x11580, 0x115FF, -1}, /* Siddham. */ + {0x11600, 0x1165F, -1}, /* Modi. */ + {0x11660, 0x1167F, 81}, /* Mongolian. */ + {0x11680, 0x116CF, -1}, /* Takri. */ + {0x11700, 0x1174F, -1}, /* Ahom. */ + {0x11800, 0x1184F, -1}, /* Dogra. */ + {0x118A0, 0x118FF, -1}, /* Warang Citi. */ + {0x11900, 0x1195F, -1}, /* Dives Akuru. */ + {0x119A0, 0x119FF, -1}, /* Nandinagari. */ + {0x11A00, 0x11A4F, -1}, /* Zanabazar Square. */ + {0x11A50, 0x11AAF, -1}, /* Soyombo. */ + {0x11AB0, 0x11ABF, 77}, /* Canadian Aboriginal Syllabics. */ + {0x11AC0, 0x11AFF, -1}, /* Pau Cin Hau. */ + {0x11C00, 0x11C6F, -1}, /* Bhaiksuki. */ + {0x11C70, 0x11CBF, -1}, /* Marchen. */ + {0x11D00, 0x11D5F, -1}, /* Masaram Gondi. */ + {0x11D60, 0x11DAF, -1}, /* Gunjala Gondi. */ + {0x11EE0, 0x11EFF, -1}, /* Makasar. */ + {0x11FB0, 0x11FBF, -1}, /* Lisu. */ + {0x11FC0, 0x11FFF, 20}, /* Tamil. */ + {0x12000, 0x1254F, 110}, /* Cuneiform. */ + {0x12F90, 0x12FFF, -1}, /* Cypro-Minoan. */ + {0x13000, 0x1343F, -1}, /* Egyptian Hieroglyphs. */ + {0x14400, 0x1467F, -1}, /* Anatolian Hieroglyphs. */ + {0x16800, 0x16A3F, -1}, /* Bamum. */ + {0x16A40, 0x16A6F, -1}, /* Mro. */ + {0x16A70, 0x16ACF, -1}, /* Tangsa. */ + {0x16AD0, 0x16AFF, -1}, /* Bassa Vah. */ + {0x16B00, 0x16B8F, -1}, /* Pahawh Hmong. */ + {0x16E40, 0x16E9F, -1}, /* Medefaidrin. */ + {0x16F00, 0x16F9F, -1}, /* Miao. */ + {0x16FE0, 0x16FFF, -1}, /* Ideographic Symbols. */ + {0x17000, 0x18AFF, -1}, /* Tangut. */ + {0x1B170, 0x1B2FF, -1}, /* Nushu. */ + {0x1BC00, 0x1BC9F, -1}, /* Duployan. */ + {0x1D000, 0x1D24F, 88}, /* Musical Symbols. */ + {0x1D2E0, 0x1D2FF, -1}, /* Mayan Numerals. */ + {0x1D300, 0x1D35F, 109}, /* Tai Xuan Jing. */ + {0x1D360, 0x1D37F, 111}, /* Counting Rod Numerals. */ + {0x1D400, 0x1D7FF, 89}, /* Mathematical Alphanumeric Symbols. */ + {0x1E2C0, 0x1E2FF, -1}, /* Wancho. */ + {0x1E800, 0x1E8DF, -1}, /* Mende Kikakui. */ + {0x1E900, 0x1E95F, -1}, /* Adlam. */ + {0x1EC70, 0x1ECBF, -1}, /* Indic Siyaq Numbers. */ + {0x1F000, 0x1F02F, 122}, /* Mahjong Tiles. */ + {0x1F030, 0x1F09F, 122}, /* Domino Tiles. */ + {0x1F600, 0x1F64F, -1}, /* Emoticons. */ + {0x20000, 0x2A6DF, 59}, /* CJK Unified Ideographs. */ + {0x2F800, 0x2FA1F, 61}, /* CJK Compatibility Ideographs. */ + {0xE0000, 0xE007F, 92}, /* Tags. */ + {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) +{ + if (charcode < 0x80) { + /* Shortcut to Basic Latin. */ + return &unicode_blocks[0]; + } + + /* Binary search for other blocks. */ + + 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; + if (charcode > unicode_blocks[mid].last) { + min = mid + 1; + } + else if (charcode < unicode_blocks[mid].first) { + max = mid - 1; + } + else { + return &unicode_blocks[mid]; + } + } + + return NULL; +} + +static int blf_charcode_to_coverage_bit(uint charcode) +{ + int coverage_bit = -1; + eUnicodeBlock *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. */ + coverage_bit = 57; + } + + return coverage_bit; +} + +static bool blf_font_has_coverage_bit(FontBLF *font, int coverage_bit) +{ + if (coverage_bit < 0) { + return false; + } + return (font->UnicodeRanges[(uint)coverage_bit >> 5] & (1u << ((uint)coverage_bit % 32))); +} + /** * Return a glyph index from `charcode`. Not found returns zero, which is a valid * printable character (`.notdef` or `tofu`). Font is allowed to change here. @@ -229,8 +559,42 @@ static GlyphBLF *blf_glyph_cache_add_glyph( static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode) { FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode); - /* TODO: If not found in this font, check others, update font pointer. */ - return glyph_index; + if (glyph_index) { + return glyph_index; + } + + /* Not found in main font, so look in the others. */ + FontBLF *last_resort = NULL; + int coverage_bit = blf_charcode_to_coverage_bit(charcode); + for (int i = 0; i < BLF_MAX_FONT; i++) { + FontBLF *f = global_font[i]; + if (!f || f == *font || !(f->flags & BLF_DEFAULT)) { + continue; + } + + if (f->flags & BLF_LAST_RESORT) { + last_resort = f; + continue; + } + if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) { + glyph_index = FT_Get_Char_Index(f->face, charcode); + if (glyph_index) { + *font = f; + return glyph_index; + } + } + } + + /* Not found in the stack, return from Last Resort if there is one. */ + if (last_resort) { + glyph_index = FT_Get_Char_Index(last_resort->face, charcode); + if (glyph_index) { + *font = last_resort; + return glyph_index; + } + } + + return 0; } /** @@ -377,24 +741,24 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float /** * Transform glyph to fit nicely within a fixed column width. */ -static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, int width) +static bool blf_glyph_transform_monospace(FT_GlyphSlot glyph, int width) { if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { - int gwidth = (int)(glyph->linearHoriAdvance >> 16); - if (gwidth > width) { - float scale = (float)width / (float)gwidth; + FT_Fixed current = glyph->linearHoriAdvance; + FT_Fixed target = width << 16; /* Do math in 16.16 values. */ + if (target < current) { + const FT_Pos embolden = (FT_Pos)((current - target) >> 13); + /* Horizontally widen strokes to counteract narrowing. */ + FT_Outline_EmboldenXY(&glyph->outline, embolden, 0); + const float scale = (float)(target - (embolden << 9)) / (float)current; FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)}; - /* Narrowing all points also thins vertical strokes. */ FT_Outline_Transform(&glyph->outline, &matrix); - const FT_Pos extra_x = (int)((float)(gwidth - width) * 5.65f); - /* Horizontally widen strokes to counteract narrowing. */ - FT_Outline_EmboldenXY(&glyph->outline, extra_x, 0); } - else if (gwidth < width) { - /* Narrow glyphs only need to be centered. */ - int nudge = (width - gwidth) / 2; - FT_Outline_Translate(&glyph->outline, (FT_Pos)nudge * 64, 0); + else if (target > current) { + /* Center narrow glyphs. */ + FT_Outline_Translate(&glyph->outline, (FT_Pos)((target - current) >> 11), 0); } + glyph->advance.x = width << 6; return true; } return false; @@ -411,7 +775,9 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, i */ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, FontBLF *glyph_font, - FT_UInt glyph_index) + FT_UInt glyph_index, + uint charcode, + int fixed_width) { if (glyph_font != settings_font) { FT_Set_Char_Size(glyph_font->face, @@ -428,6 +794,10 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, return NULL; } + if ((settings_font->flags & BLF_MONOSPACED) && (settings_font != glyph_font)) { + blf_glyph_transform_monospace(glyph, BLI_wcwidth((char32_t)charcode) * fixed_width); + } + if ((settings_font->flags & BLF_ITALIC) != 0) { /* 37.5% of maximum rightward slant results in 6 degree slope, matching italic * version (`DejaVuSans-Oblique.ttf`) of our current font. But a nice median when @@ -466,7 +836,8 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode) * renderer uses a shared buffer internally. */ BLI_spin_lock(font_with_glyph->ft_lib_mutex); - FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index); + FT_GlyphSlot glyph = blf_glyph_render( + font, font_with_glyph, glyph_index, charcode, gc->fixed_width); if (glyph) { /* Save this glyph in the initial font's cache. */ diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 7754f960043..84037ff4bd0 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -14,6 +14,12 @@ struct ResultBLF; struct rctf; struct rcti; +/* Max number of fonts 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 + +extern struct FontBLF *global_font[BLF_MAX_FONT]; + void blf_batch_draw_begin(struct FontBLF *font); void blf_batch_draw(void); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 9dfcb1a4ad6..998093dae70 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -226,6 +226,11 @@ typedef struct FontBLF { /** File-path or NULL. */ char *filepath; + /* 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]; + /* aspect ratio or scale. */ float aspect[3]; diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 59f0c86684d..4274ca97fd1 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -68,8 +68,8 @@ struct Object; struct Scene; /* - * NOTE: all mface interfaces now officially operate on tessellated data. - * Also, the mface origindex layer indexes mpolys, not mfaces. + * NOTE: all #MFace interfaces now officially operate on tessellated data. + * Also, the #MFace orig-index layer indexes #MPoly, not #MFace. */ /* keep in sync with MFace/MPoly types */ diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index d5487b3558a..79d0fe6e20a 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -92,6 +92,11 @@ bool action_has_motion(const struct bAction *act); */ bool BKE_action_is_cyclic(const struct bAction *act); +/** + * Remove all fcurves from the action. + */ +void BKE_action_fcurves_clear(struct bAction *act); + /* Action Groups API ----------------- */ /** diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index cc50076e964..13eefd27bec 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -22,7 +22,7 @@ struct ID; struct ReportList; /** #Attribute.domain */ -typedef enum AttributeDomain { +typedef enum eAttrDomain { ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ ATTR_DOMAIN_POINT = 0, /* Mesh, Curve or Point Cloud Point */ ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ @@ -30,51 +30,64 @@ typedef enum AttributeDomain { ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ ATTR_DOMAIN_CURVE = 4, /* A single curve in a larger curve data-block */ ATTR_DOMAIN_INSTANCE = 5, /* Instance */ -} AttributeDomain; +} eAttrDomain; #define ATTR_DOMAIN_NUM 6 -typedef enum AttributeDomainMask { +typedef enum eAttrDomainMask { ATTR_DOMAIN_MASK_POINT = (1 << 0), ATTR_DOMAIN_MASK_EDGE = (1 << 1), ATTR_DOMAIN_MASK_FACE = (1 << 2), ATTR_DOMAIN_MASK_CORNER = (1 << 3), ATTR_DOMAIN_MASK_CURVE = (1 << 4), ATTR_DOMAIN_MASK_ALL = (1 << 5) - 1 -} AttributeDomainMask; +} eAttrDomainMask; + +#define ATTR_DOMAIN_AS_MASK(domain) ((eAttrDomainMask)((1 << (int)(domain)))) /* All domains that support color attributes. */ #define ATTR_DOMAIN_MASK_COLOR \ - ((AttributeDomainMask)((ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER))) + ((eAttrDomainMask)((ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER))) /* Attributes. */ -bool BKE_id_attributes_supported(struct ID *id); +bool BKE_id_attributes_supported(const struct ID *id); +bool BKE_attribute_allow_procedural_access(const char *attribute_name); /** * Create a new attribute layer. */ struct CustomDataLayer *BKE_id_attribute_new( - struct ID *id, const char *name, int type, AttributeDomain domain, struct ReportList *reports); -bool BKE_id_attribute_remove(struct ID *id, - struct CustomDataLayer *layer, - struct ReportList *reports); + struct ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports); +bool BKE_id_attribute_remove(struct ID *id, const char *name, struct ReportList *reports); + +/** + * Creates a duplicate attribute layer. + */ +struct CustomDataLayer *BKE_id_attribute_duplicate(struct ID *id, + const char *name, + struct ReportList *reports); struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id, const char *name, int type, - AttributeDomain domain); + eAttrDomain domain); + +struct CustomDataLayer *BKE_id_attribute_search(struct ID *id, + const char *name, + eCustomDataMask type, + eAttrDomainMask domain_mask); -AttributeDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer); +eAttrDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer); int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer); -bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer); +bool BKE_id_attribute_required(const struct ID *id, const char *name); bool BKE_id_attribute_rename(struct ID *id, - struct CustomDataLayer *layer, + const char *old_name, const char *new_name, struct ReportList *reports); int BKE_id_attributes_length(const struct ID *id, - AttributeDomainMask domain_mask, - CustomDataMask mask); + eAttrDomainMask domain_mask, + eCustomDataMask mask); struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id); void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer); @@ -83,24 +96,24 @@ int *BKE_id_attributes_active_index_p(struct ID *id); CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers); CustomDataLayer *BKE_id_attribute_from_index(struct ID *id, int lookup_index, - AttributeDomainMask domain_mask, - CustomDataMask layer_mask); + eAttrDomainMask domain_mask, + eCustomDataMask layer_mask); /** Layer is allowed to be nullptr; if so -1 (layer not found) will be returned. */ int BKE_id_attribute_to_index(const struct ID *id, const CustomDataLayer *layer, - AttributeDomainMask domain_mask, - CustomDataMask layer_mask); + eAttrDomainMask domain_mask, + eCustomDataMask layer_mask); struct CustomDataLayer *BKE_id_attribute_subset_active_get(const struct ID *id, int active_flag, - AttributeDomainMask domain_mask, - CustomDataMask mask); + eAttrDomainMask domain_mask, + eCustomDataMask mask); void BKE_id_attribute_subset_active_set(struct ID *id, struct CustomDataLayer *layer, int active_flag, - AttributeDomainMask domain_mask, - CustomDataMask mask); + eAttrDomainMask domain_mask, + eCustomDataMask mask); /** * Sets up a temporary ID with arbitrary CustomData domains. `r_id` will diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 8d449a124ec..fef91d6f75d 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -32,7 +32,7 @@ * extremely important for writing coherent bug-free code. When an attribute is retrieved with * write access, via #WriteAttributeLookup or #OutputAttribute, the geometry component must be * tagged to clear caches that depend on the changed data. - * 2. Domain interpolation: When retrieving an attribute, a domain (#AttributeDomain) can be + * 2. Domain interpolation: When retrieving an attribute, a domain (#eAttrDomain) can be * provided. If the attribute is stored on a different domain and conversion is possible, a * version of the data interpolated to the requested domain will be provided. These conversions * are implemented in each #GeometryComponent by `attribute_try_adapt_domain_impl`. @@ -77,6 +77,9 @@ class AttributeIDRef { friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id); }; +bool allow_procedural_attribute_access(StringRef attribute_name); +extern const char *no_procedural_access_message; + } // namespace blender::bke /** @@ -85,8 +88,8 @@ class AttributeIDRef { * stored (uv map, vertex group, ...). */ struct AttributeMetaData { - AttributeDomain domain; - CustomDataType data_type; + eAttrDomain domain; + eCustomDataType data_type; constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b) { @@ -95,8 +98,8 @@ struct AttributeMetaData { }; struct AttributeKind { - AttributeDomain domain; - CustomDataType data_type; + eAttrDomain domain; + eCustomDataType data_type; }; /** @@ -164,12 +167,12 @@ using AttributeForeachCallback = blender::FunctionRef<bool( namespace blender::bke { -CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types); +eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types); /** * Domains with a higher "information density" have a higher priority, * in order to choose a domain that will not lose data through domain conversion. */ -AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains); +eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains); /** * Used when looking up a "plain attribute" based on a name for reading from it. @@ -178,7 +181,7 @@ struct ReadAttributeLookup { /* The virtual array that is used to read from this attribute. */ GVArray varray; /* Domain the attribute lives on in the geometry. */ - AttributeDomain domain; + eAttrDomain domain; /* Convenience function to check if the attribute has been found. */ operator bool() const @@ -194,7 +197,7 @@ struct WriteAttributeLookup { /** The virtual array that is used to read from and write to the attribute. */ GVMutableArray varray; /** Domain the attributes lives on in the geometry component. */ - AttributeDomain domain; + eAttrDomain domain; /** * Call this after changing the attribute to invalidate caches that depend on this attribute. * \note Do not call this after the component the attribute is from has been destructed. @@ -229,7 +232,7 @@ class OutputAttribute { private: GVMutableArray varray_; - AttributeDomain domain_ = ATTR_DOMAIN_AUTO; + eAttrDomain domain_ = ATTR_DOMAIN_AUTO; SaveFn save_; std::unique_ptr<GVMutableArray_GSpan> optional_span_varray_; bool ignore_old_values_ = false; @@ -238,10 +241,7 @@ class OutputAttribute { public: OutputAttribute(); OutputAttribute(OutputAttribute &&other); - OutputAttribute(GVMutableArray varray, - AttributeDomain domain, - SaveFn save, - bool ignore_old_values); + OutputAttribute(GVMutableArray varray, eAttrDomain domain, SaveFn save, bool ignore_old_values); ~OutputAttribute(); @@ -250,9 +250,9 @@ class OutputAttribute { GVMutableArray &operator*(); GVMutableArray *operator->(); GVMutableArray &varray(); - AttributeDomain domain() const; + eAttrDomain domain() const; const CPPType &cpp_type() const; - CustomDataType custom_data_type() const; + eCustomDataType custom_data_type() const; GMutableSpan as_span(); template<typename T> MutableSpan<T> as_span(); @@ -310,7 +310,7 @@ template<typename T> class OutputAttribute_Typed { return varray_; } - AttributeDomain domain() const + eAttrDomain domain() const { return attribute_.domain(); } @@ -320,7 +320,7 @@ template<typename T> class OutputAttribute_Typed { return CPPType::get<T>(); } - CustomDataType custom_data_type() const + eCustomDataType custom_data_type() const { return cpp_type_to_custom_data_type(this->cpp_type()); } @@ -376,23 +376,21 @@ class CustomDataAttributes { * value for the type will be used. */ blender::GVArray get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, + eCustomDataType data_type, const void *default_value) const; template<typename T> blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const { const blender::CPPType &cpp_type = blender::CPPType::get<T>(); - const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); GVArray varray = this->get_for_read(attribute_id, type, &default_value); return varray.typed<T>(); } std::optional<blender::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id); - bool create(const AttributeIDRef &attribute_id, const CustomDataType data_type); - bool create_by_move(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - void *buffer); + bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type); + bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer); bool remove(const AttributeIDRef &attribute_id); /** @@ -400,7 +398,7 @@ class CustomDataAttributes { */ void reorder(Span<AttributeIDRef> new_order); - bool foreach_attribute(const AttributeForeachCallback callback, AttributeDomain domain) const; + bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const; }; /* -------------------------------------------------------------------- */ @@ -488,7 +486,7 @@ inline OutputAttribute::OutputAttribute() = default; inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default; inline OutputAttribute::OutputAttribute(GVMutableArray varray, - AttributeDomain domain, + eAttrDomain domain, SaveFn save, const bool ignore_old_values) : varray_(std::move(varray)), @@ -518,7 +516,7 @@ inline GVMutableArray &OutputAttribute::varray() return varray_; } -inline AttributeDomain OutputAttribute::domain() const +inline eAttrDomain OutputAttribute::domain() const { return domain_; } @@ -528,7 +526,7 @@ inline const CPPType &OutputAttribute::cpp_type() const return varray_.type(); } -inline CustomDataType OutputAttribute::custom_data_type() const +inline eCustomDataType OutputAttribute::custom_data_type() const { return cpp_type_to_custom_data_type(this->cpp_type()); } diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 3d194ba77dc..01c2ef988f2 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -39,7 +39,7 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func) } template<typename Func> -inline void convert_to_static_type(const CustomDataType data_type, const Func &func) +inline void convert_to_static_type(const eCustomDataType data_type, const Func &func) { const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(data_type); convert_to_static_type(cpp_type, func); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 2cd753da9d3..19bb4826956 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 1 +#define BLENDER_FILE_SUBVERSION 4 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index a98f4802991..4d728002c87 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -119,10 +119,6 @@ float BKE_brush_sample_masktex(const struct Scene *scene, int thread, struct ImagePool *pool); -/* Texture. */ - -unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary); - /** * Radial control. */ diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h index 8b2af96a063..8c65214c78e 100644 --- a/source/blender/blenkernel/BKE_callbacks.h +++ b/source/blender/blenkernel/BKE_callbacks.h @@ -97,6 +97,12 @@ typedef enum { BKE_CB_EVT_XR_SESSION_START_PRE, BKE_CB_EVT_ANNOTATION_PRE, BKE_CB_EVT_ANNOTATION_POST, + BKE_CB_EVT_OBJECT_BAKE_PRE, + BKE_CB_EVT_OBJECT_BAKE_COMPLETE, + BKE_CB_EVT_OBJECT_BAKE_CANCEL, + BKE_CB_EVT_COMPOSITE_PRE, + BKE_CB_EVT_COMPOSITE_POST, + BKE_CB_EVT_COMPOSITE_CANCEL, BKE_CB_EVT_TOT, } eCbEvent; diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index b7aa1c09e04..40df7acd066 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -171,7 +171,7 @@ struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam); * `BKE_lib_id.h`. */ struct CameraBGImage *BKE_camera_background_image_copy(struct CameraBGImage *bgpic_src, - const int copy_flag); + const int copy_flag); void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic); void BKE_camera_background_image_clear(struct Camera *cam); diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index a3bbcc8687a..feb3dc7de80 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -115,6 +115,18 @@ bool BKE_collection_is_empty(const struct Collection *collection); bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob); + +/** + * Add object to given collection, similar to #BKE_collection_object_add. + * + * However, it additionally ensures that the selected collection is also part of the given + * `view_layer`, if non-NULL. Otherwise, the object is not added to any collection. + */ +bool BKE_collection_viewlayer_object_add(struct Main *bmain, + const struct ViewLayer *view_layer, + struct Collection *collection, + struct Object *ob); + /** * Same as #BKE_collection_object_add, but unconditionally adds the object to the given collection. * diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index ce1f4c2b98c..737b05fee0c 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -307,6 +307,25 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, void *ownerdata, float mat[4][4], float ctime); + +/** + * Retrieves the list of all constraint targets, including the custom space target. + * Must be followed by a call to BKE_constraint_targets_flush to free memory. + * + * \param r_targets Pointer to the list to be initialized with target data. + * \returns the number of targets stored in the list. + */ +int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets); + +/** + * Copies changed data from the list produced by BKE_constraint_targets_get back to the constraint + * data structures and frees memory. + * + * \param targets List of targets filled by BKE_constraint_targets_get. + * \param no_copy Only free memory without copying changes (read-only mode). + */ +void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy); + /** * Get the list of targets required for solving a constraint. */ diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index f441203d9d6..b7068720469 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -222,9 +222,10 @@ void CTX_wm_operator_poll_msg_clear(struct bContext *C); /* Data Context * - * - listbases consist of CollectionPointerLink items and must be - * freed with BLI_freelistN! - * - the dir listbase consists of LinkData items */ + * - #ListBase consists of #CollectionPointerLink items and must be + * freed with #BLI_freelistN! + * - The dir #ListBase consists of #LinkData items. + */ /* data type, needed so we can tell between a NULL pointer and an empty list */ enum { diff --git a/source/blender/blenkernel/BKE_curves.h b/source/blender/blenkernel/BKE_curves.h index 88bb1c67fd1..c3302c6d2aa 100644 --- a/source/blender/blenkernel/BKE_curves.h +++ b/source/blender/blenkernel/BKE_curves.h @@ -25,7 +25,7 @@ void *BKE_curves_add(struct Main *bmain, const char *name); struct BoundBox *BKE_curves_boundbox_get(struct Object *ob); -bool BKE_curves_customdata_required(struct Curves *curves, struct CustomDataLayer *layer); +bool BKE_curves_customdata_required(const struct Curves *curves, const char *name); /* Depsgraph */ diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index cc056dab248..2bebd3ff97d 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -182,6 +182,7 @@ class CurvesGeometry : public ::CurvesGeometry { void update_curve_types(); bool has_curve_with_type(CurveType type) const; + bool has_curve_with_type(Span<CurveType> types) const; /** Return true if all of the curves have the provided type. */ bool is_single_type(CurveType type) const; /** Return the number of curves with each type. */ @@ -264,22 +265,15 @@ class CurvesGeometry : public ::CurvesGeometry { MutableSpan<float> nurbs_weights_for_write(); /** - * The index of a triangle (#MLoopTri) that a curve is attached to. - * The index is -1, if the curve is not attached. + * UV coordinate for each curve that encodes where the curve is attached to the surface mesh. */ - VArray<int> surface_triangle_indices() const; - MutableSpan<int> surface_triangle_indices_for_write(); + Span<float2> surface_uv_coords() const; + MutableSpan<float2> surface_uv_coords_for_write(); - /** - * Barycentric coordinates of the attachment point within a triangle. - * Only the first two coordinates are stored. The third coordinate can be derived because the sum - * of the three coordinates is 1. - * - * When the triangle index is -1, this coordinate should be ignored. - * The span can be empty, when all triangle indices are -1. - */ - Span<float2> surface_triangle_coords() const; - MutableSpan<float2> surface_triangle_coords_for_write(); + VArray<float> selection_point_float() const; + MutableSpan<float> selection_point_float_for_write(); + VArray<float> selection_curve_float() const; + MutableSpan<float> selection_curve_float_for_write(); /** * Calculate the largest and smallest position values, only including control points @@ -393,6 +387,7 @@ class CurvesGeometry : public ::CurvesGeometry { void update_customdata_pointers(); + void remove_points(IndexMask points_to_delete); void remove_curves(IndexMask curves_to_delete); /** @@ -401,11 +396,21 @@ class CurvesGeometry : public ::CurvesGeometry { */ void reverse_curves(IndexMask curves_to_reverse); + /** + * Remove any attributes that are unused based on the types in the curves. + */ + void remove_attributes_based_on_types(); + /* -------------------------------------------------------------------- * Attributes. */ - GVArray adapt_domain(const GVArray &varray, AttributeDomain from, AttributeDomain to) const; + GVArray adapt_domain(const GVArray &varray, eAttrDomain from, eAttrDomain to) const; + template<typename T> + VArray<T> adapt_domain(const VArray<T> &varray, eAttrDomain from, eAttrDomain to) const + { + return this->adapt_domain(GVArray(varray), from, to).typed<T>(); + } }; namespace curves { @@ -712,6 +717,12 @@ inline bool CurvesGeometry::has_curve_with_type(const CurveType type) const return this->curve_type_counts()[type] > 0; } +inline bool CurvesGeometry::has_curve_with_type(const Span<CurveType> types) const +{ + return std::any_of( + types.begin(), types.end(), [&](CurveType type) { return this->has_curve_with_type(type); }); +} + inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts() const { BLI_assert(this->runtime->type_counts == calculate_type_counts(this->curve_types())); diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh index 62b060093e9..f223e173ea9 100644 --- a/source/blender/blenkernel/BKE_curves_utils.hh +++ b/source/blender/blenkernel/BKE_curves_utils.hh @@ -9,9 +9,53 @@ * \brief Low-level operations for curves. */ +#include "BLI_function_ref.hh" +#include "BLI_generic_pointer.hh" + namespace blender::bke::curves { /** + * Copy the provided point attribute values between all curves in the #curve_ranges index + * ranges, assuming that all curves have the same number of control points in #src_curves + * and #dst_curves. + */ +void copy_point_data(const CurvesGeometry &src_curves, + const CurvesGeometry &dst_curves, + Span<IndexRange> curve_ranges, + GSpan src, + GMutableSpan dst); + +void copy_point_data(const CurvesGeometry &src_curves, + const CurvesGeometry &dst_curves, + IndexMask src_curve_selection, + GSpan src, + GMutableSpan dst); + +template<typename T> +void copy_point_data(const CurvesGeometry &src_curves, + const CurvesGeometry &dst_curves, + const IndexMask src_curve_selection, + const Span<T> src, + MutableSpan<T> dst) +{ + copy_point_data(src_curves, dst_curves, src_curve_selection, GSpan(src), GMutableSpan(dst)); +} + +void fill_points(const CurvesGeometry &curves, + IndexMask curve_selection, + GPointer value, + GMutableSpan dst); + +template<typename T> +void fill_points(const CurvesGeometry &curves, + const IndexMask curve_selection, + const T &value, + MutableSpan<T> dst) +{ + fill_points(curves, curve_selection, &value, dst); +} + +/** * Copy the size of every curve in #curve_ranges to the corresponding index in #counts. */ void fill_curve_counts(const bke::CurvesGeometry &curves, @@ -23,4 +67,18 @@ void fill_curve_counts(const bke::CurvesGeometry &curves, */ void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0); +IndexMask indices_for_type(const VArray<int8_t> &types, + const std::array<int, CURVE_TYPES_NUM> &type_counts, + const CurveType type, + const IndexMask selection, + Vector<int64_t> &r_indices); + +void foreach_curve_by_type(const VArray<int8_t> &types, + const std::array<int, CURVE_TYPES_NUM> &type_counts, + IndexMask selection, + FunctionRef<void(IndexMask)> catmull_rom_fn, + FunctionRef<void(IndexMask)> poly_fn, + FunctionRef<void(IndexMask)> bezier_fn, + FunctionRef<void(IndexMask)> nurbs_fn); + } // namespace blender::bke::curves diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index d4a78057a29..bbfd11b50c2 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -28,7 +28,7 @@ struct BlendWriter; struct CustomData; struct CustomData_MeshMasks; struct ID; -typedef uint64_t CustomDataMask; +typedef uint64_t eCustomDataMask; /* A data type large enough to hold 1 element from any custom-data layer type. */ typedef struct { @@ -63,7 +63,7 @@ typedef enum eCDAllocType { CD_DUPLICATE = 4, } eCDAllocType; -#define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type)) +#define CD_TYPE_AS_MASK(_type) (eCustomDataMask)((eCustomDataMask)1 << (eCustomDataMask)(_type)) void customData_mask_layers__print(const struct CustomData_MeshMasks *mask); @@ -137,7 +137,7 @@ void CustomData_data_add(int type, void *data1, const void *data2); */ void CustomData_copy(const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, + eCustomDataMask mask, eCDAllocType alloctype, int totelem); @@ -150,7 +150,7 @@ void CustomData_update_typemap(struct CustomData *data); */ bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, + eCustomDataMask mask, eCDAllocType alloctype, int totelem); @@ -170,7 +170,7 @@ void CustomData_realloc(struct CustomData *data, int totelem); */ bool CustomData_bmesh_merge(const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, + eCustomDataMask mask, eCDAllocType alloctype, struct BMesh *bm, char htype); @@ -188,7 +188,7 @@ void CustomData_free(struct CustomData *data, int totelem); /** * Same as above, but only frees layers which matches the given mask. */ -void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask); +void CustomData_free_typemask(struct CustomData *data, int totelem, eCustomDataMask mask); /** * Frees all layers with #CD_FLAG_TEMPORARY. @@ -225,6 +225,7 @@ void *CustomData_add_layer_anonymous(struct CustomData *data, * In edit-mode, use #EDBM_data_layer_free instead of this function. */ bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index); +bool CustomData_free_layer_named(struct CustomData *data, const char *name, const int totelem); /** * Frees the layer index with the give type. @@ -248,7 +249,7 @@ bool CustomData_has_layer(const struct CustomData *data, int type); * Returns the number of layers with this type. */ int CustomData_number_of_layers(const struct CustomData *data, int type); -int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDataMask mask); +int CustomData_number_of_layers_typemask(const struct CustomData *data, eCustomDataMask mask); /** * Duplicate data of a layer with flag NOFREE, and remove that flag. @@ -276,7 +277,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem); * Set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is * zero for the layer type, so only layer types specified by the mask will be copied */ -void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask); +void CustomData_set_only_copy(const struct CustomData *data, eCustomDataMask mask); /** * Copies data from one CustomData object to another @@ -309,7 +310,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source, struct CustomData *dest, void *src_block, void **dest_block, - CustomDataMask mask_exclude); + eCustomDataMask mask_exclude); /** * Copies data of a single layer of a given type. @@ -488,7 +489,7 @@ void CustomData_bmesh_free_block_data(struct CustomData *data, void *block); */ void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data, void *block, - CustomDataMask mask_exclude); + eCustomDataMask mask_exclude); /** * Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh @@ -593,14 +594,14 @@ void CustomData_external_remove(struct CustomData *data, struct ID *id, int type bool CustomData_external_test(struct CustomData *data, int type); void CustomData_external_write( - struct CustomData *data, struct ID *id, CustomDataMask mask, int totelem, int free); + struct CustomData *data, struct ID *id, eCustomDataMask mask, int totelem, int free); void CustomData_external_read(struct CustomData *data, struct ID *id, - CustomDataMask mask, + eCustomDataMask mask, int totelem); void CustomData_external_reload(struct CustomData *data, struct ID *id, - CustomDataMask mask, + eCustomDataMask mask, int totelem); /* Mesh-to-mesh transfer data. */ @@ -725,7 +726,7 @@ void CustomData_blend_write(BlendWriter *writer, CustomData *data, blender::Span<CustomDataLayer> layers_to_write, int count, - CustomDataMask cddata_mask, + eCustomDataMask cddata_mask, ID *id); #endif @@ -748,7 +749,7 @@ void CustomData_debug_info_from_layers(const struct CustomData *data, # include "BLI_cpp_type.hh" namespace blender::bke { -const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); -CustomDataType cpp_type_to_custom_data_type(const CPPType &type); +const CPPType *custom_data_type_to_cpp_type(eCustomDataType type); +eCustomDataType cpp_type_to_custom_data_type(const CPPType &type); } // namespace blender::bke #endif diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 78d80ce200e..4489527fcab 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -259,6 +259,18 @@ struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path /** * High level function to get an f-curve from C without having the RNA. + * + * If there is an action assigned to the `id`'s #AnimData, it will be searched for a matching + * F-curve first. Drivers are searched only if no valid action F-curve could be found. + * + * \note Return pointer parameter (`r_driven`) is optional and may be NULL. + * + * \warning In case no animation (from an Action) F-curve is found, returned value is always NULL. + * This means that this function will set `r_driven` to True in case a valid driver F-curve is + * found, but will not return said F-curve. In other words: + * - Animated with FCurve: returns the `FCurve*` and `*r_driven = false`. + * - Animated with driver: returns `NULL` and `*r_driven = true`. + * - Not animated: returns `NULL` and `*r_driven = false`. */ struct FCurve *id_data_find_fcurve( ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven); @@ -279,6 +291,25 @@ struct FCurve *id_data_find_fcurve( int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName); /** + * Find an F-Curve from its rna path and index. + * + * If there is an action assigned to the `animdata`, it will be searched for a matching F-curve + * first. Drivers are searched only if no valid action F-curve could be found. + * + * \note Typically, indices in RNA arrays are stored separately in F-curves, so the rna_path + * should not include them (e.g. `rna_path='location[0]'` will not match any F-Curve on an Object, + * but `rna_path='location', rna_index=0` will if it exists). + * + * \note Return pointer parameters (`r_action`, `r_driven` and `r_special`) are all optional and + * may be NULL. + */ +struct FCurve *BKE_animadata_fcurve_find_by_rna_path(struct AnimData *animdata, + const char *rna_path, + const int rna_index, + struct bAction **r_action, + bool *r_driven); + +/** * Find an f-curve based on an rna property. */ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr, @@ -291,7 +322,9 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr, /** * Same as above, but takes a context data, * temp hack needed for complex paths like texture ones. - */ + * + * \param r_special Optional, ignored when NULL. Set to `true` if the given RNA `ptr` is a NLA + * strip, and the returned F-curve comes from this NLA strip. */ struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C, const struct PointerRNA *ptr, struct PropertyRNA *prop, diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh index 9c86ab262ef..7c504826044 100644 --- a/source/blender/blenkernel/BKE_geometry_fields.hh +++ b/source/blender/blenkernel/BKE_geometry_fields.hh @@ -17,10 +17,10 @@ namespace blender::bke { class GeometryComponentFieldContext : public fn::FieldContext { private: const GeometryComponent &component_; - const AttributeDomain domain_; + const eAttrDomain domain_; public: - GeometryComponentFieldContext(const GeometryComponent &component, const AttributeDomain domain) + GeometryComponentFieldContext(const GeometryComponent &component, const eAttrDomain domain) : component_(component), domain_(domain) { } @@ -30,7 +30,7 @@ class GeometryComponentFieldContext : public fn::FieldContext { return component_; } - AttributeDomain domain() const + eAttrDomain domain() const { return domain_; } @@ -45,7 +45,7 @@ class GeometryFieldInput : public fn::FieldInput { ResourceScope &scope) const override; virtual GVArray get_varray_for_context(const GeometryComponent &component, - AttributeDomain domain, + eAttrDomain domain, IndexMask mask) const = 0; }; @@ -73,7 +73,7 @@ class AttributeFieldInput : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - AttributeDomain domain, + eAttrDomain domain, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -90,7 +90,7 @@ class IDAttributeFieldInput : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - AttributeDomain domain, + eAttrDomain domain, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -99,12 +99,12 @@ class IDAttributeFieldInput : public GeometryFieldInput { bool is_equal_to(const fn::FieldNode &other) const override; }; -VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain); +VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain); VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, const Mesh &mesh, const IndexMask mask, - const AttributeDomain domain); + eAttrDomain domain); class NormalFieldInput : public GeometryFieldInput { public: @@ -114,7 +114,7 @@ class NormalFieldInput : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -153,7 +153,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - AttributeDomain domain, + eAttrDomain domain, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -166,7 +166,7 @@ class CurveLengthFieldInput final : public GeometryFieldInput { public: CurveLengthFieldInput(); GVArray get_varray_for_context(const GeometryComponent &component, - AttributeDomain domain, + eAttrDomain domain, IndexMask mask) const final; uint64_t hash() const override; bool is_equal_to(const fn::FieldNode &other) const override; diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index c58420efceb..8d658c9be15 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -94,11 +94,11 @@ class GeometryComponent { * \note Conceptually this function is static, the result is always the same for different * instances of the same geometry component type. */ - bool attribute_domain_supported(AttributeDomain domain) const; + bool attribute_domain_supported(eAttrDomain domain) const; /** * Return the length of a specific domain, or 0 if the domain is not supported. */ - virtual int attribute_domain_num(AttributeDomain domain) const; + virtual int attribute_domain_num(eAttrDomain domain) const; /** * Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain @@ -130,16 +130,16 @@ class GeometryComponent { * \return null if the interpolation is not implemented. */ blender::GVArray attribute_try_adapt_domain(const blender::GVArray &varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const + const eAttrDomain from_domain, + const eAttrDomain to_domain) const { return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain); } /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const + const eAttrDomain from_domain, + const eAttrDomain to_domain) const { return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain) .template typed<T>(); @@ -156,8 +156,8 @@ class GeometryComponent { /** Returns true when the attribute has been created. */ bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id, - AttributeDomain domain, - const CustomDataType data_type, + eAttrDomain domain, + eCustomDataType data_type, const AttributeInit &initializer); /** @@ -182,8 +182,8 @@ class GeometryComponent { * interpolated or converted. */ blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - AttributeDomain domain, - const CustomDataType data_type) const; + eAttrDomain domain, + eCustomDataType data_type) const; /** * Get a virtual array that refers to the data of an attribute, interpolated to the given domain. @@ -191,7 +191,7 @@ class GeometryComponent { * interpolated. */ blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - AttributeDomain domain) const; + eAttrDomain domain) const; /** * Get a virtual array that refers to the data of an attribute converted to the given data type. @@ -199,7 +199,7 @@ class GeometryComponent { * cannot be converted. */ blender::bke::ReadAttributeLookup attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const; + const blender::bke::AttributeIDRef &attribute_id, eCustomDataType data_type) const; /** * Get a virtual array that refers to the data of an attribute, interpolated to the given domain @@ -207,17 +207,17 @@ class GeometryComponent { * contain a default value. This never returns null. */ blender::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - AttributeDomain domain, - const CustomDataType data_type, + eAttrDomain domain, + eCustomDataType data_type, const void *default_value = nullptr) const; /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, + const eAttrDomain domain, const T &default_value) const { const blender::CPPType &cpp_type = blender::CPPType::get<T>(); - const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); return this->attribute_get_for_read(attribute_id, domain, type, &default_value) .template typed<T>(); } @@ -234,18 +234,18 @@ class GeometryComponent { */ blender::bke::OutputAttribute attribute_try_get_for_output( const blender::bke::AttributeIDRef &attribute_id, - AttributeDomain domain, - const CustomDataType data_type, + eAttrDomain domain, + eCustomDataType data_type, const void *default_value = nullptr); /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output( const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, + const eAttrDomain domain, const T default_value) { const blender::CPPType &cpp_type = blender::CPPType::get<T>(); - const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value); } @@ -257,15 +257,15 @@ class GeometryComponent { */ blender::bke::OutputAttribute attribute_try_get_for_output_only( const blender::bke::AttributeIDRef &attribute_id, - AttributeDomain domain, - const CustomDataType data_type); + eAttrDomain domain, + eCustomDataType data_type); /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only( - const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) + const blender::bke::AttributeIDRef &attribute_id, const eAttrDomain domain) { const blender::CPPType &cpp_type = blender::CPPType::get<T>(); - const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); return this->attribute_try_get_for_output_only(attribute_id, domain, data_type); } @@ -273,8 +273,8 @@ class GeometryComponent { virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const; virtual blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - AttributeDomain from_domain, - AttributeDomain to_domain) const; + eAttrDomain from_domain, + eAttrDomain to_domain) const; }; template<typename T> @@ -560,7 +560,7 @@ class MeshComponent : public GeometryComponent { */ Mesh *get_for_write(); - int attribute_domain_num(AttributeDomain domain) const final; + int attribute_domain_num(eAttrDomain domain) const final; bool is_empty() const final; @@ -573,8 +573,8 @@ class MeshComponent : public GeometryComponent { const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - AttributeDomain from_domain, - AttributeDomain to_domain) const final; + eAttrDomain from_domain, + eAttrDomain to_domain) const final; }; /** @@ -623,7 +623,7 @@ class PointCloudComponent : public GeometryComponent { */ PointCloud *get_for_write(); - int attribute_domain_num(AttributeDomain domain) const final; + int attribute_domain_num(eAttrDomain domain) const final; bool is_empty() const final; @@ -664,7 +664,7 @@ class CurveComponentLegacy : public GeometryComponent { const CurveEval *get_for_read() const; CurveEval *get_for_write(); - int attribute_domain_num(AttributeDomain domain) const final; + int attribute_domain_num(eAttrDomain domain) const final; bool is_empty() const final; @@ -677,8 +677,8 @@ class CurveComponentLegacy : public GeometryComponent { const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - AttributeDomain from_domain, - AttributeDomain to_domain) const final; + eAttrDomain from_domain, + eAttrDomain to_domain) const final; }; /** @@ -716,7 +716,7 @@ class CurveComponent : public GeometryComponent { const Curves *get_for_read() const; Curves *get_for_write(); - int attribute_domain_num(AttributeDomain domain) const final; + int attribute_domain_num(eAttrDomain domain) const final; bool is_empty() const final; @@ -735,8 +735,8 @@ class CurveComponent : public GeometryComponent { const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - AttributeDomain from_domain, - AttributeDomain to_domain) const final; + eAttrDomain from_domain, + eAttrDomain to_domain) const final; }; /** @@ -964,7 +964,7 @@ class InstancesComponent : public GeometryComponent { blender::bke::CustomDataAttributes &attributes(); const blender::bke::CustomDataAttributes &attributes() const; - int attribute_domain_num(AttributeDomain domain) const final; + int attribute_domain_num(eAttrDomain domain) const final; void foreach_referenced_geometry( blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const; diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 60564d1282e..dc7a5ab003a 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -76,13 +76,13 @@ struct bGPdata; void BKE_gpencil_free_point_weights(struct MDeformVert *dvert); void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps); void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps); -/* free stroke, doesn't unlink from any listbase */ +/** Free stroke, doesn't unlink from any #ListBase. */ void BKE_gpencil_free_stroke(struct bGPDstroke *gps); -/* Free strokes belonging to a gp-frame */ +/** Free strokes belonging to a gp-frame. */ bool BKE_gpencil_free_strokes(struct bGPDframe *gpf); -/* Free all of a gp-layer's frames */ +/** Free all of a gp-layer's frames. */ void BKE_gpencil_free_frames(struct bGPDlayer *gpl); -/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ +/** Free all of the gp-layers for a viewport (list should be `&gpd->layers` or so). */ void BKE_gpencil_free_layers(struct ListBase *list); /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all); @@ -108,9 +108,9 @@ void BKE_gpencil_batch_cache_free(struct bGPdata *gpd); */ void BKE_gpencil_stroke_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps); void BKE_gpencil_curve_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps); -/* Assign unique stroke ID for selection. */ +/** Assign unique stroke ID for selection. */ void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps); -/* Reset unique stroke ID for selection. */ +/** Reset unique stroke ID for selection. */ void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps); /** diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 504ab47c1c5..beac608a138 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -603,7 +603,7 @@ bool BKE_id_can_be_asset(const struct ID *id); * we should either cache that status info also in virtual override IDs, or address the * long-standing TODO of getting an efficient 'owner_id' access for all embedded ID types. */ -bool BKE_id_is_editable(struct Main *bmain, struct ID *id); +bool BKE_id_is_editable(const struct Main *bmain, const struct ID *id); /** * Returns ordered list of data-blocks for display in the UI. diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 38de4bebdbd..2e28b3c00ee 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -62,12 +62,25 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_ /** * Check if given ID has some override rules that actually indicate the user edited it. */ -bool BKE_lib_override_library_is_user_edited(struct ID *id); +bool BKE_lib_override_library_is_user_edited(const struct ID *id); /** * Check if given ID is a system override. */ -bool BKE_lib_override_library_is_system_defined(struct Main *bmain, struct ID *id); +bool BKE_lib_override_library_is_system_defined(const struct Main *bmain, const struct ID *id); + +/** + * Check if given Override Property for given ID is animated (through a F-Curve in an Action, or + * from a driver). + * + * \param override_rna_prop if not NULL, the RNA property matching the given path in the + * `override_prop`. + * \param rnaprop_index Array in the RNA property, 0 if unknown or irrelevant. + */ +bool BKE_lib_override_library_property_is_animated(const ID *id, + const IDOverrideLibraryProperty *override_prop, + const struct PropertyRNA *override_rna_prop, + const int rnaprop_index); /** * Check if given ID is a leaf in its liboverride hierarchy (i.e. if it does not use any other @@ -281,11 +294,14 @@ void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override * * \param idpoin: Pointer to the override ID. * \param library_prop: The library override property to find the matching RNA property for. + * \param r_index: The RNA array flat index (i.e. flattened index in case of multi-dimensional + * array properties). See #RNA_path_resolve_full family of functions for details. */ bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin, const struct IDOverrideLibraryProperty *library_prop, struct PointerRNA *r_override_poin, - struct PropertyRNA **r_override_prop); + struct PropertyRNA **r_override_prop, + int *r_index); /** * Find override property operation from given sub-item(s), if it exists. diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index f62225179bd..37b626fb4da 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -95,11 +95,11 @@ typedef enum eIDRemapType { */ void BKE_libblock_remap_multiple_locked(struct Main *bmain, struct IDRemapper *mappings, - const short remap_flags); + short remap_flags); void BKE_libblock_remap_multiple(struct Main *bmain, struct IDRemapper *mappings, - const short remap_flags); + short remap_flags); /** * Replace all references in given Main to \a old_id by \a new_id @@ -142,9 +142,9 @@ void BKE_libblock_relink_ex(struct Main *bmain, */ void BKE_libblock_relink_multiple(struct Main *bmain, struct LinkNode *ids, - const eIDRemapType remap_type, + eIDRemapType remap_type, struct IDRemapper *id_remapper, - const short remap_flags); + short remap_flags); /** * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 59b22f7759b..2c444f42c46 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -77,8 +77,16 @@ typedef struct MainIDRelationsEntry { typedef enum eMainIDRelationsEntryTags { /* Generic tag marking the entry as to be processed. */ MAINIDRELATIONS_ENTRY_TAGS_DOIT = 1 << 0, + + /* Generic tag marking the entry as processed in the `to` direction (i.e. we processed the IDs + * used by this item). */ + MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO = 1 << 1, + /* Generic tag marking the entry as processed in the `from` direction (i.e. we processed the IDs + * using by this item). */ + MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM = 1 << 2, /* Generic tag marking the entry as processed. */ - MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1, + MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO | + MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM, } eMainIDRelationsEntryTags; typedef struct MainIDRelations { diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 23ec69babc8..66e0ff8e81a 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -52,6 +52,18 @@ extern "C" { # define BKE_MESH_OMP_LIMIT 10000 #endif +/* mesh_runtime.cc */ + +/** + * Call after changing vertex positions to tag lazily calculated caches for recomputation. + */ +void BKE_mesh_tag_coords_changed(struct Mesh *mesh); + +/** + * Call after moving every mesh vertex by the same translation. + */ +void BKE_mesh_tag_coords_changed_uniformly(struct Mesh *mesh); + /* *** mesh.c *** */ struct BMesh *BKE_mesh_to_bmesh_ex(const struct Mesh *me, @@ -324,21 +336,10 @@ void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3] /** * Recreate #MFace Tessellation. * - * \param do_face_nor_copy: Controls whether the normals from the poly - * are copied to the tessellated faces. - * - * \return number of tessellation faces. - * * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since * it's not used in many places and #MFace should be phased out. */ -int BKE_mesh_tessface_calc_ex(struct CustomData *fdata, - struct CustomData *ldata, - struct CustomData *pdata, - struct MVert *mvert, - int totface, - int totloop, - int totpoly); + void BKE_mesh_tessface_calc(struct Mesh *mesh); /** @@ -885,9 +886,6 @@ enum { * Actually this later behavior could apply to the Mirror Modifier as well, * but the additional checks are costly and not necessary in the case of mirror, * because each vertex is only merged to its own mirror. - * - * \note #BKE_mesh_tessface_calc_ex has to run on the returned DM - * if you want to access tess-faces. */ struct Mesh *BKE_mesh_merge_verts(struct Mesh *mesh, const int *vtargetmap, diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh index abaf2ab0178..441783d46a1 100644 --- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh +++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh @@ -23,6 +23,8 @@ namespace blender::meshintersect { * \param material_remaps: An array of maps from material slot numbers in the corresponding mesh * to the material slot in the first mesh. It is OK for material_remaps or any of its constituent * arrays to be empty. + * \param r_intersecting_edges: Array to store indices of edges on the resulting mesh in. These + * 'new' edges are the result of the intersections. */ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, Span<const float4x4 *> transforms, @@ -30,6 +32,7 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, Span<Array<short>> material_remaps, bool use_self, bool hole_tolerant, - int boolean_mode); + int boolean_mode, + Vector<int> *r_intersecting_edges); } // namespace blender::meshintersect diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h index e2b16a7681d..ee0179c7a77 100644 --- a/source/blender/blenkernel/BKE_mesh_remap.h +++ b/source/blender/blenkernel/BKE_mesh_remap.h @@ -42,7 +42,7 @@ void BKE_mesh_remap_free(MeshPairRemap *map); void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, int index); /* TODO: - * Add other 'from/to' mapping sources, like e.g. using an UVMap, etc. + * Add other 'from/to' mapping sources, like e.g. using a UVMap, etc. * https://blenderartists.org/t/619105 * * We could also use similar topology mappings inside a same mesh diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h index 0e78f9d7e15..dfefe125a51 100644 --- a/source/blender/blenkernel/BKE_mesh_runtime.h +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -8,7 +8,7 @@ * This file contains access functions for the Mesh.runtime struct. */ -//#include "BKE_customdata.h" /* for CustomDataMask */ +//#include "BKE_customdata.h" /* for eCustomDataMask */ #ifdef __cplusplus extern "C" { diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh index a942f3bb7ed..cbbd0249f4f 100644 --- a/source/blender/blenkernel/BKE_mesh_sample.hh +++ b/source/blender/blenkernel/BKE_mesh_sample.hh @@ -6,12 +6,20 @@ * \ingroup bke */ +#include "BLI_function_ref.hh" #include "BLI_generic_virtual_array.hh" #include "BLI_math_vec_types.hh" +#include "DNA_meshdata_types.h" + #include "BKE_attribute.h" struct Mesh; +struct BVHTreeFromMesh; + +namespace blender { +class RandomNumberGenerator; +} namespace blender::bke { struct ReadAttributeLookup; @@ -69,7 +77,7 @@ class MeshAttributeInterpolator { const Span<int> looptri_indices); void sample_data(const GVArray &src, - AttributeDomain domain, + eAttrDomain domain, eAttributeMapMode mode, const GMutableSpan dst); @@ -82,4 +90,55 @@ class MeshAttributeInterpolator { Span<float3> ensure_nearest_weights(); }; +/** + * Find randomly distributed points on the surface of a mesh within a 3D sphere. This does not + * sample an exact number of points because it comes with extra overhead to avoid bias that is only + * required in some cases. If an exact number of points is required, that has to be implemented at + * a higher level. + * + * \param approximate_density: Roughly the number of points per unit of area. + * \return The number of added points. + */ +int sample_surface_points_spherical(RandomNumberGenerator &rng, + const Mesh &mesh, + Span<int> looptri_indices_to_sample, + const float3 &sample_pos, + float sample_radius, + float approximate_density, + Vector<float3> &r_bary_coords, + Vector<int> &r_looptri_indices, + Vector<float3> &r_positions); + +/** + * Find randomly distributed points on the surface of a mesh within a circle that is projected on + * the mesh. This does not result in an exact number of points because that would come with extra + * overhead and is not always possible. If an exact number of points is required, that has to be + * implemented at a higher level. + * + * \param region_position_to_ray: Function that converts a 2D position into a 3D ray that is used + * to find positions on the mesh. + * \param mesh_bvhtree: BVH tree of the triangles in the mesh. Passed in so that it does not have + * to be retrieved again. + * \param tries_num: Number of 2d positions that are sampled. The maximum + * number of new samples. + * \return The number of added points. + */ +int sample_surface_points_projected( + RandomNumberGenerator &rng, + const Mesh &mesh, + BVHTreeFromMesh &mesh_bvhtree, + const float2 &sample_pos_re, + float sample_radius_re, + FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)> region_position_to_ray, + bool front_face_only, + int tries_num, + int max_points, + Vector<float3> &r_bary_coords, + Vector<int> &r_looptri_indices, + Vector<float3> &r_positions); + +float3 compute_bary_coord_in_triangle(const Mesh &mesh, + const MLoopTri &looptri, + const float3 &position); + } // namespace blender::bke::mesh_surface_sample diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 1ff10d06b00..59a1599e7ae 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1493,6 +1493,9 @@ struct TexResult; #define GEO_NODE_STORE_NAMED_ATTRIBUTE 1156 #define GEO_NODE_INPUT_NAMED_ATTRIBUTE 1157 #define GEO_NODE_REMOVE_ATTRIBUTE 1158 +#define GEO_NODE_INPUT_INSTANCE_ROTATION 1159 +#define GEO_NODE_INPUT_INSTANCE_SCALE 1160 +#define GEO_NODE_VOLUME_CUBE 1161 /** \} */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index c39ab22ce3a..93a5e0a4072 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -501,8 +501,8 @@ typedef struct SculptSession { struct MPropCol *vcol; struct MLoopCol *mcol; - AttributeDomain vcol_domain; - CustomDataType vcol_type; + eAttrDomain vcol_domain; + eCustomDataType vcol_type; float *vmask; @@ -552,8 +552,7 @@ typedef struct SculptSession { float (*deform_cos)[3]; /* Coords of deformed mesh but without stroke displacement. */ float (*deform_imats)[3][3]; /* Crazy-space deformation matrices. */ - /* Used to cache the render of the active texture */ - unsigned int texcache_side, *texcache, texcache_actual; + /* Pool for texture evaluations. */ struct ImagePool *tex_pool; struct StrokeCache *cache; @@ -613,6 +612,10 @@ typedef struct SculptSession { float init_pivot_rot[4]; float init_pivot_scale[3]; + float prev_pivot_pos[3]; + float prev_pivot_rot[4]; + float prev_pivot_scale[3]; + union { struct { struct SculptVertexPaintGeomMap gmap; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 291b9b6b778..f517ff3a949 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -221,7 +221,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, PBVHFrustumPlanes *update_frustum, PBVHFrustumPlanes *draw_frustum, void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers), - void *user_data); + void *user_data, + bool full_render); void BKE_pbvh_draw_debug_cb( PBVH *pbvh, @@ -549,7 +550,7 @@ PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node); void BKE_pbvh_node_color_buffer_free(PBVH *pbvh); bool BKE_pbvh_get_color_layer(const struct Mesh *me, CustomDataLayer **r_layer, - AttributeDomain *r_attr); + eAttrDomain *r_attr); /* Swaps colors at each element in indices (of domain pbvh->vcol_domain) * with values in colors. */ diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index c238a24f173..6dbba11a56d 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -30,8 +30,7 @@ struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob); bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]); void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud); -bool BKE_pointcloud_customdata_required(struct PointCloud *pointcloud, - struct CustomDataLayer *layer); +bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, const char *name); /* Dependency Graph */ diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index edb301f06bf..9965b6f1351 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -136,7 +136,7 @@ void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle); void BKE_sound_mute_scene_sound(void *handle, char mute); -void BKE_sound_move_scene_sound(struct Scene *scene, +void BKE_sound_move_scene_sound(const struct Scene *scene, void *handle, int startframe, int endframe, diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h index 4ad17610207..271026d4253 100644 --- a/source/blender/blenkernel/BKE_subdiv_modifier.h +++ b/source/blender/blenkernel/BKE_subdiv_modifier.h @@ -7,6 +7,8 @@ #pragma once +#include "BKE_subdiv.h" + #include "BLI_sys_types.h" #ifdef __cplusplus @@ -24,9 +26,30 @@ struct Subdiv; struct SubdivSettings; struct SubsurfModifierData; -void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings, - const struct SubsurfModifierData *smd, - bool use_render_params); +/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */ +typedef struct SubsurfRuntimeData { + /* Subdivision settings, exists before descriptor or mesh wrapper is created. */ + SubdivSettings settings; + + /* Cached subdivision surface descriptor, with topology and settings. */ + struct Subdiv *subdiv; + bool set_by_draw_code; + + /* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */ + bool has_gpu_subdiv; + int resolution; + bool use_optimal_display; + bool calc_loop_normals; + bool use_loop_normals; + + /* Cached from the draw code for stats display. */ + int stats_totvert; + int stats_totedge; + int stats_totpoly; + int stats_totloop; +} SubsurfRuntimeData; + +bool BKE_subsurf_modifier_runtime_init(struct SubsurfModifierData *smd, bool use_render_params); bool BKE_subsurf_modifier_use_custom_loop_normals(const struct SubsurfModifierData *smd, const struct Mesh *mesh); @@ -57,12 +80,7 @@ extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv); * which matches settings and topology. */ struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure( - const struct SubsurfModifierData *smd, - const struct SubdivSettings *subdiv_settings, - const struct Mesh *mesh, - bool for_draw_code); - -struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd); + struct SubsurfRuntimeData *runtime_data, const struct Mesh *mesh, bool for_draw_code); /** * Return the #ModifierMode required for the evaluation of the subsurf modifier, diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h index 823d32f83ba..f051335fc41 100644 --- a/source/blender/blenkernel/BKE_unit.h +++ b/source/blender/blenkernel/BKE_unit.h @@ -19,6 +19,10 @@ struct UnitSettings; */ size_t BKE_unit_value_as_string_adaptive( char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad); +/** + * Representation of a value in units. Negative precision is used to disable stripping of zeroes. + * This reduces text jumping when changing values. + */ size_t BKE_unit_value_as_string(char *str, int len_max, double value, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 0b5f252b0d6..8dc6f711fae 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -174,7 +174,7 @@ set(SRC intern/lib_id_delete.c intern/lib_id_eval.c intern/lib_id_remapper.cc - intern/lib_override.c + intern/lib_override.cc intern/lib_override_proxy_conversion.c intern/lib_query.c intern/lib_remap.c @@ -611,7 +611,7 @@ if(WITH_IMAGE_HDR) endif() if(WITH_IMAGE_WEBP) - add_definitions(-DWITH_WEBP) + add_definitions(-DWITH_WEBP) endif() if(WITH_CODEC_AVI) diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 5cf0ca6e062..b3a9d894944 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -52,6 +52,7 @@ #include "BKE_object.h" #include "BKE_object_deform.h" #include "BKE_paint.h" +#include "BKE_subdiv_modifier.h" #include "BLI_sys_types.h" /* for intptr_t support */ @@ -598,10 +599,10 @@ static bool mesh_has_modifier_final_normals(const Mesh *mesh_input, /* Test if mesh has the required loop normals, in case an additional modifier * evaluation from another instance or from an operator requests it but the * initial normals were not loop normals. */ - const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || - (final_datamask->lmask & CD_MASK_NORMAL) != 0); + const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || + (final_datamask->lmask & CD_MASK_NORMAL) != 0); - return (!do_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)); + return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)); } static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, @@ -610,16 +611,19 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, Mesh *mesh_final) { /* Compute normals. */ - const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || - (final_datamask->lmask & CD_MASK_NORMAL) != 0); + const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || + (final_datamask->lmask & CD_MASK_NORMAL) != 0); /* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */ - mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals; + SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data; + if (subsurf_runtime_data) { + subsurf_runtime_data->calc_loop_normals = calc_loop_normals; + } - if (do_loop_normals) { + if (calc_loop_normals) { /* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). In case * of deferred CPU subdivision, this will be computed when the wrapper is generated. */ - if (mesh_final->runtime.subsurf_resolution == 0) { + if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) { BKE_mesh_calc_normals_split(mesh_final); } } @@ -628,14 +632,14 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, /* without this, drawing ngon tri's faces will show ugly tessellated face * normals and will also have to calculate normals on the fly, try avoid * this where possible since calculating polygon normals isn't fast, - * note that this isn't a problem for subsurf (only quads) or editmode + * note that this isn't a problem for subsurf (only quads) or edit-mode * which deals with drawing differently. */ BKE_mesh_ensure_normals_for_display(mesh_final); } /* Some modifiers, like data-transfer, may generate those data as temp layer, * we do not want to keep them, as they are used by display code when available - * (i.e. even if autosmooth is disabled). */ + * (i.e. even if auto-smooth is disabled). */ if (CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) { CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop); } @@ -1266,15 +1270,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, return; } - const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 || - (final_datamask->lmask & CD_MASK_NORMAL) != 0); + const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 || + (final_datamask->lmask & CD_MASK_NORMAL) != 0); - mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals; + SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data; + if (subsurf_runtime_data) { + subsurf_runtime_data->calc_loop_normals = calc_loop_normals; + } - if (do_loop_normals) { + if (calc_loop_normals) { /* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the * wrapper is generated. */ - if (mesh_final->runtime.subsurf_resolution == 0) { + if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) { BKE_mesh_calc_normals_split(mesh_final); } } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 371bd8ded6d..fee7582acb3 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -980,13 +980,10 @@ void BKE_pose_channels_remove(Object *ob, else { /* Maybe something the bone references is being removed instead? */ for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if (ct->tar == ob) { if (ct->subtarget[0]) { @@ -998,9 +995,7 @@ void BKE_pose_channels_remove(Object *ob, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } } @@ -1988,3 +1983,16 @@ void BKE_pose_blend_read_expand(BlendExpander *expander, bPose *pose) BLO_expand(expander, chan->custom); } } + +void BKE_action_fcurves_clear(bAction *act) +{ + if (!act) { + return; + } + while (act->curves.first) { + FCurve *fcu = act->curves.first; + action_groups_remove_channel(act, fcu); + BKE_fcurve_free(fcu); + } + DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH); +} diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 94b85e42f96..eb4784bebff 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -4074,7 +4074,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float /* objects */ /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets - * this tagged by Depsgraph on framechange. This optimization means that objects + * this tagged by Depsgraph on frame-change. This optimization means that objects * linked from other (not-visible) scenes will not need their data calculated. */ EVAL_ANIM_IDS(main->objects.first, 0); diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index 0007fea62cb..7c09b4a4ce3 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -23,6 +23,7 @@ #include "BLI_string_utils.h" #include "BKE_attribute.h" +#include "BKE_attribute_access.hh" #include "BKE_curves.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" @@ -88,23 +89,7 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM]) } } -static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer) -{ - DomainInfo info[ATTR_DOMAIN_NUM]; - get_domains(id, info); - - for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) { - CustomData *customdata = info[domain].customdata; - if (customdata && - ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) { - return customdata; - } - } - - return nullptr; -} - -bool BKE_id_attributes_supported(ID *id) +bool BKE_id_attributes_supported(const ID *id) { DomainInfo info[ATTR_DOMAIN_NUM]; get_domains(id, info); @@ -116,24 +101,32 @@ bool BKE_id_attributes_supported(ID *id) return false; } +bool BKE_attribute_allow_procedural_access(const char *attribute_name) +{ + return blender::bke::allow_procedural_attribute_access(attribute_name); +} + bool BKE_id_attribute_rename(ID *id, - CustomDataLayer *layer, + const char *old_name, const char *new_name, ReportList *reports) { - if (BKE_id_attribute_required(id, layer)) { + if (BKE_id_attribute_required(id, old_name)) { BLI_assert_msg(0, "Required attribute name is not editable"); return false; } - CustomData *customdata = attribute_customdata_find(id, layer); - if (customdata == nullptr) { + CustomDataLayer *layer = BKE_id_attribute_search( + id, old_name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL); + if (layer == nullptr) { BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); return false; } - BLI_strncpy_utf8(layer->name, new_name, sizeof(layer->name)); - CustomData_set_layer_unique_name(customdata, layer - customdata->layers); + char result_name[MAX_CUSTOMDATA_LAYER_NAME]; + BKE_id_attribute_calc_unique_name(id, new_name, result_name); + BLI_strncpy_utf8(layer->name, result_name, sizeof(layer->name)); + return true; } @@ -177,7 +170,7 @@ bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname) } CustomDataLayer *BKE_id_attribute_new( - ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports) + ID *id, const char *name, const int type, const eAttrDomain domain, ReportList *reports) { DomainInfo info[ATTR_DOMAIN_NUM]; get_domains(id, info); @@ -215,50 +208,79 @@ CustomDataLayer *BKE_id_attribute_new( return (index == -1) ? nullptr : &(customdata->layers[index]); } -bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports) +CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList *reports) { - CustomData *customdata = attribute_customdata_find(id, layer); - const int index = (customdata) ? - CustomData_get_named_layer_index(customdata, layer->type, layer->name) : - -1; - - if (index == -1) { + const CustomDataLayer *src_layer = BKE_id_attribute_search( + id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL); + if (src_layer == nullptr) { BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); - return false; + return nullptr; + } + + const eCustomDataType type = (eCustomDataType)src_layer->type; + const eAttrDomain domain = BKE_id_attribute_domain(id, src_layer); + + /* Make a copy of name in case CustomData API reallocates the layers. */ + const std::string name_copy = name; + + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + CustomData *customdata = info[domain].customdata; + + CustomDataLayer *new_layer = BKE_id_attribute_new(id, name_copy.c_str(), type, domain, reports); + if (new_layer == nullptr) { + return nullptr; } - if (BKE_id_attribute_required(id, layer)) { + const int from_index = CustomData_get_named_layer_index(customdata, type, name_copy.c_str()); + const int to_index = CustomData_get_named_layer_index(customdata, type, new_layer->name); + CustomData_copy_data_layer( + customdata, customdata, from_index, to_index, 0, 0, info[domain].length); + + return new_layer; +} + +bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports) +{ + if (BKE_id_attribute_required(id, name)) { BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed"); return false; } + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + switch (GS(id->name)) { case ID_ME: { - Mesh *me = (Mesh *)id; - BMEditMesh *em = me->edit_mesh; - if (em != nullptr) { - BM_data_layer_free(em->bm, customdata, layer->type); - } - else { - const int length = BKE_id_attribute_data_length(id, layer); - CustomData_free_layer(customdata, layer->type, length, index); + Mesh *mesh = reinterpret_cast<Mesh *>(id); + if (BMEditMesh *em = mesh->edit_mesh) { + for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) { + if (CustomData *data = info[domain].customdata) { + if (BM_data_layer_free_named(em->bm, data, name)) { + return true; + } + } + } + return false; } - break; - } - default: { - const int length = BKE_id_attribute_data_length(id, layer); - CustomData_free_layer(customdata, layer->type, length, index); - break; + ATTR_FALLTHROUGH; } + default: + for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) { + if (CustomData *data = info[domain].customdata) { + if (CustomData_free_layer_named(data, name, info[domain].length)) { + return true; + } + } + } + return false; } - - return true; } CustomDataLayer *BKE_id_attribute_find(const ID *id, const char *name, const int type, - const AttributeDomain domain) + const eAttrDomain domain) { DomainInfo info[ATTR_DOMAIN_NUM]; get_domains(id, info); @@ -278,7 +300,37 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id, return nullptr; } -int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, CustomDataMask mask) +CustomDataLayer *BKE_id_attribute_search(ID *id, + const char *name, + const eCustomDataMask type_mask, + const eAttrDomainMask domain_mask) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + for (eAttrDomain domain = ATTR_DOMAIN_POINT; domain < ATTR_DOMAIN_NUM; + domain = static_cast<eAttrDomain>((static_cast<int>(domain)) + 1)) { + if (!(domain_mask & ATTR_DOMAIN_AS_MASK(domain))) { + continue; + } + + CustomData *customdata = info[domain].customdata; + if (customdata == nullptr) { + continue; + } + + for (int i = 0; i < customdata->totlayer; i++) { + CustomDataLayer *layer = &customdata->layers[i]; + if ((CD_TYPE_AS_MASK(layer->type) & type_mask) && STREQ(layer->name, name)) { + return layer; + } + } + } + + return nullptr; +} + +int BKE_id_attributes_length(const ID *id, eAttrDomainMask domain_mask, eCustomDataMask mask) { DomainInfo info[ATTR_DOMAIN_NUM]; get_domains(id, info); @@ -296,7 +348,7 @@ int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, Cust return length; } -AttributeDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer) +eAttrDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer) { DomainInfo info[ATTR_DOMAIN_NUM]; get_domains(id, info); @@ -305,12 +357,12 @@ AttributeDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *lay CustomData *customdata = info[domain].customdata; if (customdata && ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) { - return static_cast<AttributeDomain>(domain); + return static_cast<eAttrDomain>(domain); } } BLI_assert_msg(0, "Custom data layer not found in geometry"); - return static_cast<AttributeDomain>(ATTR_DOMAIN_POINT); + return static_cast<eAttrDomain>(ATTR_DOMAIN_POINT); } int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) @@ -344,14 +396,14 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) return 0; } -bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer) +bool BKE_id_attribute_required(const ID *id, const char *name) { switch (GS(id->name)) { case ID_PT: { - return BKE_pointcloud_customdata_required((PointCloud *)id, layer); + return BKE_pointcloud_customdata_required((const PointCloud *)id, name); } case ID_CV: { - return BKE_curves_customdata_required((Curves *)id, layer); + return BKE_curves_customdata_required((const Curves *)id, name); } default: return false; @@ -453,8 +505,8 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye CustomDataLayer *BKE_id_attribute_from_index(ID *id, int lookup_index, - AttributeDomainMask domain_mask, - CustomDataMask layer_mask) + eAttrDomainMask domain_mask, + eCustomDataMask layer_mask) { DomainInfo info[ATTR_DOMAIN_NUM]; get_domains(id, info); @@ -487,27 +539,27 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id, /** Get list of domain types but with ATTR_DOMAIN_FACE and * ATTR_DOMAIN_CORNER swapped. */ -static void get_domains_types(AttributeDomain domains[ATTR_DOMAIN_NUM]) +static void get_domains_types(eAttrDomain domains[ATTR_DOMAIN_NUM]) { for (const int i : IndexRange(ATTR_DOMAIN_NUM)) { - domains[i] = static_cast<AttributeDomain>(i); + domains[i] = static_cast<eAttrDomain>(i); } /* Swap corner and face. */ - SWAP(AttributeDomain, domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]); + SWAP(eAttrDomain, domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]); } int BKE_id_attribute_to_index(const ID *id, const CustomDataLayer *layer, - AttributeDomainMask domain_mask, - CustomDataMask layer_mask) + eAttrDomainMask domain_mask, + eCustomDataMask layer_mask) { if (!layer) { return -1; } DomainInfo info[ATTR_DOMAIN_NUM]; - AttributeDomain domains[ATTR_DOMAIN_NUM]; + eAttrDomain domains[ATTR_DOMAIN_NUM]; get_domains_types(domains); get_domains(id, info); @@ -517,9 +569,9 @@ int BKE_id_attribute_to_index(const ID *id, continue; } - CustomData *cdata = info[domains[i]].customdata; + const CustomData *cdata = info[domains[i]].customdata; for (int j = 0; j < cdata->totlayer; j++) { - CustomDataLayer *layer_iter = cdata->layers + j; + const CustomDataLayer *layer_iter = cdata->layers + j; if (!(CD_TYPE_AS_MASK(layer_iter->type) & layer_mask) || (layer_iter->flag & CD_FLAG_TEMPORARY)) { @@ -539,11 +591,11 @@ int BKE_id_attribute_to_index(const ID *id, CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id, int active_flag, - AttributeDomainMask domain_mask, - CustomDataMask mask) + eAttrDomainMask domain_mask, + eCustomDataMask mask) { DomainInfo info[ATTR_DOMAIN_NUM]; - AttributeDomain domains[ATTR_DOMAIN_NUM]; + eAttrDomain domains[ATTR_DOMAIN_NUM]; get_domains_types(domains); get_domains(id, info); @@ -577,17 +629,17 @@ CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id, void BKE_id_attribute_subset_active_set(ID *id, CustomDataLayer *layer, int active_flag, - AttributeDomainMask domain_mask, - CustomDataMask mask) + eAttrDomainMask domain_mask, + eCustomDataMask mask) { DomainInfo info[ATTR_DOMAIN_NUM]; - AttributeDomain domains[ATTR_DOMAIN_NUM]; + eAttrDomain domains[ATTR_DOMAIN_NUM]; get_domains_types(domains); get_domains(id, info); for (int i = 0; i < ATTR_DOMAIN_NUM; i++) { - AttributeDomainMask domain_mask2 = (AttributeDomainMask)(1 << domains[i]); + eAttrDomainMask domain_mask2 = (eAttrDomainMask)(1 << domains[i]); if (!(domain_mask2 & domain_mask) || !info[domains[i]].customdata) { continue; @@ -645,6 +697,7 @@ CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name) if (layer == nullptr) { layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER); } + return layer; } diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index e86bac21084..409941623d2 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -55,7 +55,15 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i return stream; } -static int attribute_data_type_complexity(const CustomDataType data_type) +const char *no_procedural_access_message = + "This attribute can not be accessed in a procedural context"; + +bool allow_procedural_attribute_access(StringRef attribute_name) +{ + return !attribute_name.startswith(".selection"); +} + +static int attribute_data_type_complexity(const eCustomDataType data_type) { switch (data_type) { case CD_PROP_BOOL: @@ -85,12 +93,12 @@ static int attribute_data_type_complexity(const CustomDataType data_type) } } -CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types) +eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types) { int highest_complexity = INT_MIN; - CustomDataType most_complex_type = CD_PROP_COLOR; + eCustomDataType most_complex_type = CD_PROP_COLOR; - for (const CustomDataType data_type : data_types) { + for (const eCustomDataType data_type : data_types) { const int complexity = attribute_data_type_complexity(data_type); if (complexity > highest_complexity) { highest_complexity = complexity; @@ -105,7 +113,7 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_ * \note Generally the order should mirror the order of the domains * established in each component's ComponentAttributeProviders. */ -static int attribute_domain_priority(const AttributeDomain domain) +static int attribute_domain_priority(const eAttrDomain domain) { switch (domain) { case ATTR_DOMAIN_INSTANCE: @@ -127,12 +135,12 @@ static int attribute_domain_priority(const AttributeDomain domain) } } -AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) +eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains) { int highest_priority = INT_MIN; - AttributeDomain highest_priority_domain = ATTR_DOMAIN_CORNER; + eAttrDomain highest_priority_domain = ATTR_DOMAIN_CORNER; - for (const AttributeDomain domain : domains) { + for (const eAttrDomain domain : domains) { const int priority = attribute_domain_priority(domain); if (priority > highest_priority) { highest_priority = priority; @@ -183,7 +191,7 @@ static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer } static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data, - const CustomDataType data_type, + const eCustomDataType data_type, const int domain_num, const AttributeInit &initializer) { @@ -218,7 +226,7 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data } static void *add_generic_custom_data_layer(CustomData &custom_data, - const CustomDataType data_type, + const eCustomDataType data_type, const eCDAllocType alloctype, void *layer_data, const int domain_num, @@ -237,7 +245,7 @@ static void *add_generic_custom_data_layer(CustomData &custom_data, static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, CustomData &custom_data, - const CustomDataType data_type, + const eCustomDataType data_type, const int domain_num, const AttributeInit &initializer) { @@ -367,27 +375,24 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co } const int domain_num = component.attribute_domain_num(domain_); - int layer_index; if (stored_as_named_attribute_) { - for (const int i : IndexRange(custom_data->totlayer)) { - if (custom_data_layer_matches_attribute_id(custom_data->layers[i], name_)) { - layer_index = i; - break; + if (CustomData_free_layer_named(custom_data, name_.c_str(), domain_num)) { + if (custom_data_access_.update_custom_data_pointers) { + custom_data_access_.update_custom_data_pointers(component); } + return true; } - } - else { - layer_index = CustomData_get_layer_index(custom_data, stored_type_); + return false; } - const bool delete_success = CustomData_free_layer( - custom_data, stored_type_, domain_num, layer_index); - if (delete_success) { + const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); + if (CustomData_free_layer(custom_data, stored_type_, domain_num, layer_index)) { if (custom_data_access_.update_custom_data_pointers) { custom_data_access_.update_custom_data_pointers(component); } + return true; } - return delete_success; + return false; } bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, @@ -451,7 +456,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) { continue; } - const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type); + const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type); if (type == nullptr) { continue; } @@ -480,7 +485,7 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write( CustomData_duplicate_referenced_layer_anonymous( custom_data, layer.type, &attribute_id.anonymous_id(), domain_num); } - const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type); + const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type); if (type == nullptr) { continue; } @@ -500,7 +505,7 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, const int domain_num = component.attribute_domain_num(domain_); for (const int i : IndexRange(custom_data->totlayer)) { const CustomDataLayer &layer = custom_data->layers[i]; - if (this->type_is_supported((CustomDataType)layer.type) && + if (this->type_is_supported((eCustomDataType)layer.type) && custom_data_layer_matches_attribute_id(layer, attribute_id)) { CustomData_free_layer(custom_data, layer.type, domain_num, i); return true; @@ -511,8 +516,8 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, bool CustomDataAttributeProvider::try_create(GeometryComponent &component, const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, + const eAttrDomain domain, + const eCustomDataType data_type, const AttributeInit &initializer) const { if (domain_ != domain) { @@ -544,7 +549,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com return true; } for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - const CustomDataType data_type = (CustomDataType)layer.type; + const eCustomDataType data_type = (eCustomDataType)layer.type; if (this->type_is_supported(data_type)) { AttributeMetaData meta_data{domain_, data_type}; const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer); @@ -642,7 +647,7 @@ bool NamedLegacyCustomDataProvider::foreach_attribute( } void NamedLegacyCustomDataProvider::foreach_domain( - const FunctionRef<void(AttributeDomain)> callback) const + const FunctionRef<void(eAttrDomain)> callback) const { callback(domain_); } @@ -685,7 +690,7 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at { for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) { if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { - const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type); + const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type); BLI_assert(cpp_type != nullptr); return GSpan(*cpp_type, layer.data, size_); } @@ -694,7 +699,7 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at } GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, + const eCustomDataType data_type, const void *default_value) const { const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); @@ -718,7 +723,7 @@ std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeI { for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) { if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { - const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type); + const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type); BLI_assert(cpp_type != nullptr); return GMutableSpan(*cpp_type, layer.data, size_); } @@ -727,7 +732,7 @@ std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeI } bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, - const CustomDataType data_type) + const eCustomDataType data_type) { void *result = add_generic_custom_data_layer( data, data_type, CD_DEFAULT, nullptr, size_, attribute_id); @@ -735,7 +740,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, } bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id, - const CustomDataType data_type, + const eCustomDataType data_type, void *buffer) { void *result = add_generic_custom_data_layer( @@ -768,10 +773,10 @@ void CustomDataAttributes::clear() } bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback, - const AttributeDomain domain) const + const eAttrDomain domain) const { for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) { - AttributeMetaData meta_data{domain, (CustomDataType)layer.type}; + AttributeMetaData meta_data{domain, (eCustomDataType)layer.type}; const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer); if (!callback(attribute_id, meta_data)) { return false; @@ -811,7 +816,7 @@ const blender::bke::ComponentAttributeProviders *GeometryComponent::get_attribut return nullptr; } -bool GeometryComponent::attribute_domain_supported(const AttributeDomain domain) const +bool GeometryComponent::attribute_domain_supported(const eAttrDomain domain) const { using namespace blender::bke; const ComponentAttributeProviders *providers = this->get_attribute_providers(); @@ -821,7 +826,7 @@ bool GeometryComponent::attribute_domain_supported(const AttributeDomain domain) return providers->supported_domains().contains(domain); } -int GeometryComponent::attribute_domain_num(const AttributeDomain UNUSED(domain)) const +int GeometryComponent::attribute_domain_num(const eAttrDomain UNUSED(domain)) const { return 0; } @@ -869,8 +874,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( blender::GVArray GeometryComponent::attribute_try_adapt_domain_impl( const blender::GVArray &varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const + const eAttrDomain from_domain, + const eAttrDomain to_domain) const { if (from_domain == to_domain) { return varray; @@ -941,8 +946,8 @@ void GeometryComponent::attributes_remove_anonymous() } bool GeometryComponent::attribute_try_create(const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, + const eAttrDomain domain, + const eCustomDataType data_type, const AttributeInit &initializer) { using namespace blender::bke; @@ -1079,8 +1084,8 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray, blender::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type) const + const eAttrDomain domain, + const eCustomDataType data_type) const { blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id); if (!attribute) { @@ -1108,7 +1113,7 @@ blender::GVArray GeometryComponent::attribute_try_get_for_read( } blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeIDRef &attribute_id, - const AttributeDomain domain) const + const eAttrDomain domain) const { if (!this->attribute_domain_supported(domain)) { return {}; @@ -1127,7 +1132,7 @@ blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeID } blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( - const AttributeIDRef &attribute_id, const CustomDataType data_type) const + const AttributeIDRef &attribute_id, const eCustomDataType data_type) const { blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id); if (!attribute) { @@ -1144,8 +1149,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( } blender::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, + const eAttrDomain domain, + const eCustomDataType data_type, const void *default_value) const { blender::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type); @@ -1206,8 +1211,8 @@ static void save_output_attribute(OutputAttribute &output_attribute) else { attribute_id = varray.anonymous_attribute_id.extract(); } - const AttributeDomain domain = output_attribute.domain(); - const CustomDataType data_type = output_attribute.custom_data_type(); + const eAttrDomain domain = output_attribute.domain(); + const eCustomDataType data_type = output_attribute.custom_data_type(); const CPPType &cpp_type = output_attribute.cpp_type(); component.attribute_try_delete(attribute_id); @@ -1244,8 +1249,8 @@ static std::function<void(OutputAttribute &)> get_simple_output_attribute_save_m static OutputAttribute create_output_attribute(GeometryComponent &component, const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, + const eAttrDomain domain, + const eCustomDataType data_type, const bool ignore_old_values, const void *default_value) { @@ -1350,17 +1355,15 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, } OutputAttribute GeometryComponent::attribute_try_get_for_output(const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, + const eAttrDomain domain, + const eCustomDataType data_type, const void *default_value) { return create_output_attribute(*this, attribute_id, domain, data_type, false, default_value); } OutputAttribute GeometryComponent::attribute_try_get_for_output_only( - const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type) + const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type) { return create_output_attribute(*this, attribute_id, domain, data_type, true, nullptr); } @@ -1374,17 +1377,17 @@ GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &conte if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); + const eAttrDomain domain = geometry_context->domain(); return this->get_varray_for_context(component, domain, mask); } return {}; } GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const { - const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); + const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); return component.attribute_try_get_for_read(name_, domain, data_type); } @@ -1408,7 +1411,7 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return false; } -static StringRef get_random_id_attribute_name(const AttributeDomain domain) +static StringRef get_random_id_attribute_name(const eAttrDomain domain) { switch (domain) { case ATTR_DOMAIN_POINT: @@ -1420,7 +1423,7 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain) } GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const { @@ -1453,10 +1456,10 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const } GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const { - const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); + const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type); } diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index f0f47cb7a11..ac43754dd1a 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -47,16 +47,16 @@ class BuiltinAttributeProvider { protected: const std::string name_; - const AttributeDomain domain_; - const CustomDataType data_type_; + const eAttrDomain domain_; + const eCustomDataType data_type_; const CreatableEnum createable_; const WritableEnum writable_; const DeletableEnum deletable_; public: BuiltinAttributeProvider(std::string name, - const AttributeDomain domain, - const CustomDataType data_type, + const eAttrDomain domain, + const eCustomDataType data_type, const CreatableEnum createable, const WritableEnum writable, const DeletableEnum deletable) @@ -81,12 +81,12 @@ class BuiltinAttributeProvider { return name_; } - AttributeDomain domain() const + eAttrDomain domain() const { return domain_; } - CustomDataType data_type() const + eCustomDataType data_type() const { return data_type_; } @@ -106,8 +106,8 @@ class DynamicAttributesProvider { const AttributeIDRef &attribute_id) const = 0; virtual bool try_create(GeometryComponent &UNUSED(component), const AttributeIDRef &UNUSED(attribute_id), - const AttributeDomain UNUSED(domain), - const CustomDataType UNUSED(data_type), + const eAttrDomain UNUSED(domain), + const eCustomDataType UNUSED(data_type), const AttributeInit &UNUSED(initializer)) const { /* Some providers should not create new attributes. */ @@ -116,7 +116,7 @@ class DynamicAttributesProvider { virtual bool foreach_attribute(const GeometryComponent &component, const AttributeForeachCallback callback) const = 0; - virtual void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const = 0; + virtual void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const = 0; }; /** @@ -128,11 +128,11 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL | CD_MASK_PROP_INT8 | CD_MASK_PROP_BYTE_COLOR; - const AttributeDomain domain_; + const eAttrDomain domain_; const CustomDataAccessInfo custom_data_access_; public: - CustomDataAttributeProvider(const AttributeDomain domain, + CustomDataAttributeProvider(const eAttrDomain domain, const CustomDataAccessInfo custom_data_access) : domain_(domain), custom_data_access_(custom_data_access) { @@ -148,20 +148,20 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { bool try_create(GeometryComponent &component, const AttributeIDRef &attribute_id, - AttributeDomain domain, - const CustomDataType data_type, + eAttrDomain domain, + const eCustomDataType data_type, const AttributeInit &initializer) const final; bool foreach_attribute(const GeometryComponent &component, const AttributeForeachCallback callback) const final; - void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final + void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final { callback(domain_); } private: - bool type_is_supported(CustomDataType data_type) const + bool type_is_supported(eCustomDataType data_type) const { return ((1ULL << data_type) & supported_types_mask) != 0; } @@ -174,17 +174,17 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { private: using AsReadAttribute = GVArray (*)(const void *data, int domain_num); using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num); - const AttributeDomain domain_; - const CustomDataType attribute_type_; - const CustomDataType stored_type_; + const eAttrDomain domain_; + const eCustomDataType attribute_type_; + const eCustomDataType stored_type_; const CustomDataAccessInfo custom_data_access_; const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; public: - NamedLegacyCustomDataProvider(const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, + NamedLegacyCustomDataProvider(const eAttrDomain domain, + const eCustomDataType attribute_type, + const eCustomDataType stored_type, const CustomDataAccessInfo custom_data_access, const AsReadAttribute as_read_attribute, const AsWriteAttribute as_write_attribute) @@ -204,7 +204,7 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final; bool foreach_attribute(const GeometryComponent &component, const AttributeForeachCallback callback) const final; - void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final; + void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final; }; template<typename T> GVArray make_array_read_attribute(const void *data, const int domain_num) @@ -230,7 +230,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num); using UpdateOnRead = void (*)(const GeometryComponent &component); using UpdateOnWrite = void (*)(GeometryComponent &component); - const CustomDataType stored_type_; + const eCustomDataType stored_type_; const CustomDataAccessInfo custom_data_access_; const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; @@ -239,9 +239,9 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { public: BuiltinCustomDataLayerProvider(std::string attribute_name, - const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, + const eAttrDomain domain, + const eCustomDataType attribute_type, + const eCustomDataType stored_type, const CreatableEnum creatable, const WritableEnum writable, const DeletableEnum deletable, @@ -288,7 +288,7 @@ class ComponentAttributeProviders { /** * All the domains that are supported by at least one of the providers above. */ - VectorSet<AttributeDomain> supported_domains_; + VectorSet<eAttrDomain> supported_domains_; public: ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers, @@ -301,7 +301,7 @@ class ComponentAttributeProviders { supported_domains_.add(provider->domain()); } for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) { - provider->foreach_domain([&](AttributeDomain domain) { supported_domains_.add(domain); }); + provider->foreach_domain([&](eAttrDomain domain) { supported_domains_.add(domain); }); } } @@ -315,7 +315,7 @@ class ComponentAttributeProviders { return dynamic_attribute_providers_; } - Span<AttributeDomain> supported_domains() const + Span<eAttrDomain> supported_domains() const { return supported_domains_; } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 083d5af063a..1cda0e8a4bb 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -2469,71 +2469,55 @@ float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len } /* TODO: should probably be unified with BrushPainter stuff? */ -unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_secondary) +static bool brush_gen_texture(const Brush *br, + const int side, + const bool use_secondary, + float *rect) { - unsigned int *texcache = NULL; - MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex; - float intensity; - float rgba_dummy[4]; - int ix, iy; - int side = half_side * 2; + const MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex; + if (mtex->tex == NULL) { + return false; + } - if (mtex->tex) { - float x, y, step = 2.0 / side, co[3]; + const float step = 2.0 / side; + int ix, iy; + float x, y; - texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); + /* Do normalized canonical view coords for texture. */ + for (y = -1.0, iy = 0; iy < side; iy++, y += step) { + for (x = -1.0, ix = 0; ix < side; ix++, x += step) { + const float co[3] = {x, y, 0.0f}; - /* do normalized canonical view coords for texture */ - for (y = -1.0, iy = 0; iy < side; iy++, y += step) { - for (x = -1.0, ix = 0; ix < side; ix++, x += step) { - co[0] = x; - co[1] = y; - co[2] = 0.0f; + float intensity; + float rgba_dummy[4]; + RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba_dummy); - /* This is copied from displace modifier code */ - /* TODO(sergey): brush are always caching with CM enabled for now. */ - RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba_dummy); - copy_v4_uchar((uchar *)&texcache[iy * side + ix], (char)(intensity * 255.0f)); - } + rect[iy * side + ix] = intensity; } } - return texcache; + return true; } struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient) { ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture"); - unsigned int *texcache; int side = 512; int half = side / 2; - int i, j; BKE_curvemapping_init(br->curve); - texcache = BKE_brush_gen_texture_cache(br, half, secondary); im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect"); im->x = im->y = side; - if (display_gradient || texcache) { - for (i = 0; i < side; i++) { - for (j = 0; j < side; j++) { - float magn = sqrtf(pow2f(i - half) + pow2f(j - half)); - im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half); - } - } - } + const bool have_texture = brush_gen_texture(br, side, secondary, im->rect_float); - if (texcache) { - /* Modulate curve with texture */ - for (i = 0; i < side; i++) { - for (j = 0; j < side; j++) { - const int col = texcache[i * side + j]; - im->rect_float[i * side + j] *= (((char *)&col)[0] + ((char *)&col)[1] + - ((char *)&col)[2]) / - 3.0f / 255.0f; + if (display_gradient || have_texture) { + for (int i = 0; i < side; i++) { + for (int j = 0; j < side; j++) { + float magn = sqrtf(pow2f(i - half) + pow2f(j - half)); + im->rect_float[i * side + j] *= BKE_brush_curve_strength_clamped(br, magn, half); } } - MEM_freeN(texcache); } return im; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index ab9a27a3996..8622174231c 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1171,7 +1171,7 @@ static Mesh *cloth_make_rest_mesh(ClothModifierData *clmd, Mesh *mesh) for (unsigned i = 0; i < mesh->totvert; i++, verts++) { copy_v3_v3(mvert[i].co, verts->xrest); } - BKE_mesh_normals_tag_dirty(new_mesh); + BKE_mesh_tag_coords_changed(new_mesh); return new_mesh; } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 76c6dc1d5e7..b71bcef229a 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -996,9 +996,11 @@ static void collection_tag_update_parent_recursive(Main *bmain, } } -static Collection *collection_parent_editable_find_recursive(Collection *collection) +static Collection *collection_parent_editable_find_recursive(const ViewLayer *view_layer, + Collection *collection) { - if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) { + if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) && + (view_layer == NULL || BKE_view_layer_has_collection(view_layer, collection))) { return collection; } @@ -1009,10 +1011,16 @@ static Collection *collection_parent_editable_find_recursive(Collection *collect LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->parents) { if (!ID_IS_LINKED(collection_parent->collection) && !ID_IS_OVERRIDE_LIBRARY(collection_parent->collection)) { + if (view_layer != NULL && + !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) { + /* In case this parent collection is not in given view_layer, there is no point in + * searching in its ancestors either, we can skip that whole parenting branch. */ + continue; + } return collection_parent->collection; } Collection *editable_collection = collection_parent_editable_find_recursive( - collection_parent->collection); + view_layer, collection_parent->collection); if (editable_collection != NULL) { return editable_collection; } @@ -1110,11 +1118,23 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob) { + return BKE_collection_viewlayer_object_add(bmain, NULL, collection, ob); +} + +bool BKE_collection_viewlayer_object_add(Main *bmain, + const ViewLayer *view_layer, + Collection *collection, + Object *ob) +{ if (collection == NULL) { return false; } - collection = collection_parent_editable_find_recursive(collection); + collection = collection_parent_editable_find_recursive(view_layer, collection); + + if (collection == NULL) { + return false; + } return BKE_collection_object_add_notest(bmain, collection, ob); } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 35f2f94bc91..aa09541c043 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -949,30 +949,9 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), } \ (void)0 -static void custom_space_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) +static bool is_custom_space_needed(bConstraint *con) { - func(con, (ID **)&con->space_object, false, userdata); -} - -static int get_space_tar(bConstraint *con, ListBase *list) -{ - if (!con || !list || - (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) { - return 0; - } - bConstraintTarget *ct; - SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, list); - return 1; -} - -static void flush_space_tar(bConstraint *con, ListBase *list, bool no_copy) -{ - if (!con || !list || - (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) { - return; - } - bConstraintTarget *ct = (bConstraintTarget *)list->last; - SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, list, no_copy); + return con->ownspace == CONSTRAINT_SPACE_CUSTOM || con->tarspace == CONSTRAINT_SPACE_CUSTOM; } /* --------- ChildOf Constraint ------------ */ @@ -1161,8 +1140,6 @@ static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *use /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int trackto_get_tars(bConstraint *con, ListBase *list) @@ -1174,7 +1151,7 @@ static int trackto_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -1188,7 +1165,6 @@ static void trackto_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -1661,11 +1637,11 @@ static bConstraintTypeInfo CTI_LOCLIMIT = { "Limit Location", /* name */ "bLocLimitConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + NULL, /* id looper */ NULL, /* copy data */ NULL, /* new data */ - get_space_tar, /* get constraint targets */ - flush_space_tar, /* flush constraint targets */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ NULL, /* get target matrix */ loclimit_evaluate, /* evaluate */ }; @@ -1742,11 +1718,11 @@ static bConstraintTypeInfo CTI_ROTLIMIT = { "Limit Rotation", /* name */ "bRotLimitConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + NULL, /* id looper */ NULL, /* copy data */ NULL, /* new data */ - get_space_tar, /* get constraint targets */ - flush_space_tar, /* flush constraint targets */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ NULL, /* get target matrix */ rotlimit_evaluate, /* evaluate */ }; @@ -1809,11 +1785,11 @@ static bConstraintTypeInfo CTI_SIZELIMIT = { "Limit Scale", /* name */ "bSizeLimitConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + NULL, /* id looper */ NULL, /* copy data */ NULL, /* new data */ - get_space_tar, /* get constraint targets */ - flush_space_tar, /* flush constraint targets */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ NULL, /* get target matrix */ sizelimit_evaluate, /* evaluate */ }; @@ -1833,8 +1809,6 @@ static void loclike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int loclike_get_tars(bConstraint *con, ListBase *list) @@ -1846,7 +1820,7 @@ static int loclike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -1860,7 +1834,6 @@ static void loclike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -1933,8 +1906,6 @@ static void rotlike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int rotlike_get_tars(bConstraint *con, ListBase *list) @@ -1946,7 +1917,7 @@ static int rotlike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -1960,7 +1931,6 @@ static void rotlike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -2114,8 +2084,6 @@ static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *us /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int sizelike_get_tars(bConstraint *con, ListBase *list) @@ -2127,7 +2095,7 @@ static int sizelike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -2141,7 +2109,6 @@ static void sizelike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -2239,8 +2206,6 @@ static void translike_id_looper(bConstraint *con, ConstraintIDFunc func, void *u /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int translike_get_tars(bConstraint *con, ListBase *list) @@ -2252,7 +2217,7 @@ static int translike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -2266,7 +2231,6 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -2400,11 +2364,11 @@ static bConstraintTypeInfo CTI_SAMEVOL = { "Maintain Volume", /* name */ "bSameVolumeConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + NULL, /* id looper */ NULL, /* copy data */ samevolume_new_data, /* new data */ - get_space_tar, /* get constraint targets */ - flush_space_tar, /* flush constraint targets */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ NULL, /* get target matrix */ samevolume_evaluate, /* evaluate */ }; @@ -2810,8 +2774,6 @@ static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *user /* action */ func(con, (ID **)&data->act, true, userdata); - - custom_space_id_looper(con, func, userdata); } static int actcon_get_tars(bConstraint *con, ListBase *list) @@ -2823,7 +2785,7 @@ static int actcon_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -2837,7 +2799,6 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -3338,8 +3299,6 @@ static void distlimit_id_looper(bConstraint *con, ConstraintIDFunc func, void *u /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int distlimit_get_tars(bConstraint *con, ListBase *list) @@ -3351,7 +3310,7 @@ static int distlimit_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -3365,7 +3324,6 @@ static void distlimit_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -3694,8 +3652,6 @@ static void minmax_id_looper(bConstraint *con, ConstraintIDFunc func, void *user /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int minmax_get_tars(bConstraint *con, ListBase *list) @@ -3707,7 +3663,7 @@ static int minmax_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -3721,7 +3677,6 @@ static void minmax_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -4019,8 +3974,6 @@ static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *u /* target only */ func(con, (ID **)&data->tar, false, userdata); - - custom_space_id_looper(con, func, userdata); } static int transform_get_tars(bConstraint *con, ListBase *list) @@ -4032,7 +3985,7 @@ static int transform_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1 + get_space_tar(con, list); + return 1; } return 0; @@ -4046,7 +3999,6 @@ static void transform_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); - flush_space_tar(con, list, no_copy); } } @@ -5582,6 +5534,19 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), } } +/** Helper function to invoke the id_looper callback, including custom space. */ +static void con_invoke_id_looper(const bConstraintTypeInfo *cti, + bConstraint *con, + ConstraintIDFunc func, + void *userdata) +{ + if (cti->id_looper) { + cti->id_looper(con, func, userdata); + } + + func(con, (ID **)&con->space_object, false, userdata); +} + void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user) { if (con->data) { @@ -5594,8 +5559,8 @@ void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user) } /* unlink the referenced resources it uses */ - if (do_id_user && cti->id_looper) { - cti->id_looper(con, con_unlink_refs_cb, NULL); + if (do_id_user) { + con_invoke_id_looper(cti, con, con_unlink_refs_cb, NULL); } } @@ -5913,9 +5878,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); if (cti) { - if (cti->id_looper) { - cti->id_looper(con, func, userdata); - } + con_invoke_id_looper(cti, con, func, userdata); } } } @@ -5967,16 +5930,14 @@ static void constraint_copy_data_ex(bConstraint *dst, } /* Fix usercounts for all referenced data that need it. */ - if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - cti->id_looper(dst, con_fix_copied_refs_cb, NULL); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + con_invoke_id_looper(cti, dst, con_fix_copied_refs_cb, NULL); } /* for proxies we don't want to make extern */ if (do_extern) { /* go over used ID-links for this constraint to ensure that they are valid for proxies */ - if (cti->id_looper) { - cti->id_looper(dst, con_extern_cb, NULL); - } + con_invoke_id_looper(cti, dst, con_extern_cb, NULL); } } } @@ -6191,6 +6152,63 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai /* -------- Target-Matrix Stuff ------- */ +int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets) +{ + BLI_listbase_clear(r_targets); + + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + + if (!cti) { + return 0; + } + + int count = 0; + + /* Constraint-specific targets. */ + if (cti->get_constraint_targets) { + count = cti->get_constraint_targets(con, r_targets); + } + + /* Add the custom target. */ + if (is_custom_space_needed(con)) { + bConstraintTarget *ct; + SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, r_targets); + ct->space = CONSTRAINT_SPACE_WORLD; + ct->flag |= CONSTRAINT_TAR_CUSTOM_SPACE; + count++; + } + + return count; +} + +void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy) +{ + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + + if (!cti) { + return; + } + + /* Remove the custom target. */ + bConstraintTarget *ct = (bConstraintTarget *)targets->last; + + if (ct && (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE)) { + BLI_assert(is_custom_space_needed(con)); + + if (!no_copy) { + con->space_object = ct->tar; + BLI_strncpy(con->space_subtarget, ct->subtarget, sizeof(con->space_subtarget)); + } + + BLI_freelinkN(targets, ct); + } + + /* Release the constraint-specific targets. */ + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(con, targets, no_copy); + } +} + void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, Scene *scene, bConstraint *con, diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 4338883853d..5125e010b81 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -44,7 +44,6 @@ #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_object.h" -#include "BKE_spline.hh" #include "BKE_vfont.h" #include "DEG_depsgraph.h" diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 0cd324cfe2c..58380a1a35f 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -315,8 +315,8 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool return result; } -static AttributeDomain get_attribute_domain_for_mesh(const MeshComponent &mesh, - const AttributeIDRef &attribute_id) +static eAttrDomain get_attribute_domain_for_mesh(const MeshComponent &mesh, + const AttributeIDRef &attribute_id) { /* Only use a different domain if it is builtin and must only exist on one domain. */ if (!mesh.attribute_is_builtin(attribute_id)) { @@ -456,7 +456,7 @@ static void copy_main_point_data_to_mesh_faces(const Span<T> src, static void copy_main_point_domain_attribute_to_mesh(const CurvesInfo &curves_info, const ResultOffsets &offsets, - const AttributeDomain dst_domain, + const eAttrDomain dst_domain, const GSpan src_all, GMutableSpan dst_all) { @@ -538,7 +538,7 @@ static void copy_profile_point_data_to_mesh_faces(const Span<T> src, static void copy_profile_point_domain_attribute_to_mesh(const CurvesInfo &curves_info, const ResultOffsets &offsets, - const AttributeDomain dst_domain, + const eAttrDomain dst_domain, const GSpan src_all, GMutableSpan dst_all) { @@ -597,7 +597,7 @@ static void copy_indices_to_offset_ranges(const VArray<T> &src, static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offsets, const Span<int> curve_indices, - const AttributeDomain dst_domain, + const eAttrDomain dst_domain, const GVArray &src, GMutableSpan dst) { @@ -728,11 +728,11 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, } main_attributes.add_new(id); - const AttributeDomain src_domain = meta_data.domain; - const CustomDataType type = meta_data.data_type; + const eAttrDomain src_domain = meta_data.domain; + const eCustomDataType type = meta_data.data_type; GVArray src = main_component.attribute_try_get_for_read(id, src_domain, type); - const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id); + const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id); OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type); if (!dst) { return true; @@ -763,11 +763,11 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, if (!should_add_attribute_to_mesh(profile_component, mesh_component, id)) { return true; } - const AttributeDomain src_domain = meta_data.domain; - const CustomDataType type = meta_data.data_type; + const eAttrDomain src_domain = meta_data.domain; + const eCustomDataType type = meta_data.data_type; GVArray src = profile_component.attribute_try_get_for_read(id, src_domain, type); - const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id); + const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id); OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type); if (!dst) { return true; diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index ab9dd702630..7ad83263b73 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -89,6 +89,10 @@ static void curves_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, dst.curve_offsets = static_cast<int *>(MEM_dupallocN(src.curve_offsets)); + if (curves_src->surface_uv_map != nullptr) { + curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map); + } + dst.runtime = MEM_new<bke::CurvesGeometryRuntime>(__func__); dst.runtime->type_counts = src.runtime->type_counts; @@ -108,6 +112,7 @@ static void curves_free_data(ID *id) BKE_curves_batch_cache_free(curves); MEM_SAFE_FREE(curves->mat); + MEM_SAFE_FREE(curves->surface_uv_map); } static void curves_foreach_id(ID *id, LibraryForeachIDData *data) @@ -148,6 +153,8 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre BLO_write_int32_array(writer, curves->geometry.curve_num + 1, curves->geometry.curve_offsets); + BLO_write_string(writer, curves->surface_uv_map); + BLO_write_pointer_array(writer, curves->totcol, curves->mat); if (curves->adt) { BKE_animdata_blend_write(writer, curves->adt); @@ -167,6 +174,8 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_int32_array(reader, curves->geometry.curve_num + 1, &curves->geometry.curve_offsets); + BLO_read_data_address(reader, &curves->surface_uv_map); + curves->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__); /* Recalculate curve type count cache that isn't saved in files. */ @@ -199,8 +208,8 @@ IDTypeInfo IDType_ID_CV = { /*id_filter */ FILTER_ID_CV, /*main_listbase_index */ INDEX_ID_CV, /*struct_size */ sizeof(Curves), - /*name */ "Hair Curves", - /*name_plural */ "Hair Curves", + /*name */ "Curves", + /*name_plural */ "curves", /*translation_context */ BLT_I18NCONTEXT_ID_CURVES, /*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, /*asset_type_info */ nullptr, @@ -264,9 +273,9 @@ BoundBox *BKE_curves_boundbox_get(Object *ob) return ob->runtime.bb; } -bool BKE_curves_customdata_required(Curves *UNUSED(curves), CustomDataLayer *layer) +bool BKE_curves_customdata_required(const Curves *UNUSED(curves), const char *name) { - return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, ATTR_POSITION); + return STREQ(name, ATTR_POSITION); } Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 0fd58a52f81..b58781ce806 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -18,6 +18,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" +#include "BKE_curves_utils.hh" namespace blender::bke { @@ -35,8 +36,9 @@ static const std::string ATTR_HANDLE_POSITION_RIGHT = "handle_right"; static const std::string ATTR_NURBS_ORDER = "nurbs_order"; static const std::string ATTR_NURBS_WEIGHT = "nurbs_weight"; static const std::string ATTR_NURBS_KNOTS_MODE = "knots_mode"; -static const std::string ATTR_SURFACE_TRIANGLE_INDEX = "surface_triangle_index"; -static const std::string ATTR_SURFACE_TRIANGLE_COORDINATE = "surface_triangle_coordinate"; +static const std::string ATTR_SELECTION_POINT_FLOAT = ".selection_point_float"; +static const std::string ATTR_SELECTION_CURVE_FLOAT = ".selection_curve_float"; +static const std::string ATTR_SURFACE_UV_COORDINATE = "surface_uv_coordinate"; /* -------------------------------------------------------------------- */ /** \name Constructors/Destructor @@ -158,30 +160,29 @@ CurvesGeometry::~CurvesGeometry() /** \name Accessors * \{ */ -static int domain_num(const CurvesGeometry &curves, const AttributeDomain domain) +static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain) { return domain == ATTR_DOMAIN_POINT ? curves.points_num() : curves.curves_num(); } -static CustomData &domain_custom_data(CurvesGeometry &curves, const AttributeDomain domain) +static CustomData &domain_custom_data(CurvesGeometry &curves, const eAttrDomain domain) { return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data; } -static const CustomData &domain_custom_data(const CurvesGeometry &curves, - const AttributeDomain domain) +static const CustomData &domain_custom_data(const CurvesGeometry &curves, const eAttrDomain domain) { return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data; } template<typename T> static VArray<T> get_varray_attribute(const CurvesGeometry &curves, - const AttributeDomain domain, + const eAttrDomain domain, const StringRefNull name, const T default_value) { const int num = domain_num(curves, domain); - const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); + const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); const CustomData &custom_data = domain_custom_data(curves, domain); const T *data = (const T *)CustomData_get_layer_named(&custom_data, type, name.c_str()); @@ -193,12 +194,12 @@ static VArray<T> get_varray_attribute(const CurvesGeometry &curves, template<typename T> static Span<T> get_span_attribute(const CurvesGeometry &curves, - const AttributeDomain domain, + const eAttrDomain domain, const StringRefNull name) { const int num = domain_num(curves, domain); const CustomData &custom_data = domain_custom_data(curves, domain); - const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); + const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); T *data = (T *)CustomData_get_layer_named(&custom_data, type, name.c_str()); if (data == nullptr) { @@ -209,12 +210,12 @@ static Span<T> get_span_attribute(const CurvesGeometry &curves, template<typename T> static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves, - const AttributeDomain domain, + const eAttrDomain domain, const StringRefNull name, const T default_value = T()) { const int num = domain_num(curves, domain); - const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); + const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); CustomData &custom_data = domain_custom_data(curves, domain); T *data = (T *)CustomData_duplicate_referenced_layer_named( @@ -418,24 +419,34 @@ MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes_for_write() return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0); } -VArray<int> CurvesGeometry::surface_triangle_indices() const +Span<float2> CurvesGeometry::surface_uv_coords() const { - return get_varray_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1); + return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE); } -MutableSpan<int> CurvesGeometry::surface_triangle_indices_for_write() +MutableSpan<float2> CurvesGeometry::surface_uv_coords_for_write() { - return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1); + return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE); } -Span<float2> CurvesGeometry::surface_triangle_coords() const +VArray<float> CurvesGeometry::selection_point_float() const { - return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE); + return get_varray_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_SELECTION_POINT_FLOAT, 1.0f); } -MutableSpan<float2> CurvesGeometry::surface_triangle_coords_for_write() +MutableSpan<float> CurvesGeometry::selection_point_float_for_write() { - return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE); + return get_mutable_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_SELECTION_POINT_FLOAT, 1.0f); +} + +VArray<float> CurvesGeometry::selection_curve_float() const +{ + return get_varray_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_SELECTION_CURVE_FLOAT, 1.0f); +} + +MutableSpan<float> CurvesGeometry::selection_curve_float_for_write() +{ + return get_mutable_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_SELECTION_CURVE_FLOAT, 1.0f); } /** \} */ @@ -540,16 +551,8 @@ IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type, const IndexMask selection, Vector<int64_t> &r_indices) const { - if (this->curve_type_counts()[type] == this->curves_num()) { - return selection; - } - const VArray<int8_t> types = this->curve_types(); - if (types.is_single()) { - return types.get_internal_single() == type ? IndexMask(this->curves_num()) : IndexMask(0); - } - Span<int8_t> types_span = types.get_internal_span(); - return index_mask_ops::find_indices_based_on_predicate( - selection, 1024, r_indices, [&](const int index) { return types_span[index] == type; }); + return curves::indices_for_type( + this->curve_types(), this->curve_type_counts(), type, selection, r_indices); } void CurvesGeometry::ensure_nurbs_basis_cache() const @@ -1084,7 +1087,7 @@ void CurvesGeometry::update_customdata_pointers() static void *ensure_customdata_layer(CustomData &custom_data, const StringRefNull name, - const CustomDataType data_type, + const eCustomDataType data_type, const int tot_elements) { for (const int other_layer_i : IndexRange(custom_data.totlayer)) { @@ -1097,6 +1100,165 @@ static void *ensure_customdata_layer(CustomData &custom_data, &custom_data, data_type, CD_DEFAULT, nullptr, tot_elements, name.c_str()); } +static void copy_between_buffers(const CPPType &type, + const void *src_buffer, + void *dst_buffer, + const IndexRange src_range, + const IndexRange dst_range) +{ + BLI_assert(src_range.size() == dst_range.size()); + type.copy_construct_n(POINTER_OFFSET(src_buffer, type.size() * src_range.start()), + POINTER_OFFSET(dst_buffer, type.size() * dst_range.start()), + src_range.size()); +} + +template<typename T> +static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst) +{ + threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) { + for (const int i : range) { + dst[i] = src[map[i]]; + } + }); +} + +static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst) +{ + attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { + using T = decltype(dummy); + copy_with_map(src.typed<T>(), map, dst.typed<T>()); + }); +} + +/** + * Builds an array that for every point, contains the corresponding curve index. + */ +static Array<int> build_point_to_curve_map(const CurvesGeometry &curves) +{ + Array<int> point_to_curve_map(curves.points_num()); + threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange curves_range) { + for (const int i_curve : curves_range) { + point_to_curve_map.as_mutable_span().slice(curves.points_for_curve(i_curve)).fill(i_curve); + } + }); + return point_to_curve_map; +} + +static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, + const IndexMask points_to_delete) +{ + /* Use a map from points to curves to facilitate using an #IndexMask input. */ + const Array<int> point_to_curve_map = build_point_to_curve_map(curves); + + const Vector<IndexRange> copy_point_ranges = points_to_delete.extract_ranges_invert( + curves.points_range()); + + /* For every range of points to copy, find the offset in the result curves point layers. */ + int new_point_count = 0; + Array<int> copy_point_range_dst_offsets(copy_point_ranges.size()); + for (const int i : copy_point_ranges.index_range()) { + copy_point_range_dst_offsets[i] = new_point_count; + new_point_count += copy_point_ranges[i].size(); + } + BLI_assert(new_point_count == (curves.points_num() - points_to_delete.size())); + + /* Find out how many non-deleted points there are in every curve. */ + Array<int> curve_point_counts(curves.curves_num(), 0); + for (const IndexRange range : copy_point_ranges) { + for (const int point_i : range) { + curve_point_counts[point_to_curve_map[point_i]]++; + } + } + + /* Build the offsets for the new curve points, skipping curves that had all points deleted. + * Also store the original indices of the corresponding input curves, to facilitate parallel + * copying of curve domain data. */ + int new_curve_count = 0; + int curve_point_offset = 0; + Vector<int> new_curve_offsets; + Vector<int> new_curve_orig_indices; + new_curve_offsets.append(0); + for (const int i : curve_point_counts.index_range()) { + if (curve_point_counts[i] > 0) { + curve_point_offset += curve_point_counts[i]; + new_curve_offsets.append(curve_point_offset); + + new_curve_count++; + new_curve_orig_indices.append(i); + } + } + + CurvesGeometry new_curves{new_point_count, new_curve_count}; + + threading::parallel_invoke( + /* Initialize curve offsets. */ + [&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); }, + /* Copy over point attributes. */ + [&]() { + const CustomData &old_point_data = curves.point_data; + CustomData &new_point_data = new_curves.point_data; + for (const int layer_i : IndexRange(old_point_data.totlayer)) { + const CustomDataLayer &old_layer = old_point_data.layers[layer_i]; + const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type); + const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); + + void *dst_buffer = ensure_customdata_layer( + new_point_data, old_layer.name, data_type, new_point_count); + + threading::parallel_for( + copy_point_ranges.index_range(), 128, [&](const IndexRange ranges_range) { + for (const int range_i : ranges_range) { + const IndexRange src_range = copy_point_ranges[range_i]; + copy_between_buffers(type, + old_layer.data, + dst_buffer, + src_range, + {copy_point_range_dst_offsets[range_i], src_range.size()}); + } + }); + } + }, + /* Copy over curve attributes. + * In some cases points are just dissolved, so the the number of + * curves will be the same. That could be optimized in the future. */ + [&]() { + const CustomData &old_curve_data = curves.curve_data; + CustomData &new_curve_data = new_curves.curve_data; + for (const int layer_i : IndexRange(old_curve_data.totlayer)) { + const CustomDataLayer &old_layer = old_curve_data.layers[layer_i]; + const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type); + const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); + + void *dst_buffer = ensure_customdata_layer( + new_curve_data, old_layer.name, data_type, new_curve_count); + + if (new_curves.curves_num() == curves.curves_num()) { + type.copy_construct_n(old_layer.data, dst_buffer, new_curves.curves_num()); + } + else { + copy_with_map({type, old_layer.data, curves.curves_num()}, + new_curve_orig_indices, + {type, dst_buffer, new_curves.curves_num()}); + } + } + }); + + new_curves.update_curve_types(); + + return new_curves; +} + +void CurvesGeometry::remove_points(const IndexMask points_to_delete) +{ + if (points_to_delete.is_empty()) { + return; + } + if (points_to_delete.size() == this->points_num()) { + *this = {}; + } + *this = copy_with_removed_points(*this, points_to_delete); +} + static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, const IndexMask curves_to_delete) { @@ -1153,23 +1315,20 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, CustomData &new_point_data = new_curves.point_data; for (const int layer_i : IndexRange(old_point_data.totlayer)) { const CustomDataLayer &old_layer = old_point_data.layers[layer_i]; - const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type); + const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type); const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); - const void *src_buffer = old_layer.data; void *dst_buffer = ensure_customdata_layer( new_point_data, old_layer.name, data_type, new_tot_points); threading::parallel_for( old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) { for (const int range_i : ranges_range) { - const IndexRange old_point_range = old_point_ranges[range_i]; - const IndexRange new_point_range = new_point_ranges[range_i]; - - type.copy_construct_n( - POINTER_OFFSET(src_buffer, type.size() * old_point_range.start()), - POINTER_OFFSET(dst_buffer, type.size() * new_point_range.start()), - old_point_range.size()); + copy_between_buffers(type, + old_layer.data, + dst_buffer, + old_point_ranges[range_i], + new_point_ranges[range_i]); } }); } @@ -1180,23 +1339,20 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, CustomData &new_curve_data = new_curves.curve_data; for (const int layer_i : IndexRange(old_curve_data.totlayer)) { const CustomDataLayer &old_layer = old_curve_data.layers[layer_i]; - const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type); + const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type); const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); - const void *src_buffer = old_layer.data; void *dst_buffer = ensure_customdata_layer( - new_curve_data, old_layer.name, data_type, new_tot_points); + new_curve_data, old_layer.name, data_type, new_tot_curves); threading::parallel_for( old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) { for (const int range_i : ranges_range) { - const IndexRange old_curve_range = old_curve_ranges[range_i]; - const IndexRange new_curve_range = new_curve_ranges[range_i]; - - type.copy_construct_n( - POINTER_OFFSET(src_buffer, type.size() * old_curve_range.start()), - POINTER_OFFSET(dst_buffer, type.size() * new_curve_range.start()), - old_curve_range.size()); + copy_between_buffers(type, + old_layer.data, + dst_buffer, + old_curve_ranges[range_i], + new_curve_ranges[range_i]); } }); } @@ -1209,6 +1365,13 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, void CurvesGeometry::remove_curves(const IndexMask curves_to_delete) { + if (curves_to_delete.is_empty()) { + return; + } + if (curves_to_delete.size() == this->curves_num()) { + *this = {}; + return; + } *this = copy_with_removed_curves(*this, curves_to_delete); } @@ -1246,7 +1409,7 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves, static bool layer_matches_name_and_type(const CustomDataLayer &layer, const StringRef name, - const CustomDataType type) + const eCustomDataType type) { if (layer.type != type) { return false; @@ -1289,7 +1452,7 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) continue; } - const CustomDataType data_type = static_cast<CustomDataType>(layer.type); + const eCustomDataType data_type = static_cast<eCustomDataType>(layer.type); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); reverse_curve_point_data<T>( @@ -1312,6 +1475,27 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) this->tag_topology_changed(); } +void CurvesGeometry::remove_attributes_based_on_types() +{ + const int points_num = this->points_num(); + const int curves_num = this->curves_num(); + if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) { + CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_LEFT.c_str(), points_num); + CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_RIGHT.c_str(), points_num); + CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_LEFT.c_str(), points_num); + CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_RIGHT.c_str(), points_num); + } + if (!this->has_curve_with_type(CURVE_TYPE_NURBS)) { + CustomData_free_layer_named(&this->point_data, ATTR_NURBS_WEIGHT.c_str(), points_num); + CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_ORDER.c_str(), curves_num); + CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_KNOTS_MODE.c_str(), curves_num); + } + if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) { + CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num); + } + this->update_customdata_pointers(); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1408,8 +1592,8 @@ static GVArray adapt_curve_domain_curve_to_point(const CurvesGeometry &curves, } GVArray CurvesGeometry::adapt_domain(const GVArray &varray, - const AttributeDomain from, - const AttributeDomain to) const + const eAttrDomain from, + const eAttrDomain to) const { if (!varray) { return {}; diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc index 78c2382b62f..802469399ab 100644 --- a/source/blender/blenkernel/intern/curves_utils.cc +++ b/source/blender/blenkernel/intern/curves_utils.cc @@ -4,6 +4,8 @@ * \ingroup bke */ +#include "BLI_index_mask_ops.hh" + #include "BKE_curves_utils.hh" namespace blender::bke::curves { @@ -35,4 +37,86 @@ void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int counts_to_offsets.last() = offset; } +void copy_point_data(const CurvesGeometry &src_curves, + const CurvesGeometry &dst_curves, + const Span<IndexRange> curve_ranges, + const GSpan src, + GMutableSpan dst) +{ + threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) { + for (const IndexRange range : curve_ranges.slice(range)) { + const IndexRange src_points = src_curves.points_for_curves(range); + const IndexRange dst_points = dst_curves.points_for_curves(range); + /* The arrays might be large, so a threaded copy might make sense here too. */ + dst.slice(dst_points).copy_from(src.slice(src_points)); + } + }); +} + +void copy_point_data(const CurvesGeometry &src_curves, + const CurvesGeometry &dst_curves, + const IndexMask src_curve_selection, + const GSpan src, + GMutableSpan dst) +{ + threading::parallel_for(src_curve_selection.index_range(), 512, [&](IndexRange range) { + for (const int i : src_curve_selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + /* The arrays might be large, so a threaded copy might make sense here too. */ + dst.slice(dst_points).copy_from(src.slice(src_points)); + } + }); +} + +void fill_points(const CurvesGeometry &curves, + const IndexMask curve_selection, + const GPointer value, + GMutableSpan dst) +{ + BLI_assert(*value.type() == dst.type()); + const CPPType &type = dst.type(); + threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) { + for (const int i : curve_selection.slice(range)) { + const IndexRange points = curves.points_for_curve(i); + type.fill_assign_n(value.get(), dst.slice(curves.points_for_curve(i)).data(), points.size()); + } + }); +} + +IndexMask indices_for_type(const VArray<int8_t> &types, + const std::array<int, CURVE_TYPES_NUM> &type_counts, + const CurveType type, + const IndexMask selection, + Vector<int64_t> &r_indices) +{ + if (type_counts[type] == types.size()) { + return selection; + } + if (types.is_single()) { + return types.get_internal_single() == type ? IndexMask(types.size()) : IndexMask(0); + } + Span<int8_t> types_span = types.get_internal_span(); + return index_mask_ops::find_indices_based_on_predicate( + selection, 4096, r_indices, [&](const int index) { return types_span[index] == type; }); +} + +void foreach_curve_by_type(const VArray<int8_t> &types, + const std::array<int, CURVE_TYPES_NUM> &counts, + const IndexMask selection, + FunctionRef<void(IndexMask)> catmull_rom_fn, + FunctionRef<void(IndexMask)> poly_fn, + FunctionRef<void(IndexMask)> bezier_fn, + FunctionRef<void(IndexMask)> nurbs_fn) +{ + Vector<int64_t> catmull_rom; + Vector<int64_t> poly; + Vector<int64_t> bezier; + Vector<int64_t> nurbs; + catmull_rom_fn(indices_for_type(types, counts, CURVE_TYPE_CATMULL_ROM, selection, catmull_rom)); + poly_fn(indices_for_type(types, counts, CURVE_TYPE_POLY, selection, poly)); + bezier_fn(indices_for_type(types, counts, CURVE_TYPE_BEZIER, selection, bezier)); + nurbs_fn(indices_for_type(types, counts, CURVE_TYPE_NURBS, selection, nurbs)); +} + } // namespace blender::bke::curves diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index ac2f1a31836..fd587e9003e 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -20,6 +20,7 @@ #include "BLI_bitmap.h" #include "BLI_color.hh" #include "BLI_endian_switch.h" +#include "BLI_index_range.hh" #include "BLI_math.h" #include "BLI_math_color_blend.h" #include "BLI_math_vector.hh" @@ -27,6 +28,7 @@ #include "BLI_path_util.h" #include "BLI_span.hh" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BLI_string_utils.h" #include "BLI_utildefines.h" @@ -55,7 +57,9 @@ /* only for customdata_data_transfer_interp_normal_normals */ #include "data_transfer_intern.h" +using blender::IndexRange; using blender::Span; +using blender::StringRef; using blender::Vector; /* number of layers to add when growing a CustomData object */ @@ -260,8 +264,8 @@ static void layerInterp_mdeformvert(const void **sources, }; MDeformVert *dvert = static_cast<MDeformVert *>(dest); - struct MDeformWeight_Link *dest_dwlink = nullptr; - struct MDeformWeight_Link *node; + MDeformWeight_Link *dest_dwlink = nullptr; + MDeformWeight_Link *node; /* build a list of unique def_nrs for dest */ int totweight = 0; @@ -288,7 +292,7 @@ static void layerInterp_mdeformvert(const void **sources, /* if this def_nr is not in the list, add it */ if (!node) { - struct MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>( + MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>( alloca(sizeof(*tmp_dwlink))); tmp_dwlink->dw.def_nr = dw->def_nr; tmp_dwlink->dw.weight = weight; @@ -521,6 +525,22 @@ static void layerCopy_propInt(const void *source, void *dest, int count) memcpy(dest, source, sizeof(MIntProperty) * count); } +static void layerInterp_propInt(const void **sources, + const float *weights, + const float *UNUSED(sub_weights), + int count, + void *dest) +{ + float result = 0.0f; + for (const int i : IndexRange(count)) { + const float weight = weights[i]; + const float src = *static_cast<const int *>(sources[i]); + result += src * weight; + } + const int rounded_result = static_cast<int>(round(result)); + *static_cast<int *>(dest) = rounded_result; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1683,7 +1703,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { N_("Int"), layerCopy_propInt, nullptr, - nullptr, + layerInterp_propInt, nullptr}, /* 12: CD_PROP_STRING */ {sizeof(MStringProperty), @@ -2220,9 +2240,9 @@ static bool customdata_typemap_is_valid(const CustomData *data) } #endif -bool CustomData_merge(const struct CustomData *source, - struct CustomData *dest, - CustomDataMask mask, +bool CustomData_merge(const CustomData *source, + CustomData *dest, + eCustomDataMask mask, eCDAllocType alloctype, int totelem) { @@ -2322,9 +2342,9 @@ void CustomData_realloc(CustomData *data, int totelem) } } -void CustomData_copy(const struct CustomData *source, - struct CustomData *dest, - CustomDataMask mask, +void CustomData_copy(const CustomData *source, + CustomData *dest, + eCustomDataMask mask, eCDAllocType alloctype, int totelem) { @@ -2386,7 +2406,7 @@ void CustomData_free(CustomData *data, int totelem) CustomData_reset(data); } -void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask) +void CustomData_free_typemask(CustomData *data, int totelem, eCustomDataMask mask) { for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; @@ -2441,7 +2461,7 @@ int CustomData_get_layer_index(const CustomData *data, int type) return data->typemap[type]; } -int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n) +int CustomData_get_layer_index_n(const CustomData *data, int type, int n) { BLI_assert(n >= 0); int i = CustomData_get_layer_index(data, type); @@ -2498,7 +2518,7 @@ int CustomData_get_stencil_layer_index(const CustomData *data, int type) /* -------------------------------------------------------------------- */ /* index values per layer type */ -int CustomData_get_named_layer(const struct CustomData *data, int type, const char *name) +int CustomData_get_named_layer(const CustomData *data, int type, const char *name) { const int named_index = CustomData_get_named_layer_index(data, type, name); const int layer_index = data->typemap[type]; @@ -2534,7 +2554,7 @@ int CustomData_get_stencil_layer(const CustomData *data, int type) return (layer_index != -1) ? data->layers[layer_index].active_mask : -1; } -const char *CustomData_get_active_layer_name(const struct CustomData *data, const int type) +const char *CustomData_get_active_layer_name(const CustomData *data, const int type) { /* Get the layer index of the active layer of this type. */ const int layer_index = CustomData_get_active_layer_index(data, type); @@ -2625,7 +2645,7 @@ void CustomData_set_layer_stencil_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_flag(struct CustomData *data, int type, int flag) +void CustomData_set_layer_flag(CustomData *data, int type, int flag) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2634,7 +2654,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag) } } -void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag) +void CustomData_clear_layer_flag(CustomData *data, int type, int flag) { const int nflag = ~flag; @@ -2809,7 +2829,7 @@ void *CustomData_add_layer_named(CustomData *data, return nullptr; } -void *CustomData_add_layer_anonymous(struct CustomData *data, +void *CustomData_add_layer_anonymous(CustomData *data, int type, eCDAllocType alloctype, void *layerdata, @@ -2882,6 +2902,18 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index) return true; } +bool CustomData_free_layer_named(CustomData *data, const char *name, const int totelem) +{ + for (const int i : IndexRange(data->totlayer)) { + const CustomDataLayer &layer = data->layers[i]; + if (StringRef(layer.name) == name) { + CustomData_free_layer(data, layer.type, totelem, i); + return true; + } + } + return false; +} + bool CustomData_free_layer_active(CustomData *data, int type, int totelem) { const int index = CustomData_get_active_layer_index(data, type); @@ -2917,7 +2949,7 @@ int CustomData_number_of_layers(const CustomData *data, int type) return number; } -int CustomData_number_of_layers_typemask(const CustomData *data, CustomDataMask mask) +int CustomData_number_of_layers_typemask(const CustomData *data, eCustomDataMask mask) { int number = 0; @@ -3015,7 +3047,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem) } } -bool CustomData_is_referenced_layer(struct CustomData *data, int type) +bool CustomData_is_referenced_layer(CustomData *data, int type) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3060,7 +3092,7 @@ void CustomData_free_temporary(CustomData *data, int totelem) } } -void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask) +void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask) { for (int i = 0; i < data->totlayer; i++) { if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) { @@ -3293,7 +3325,7 @@ void CustomData_interp(const CustomData *source, } } -void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices) +void CustomData_swap_corners(CustomData *data, int index, const int *corner_indices) { for (int i = 0; i < data->totlayer; i++) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); @@ -3306,7 +3338,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn } } -void CustomData_swap(struct CustomData *data, const int index_a, const int index_b) +void CustomData_swap(CustomData *data, const int index_a, const int index_b) { char buff_static[256]; @@ -3385,7 +3417,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n) return data->layers[layer_index].data; } -void *CustomData_get_layer_named(const struct CustomData *data, int type, const char *name) +void *CustomData_get_layer_named(const CustomData *data, int type, const char *name) { int layer_index = CustomData_get_named_layer_index(data, type, name); if (layer_index == -1) { @@ -3452,7 +3484,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr) return ptr; } -void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr) +void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); @@ -3675,7 +3707,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) bool CustomData_bmesh_merge(const CustomData *source, CustomData *dest, - CustomDataMask mask, + eCustomDataMask mask, eCDAllocType alloctype, BMesh *bm, const char htype) @@ -3824,7 +3856,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block) void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, void *block, - const CustomDataMask mask_exclude) + const eCustomDataMask mask_exclude) { if (block == nullptr) { return; @@ -3871,7 +3903,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source, CustomData *dest, void *src_block, void **dest_block, - const CustomDataMask mask_exclude) + const eCustomDataMask mask_exclude) { /* Note that having a version of this function without a 'mask_exclude' * would cause too much duplicate code, so add a check instead. */ @@ -3969,7 +4001,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) return POINTER_OFFSET(block, data->layers[n].offset); } -bool CustomData_layer_has_math(const struct CustomData *data, int layer_n) +bool CustomData_layer_has_math(const CustomData *data, int layer_n) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type); @@ -3981,7 +4013,7 @@ bool CustomData_layer_has_math(const struct CustomData *data, int layer_n) return false; } -bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n) +bool CustomData_layer_has_interp(const CustomData *data, int layer_n) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type); @@ -3992,7 +4024,7 @@ bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n) return false; } -bool CustomData_has_math(const struct CustomData *data) +bool CustomData_has_math(const CustomData *data) { /* interpolates a layer at a time */ for (int i = 0; i < data->totlayer; i++) { @@ -4004,7 +4036,7 @@ bool CustomData_has_math(const struct CustomData *data) return false; } -bool CustomData_bmesh_has_free(const struct CustomData *data) +bool CustomData_bmesh_has_free(const CustomData *data) { for (int i = 0; i < data->totlayer; i++) { if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { @@ -4017,7 +4049,7 @@ bool CustomData_bmesh_has_free(const struct CustomData *data) return false; } -bool CustomData_has_interp(const struct CustomData *data) +bool CustomData_has_interp(const CustomData *data) { /* interpolates a layer at a time */ for (int i = 0; i < data->totlayer; i++) { @@ -4029,7 +4061,7 @@ bool CustomData_has_interp(const struct CustomData *data) return false; } -bool CustomData_has_referenced(const struct CustomData *data) +bool CustomData_has_referenced(const CustomData *data) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].flag & CD_FLAG_NOFREE) { @@ -4488,7 +4520,7 @@ void CustomData_validate_layer_name(const CustomData *data, } } -bool CustomData_verify_versions(struct CustomData *data, int index) +bool CustomData_verify_versions(CustomData *data, int index) { const LayerTypeInfo *typeInfo; CustomDataLayer *layer = &data->layers[index]; @@ -4583,7 +4615,10 @@ static void customdata_external_filename(char filepath[FILE_MAX], BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(id)); } -void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask mask, int totelem) +void CustomData_external_reload(CustomData *data, + ID *UNUSED(id), + eCustomDataMask mask, + int totelem) { for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; @@ -4601,7 +4636,7 @@ void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask } } -void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int totelem) +void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, int totelem) { CustomDataExternal *external = data->external; CustomDataLayer *layer; @@ -4675,7 +4710,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int } void CustomData_external_write( - CustomData *data, ID *id, CustomDataMask mask, int totelem, int free) + CustomData *data, ID *id, eCustomDataMask mask, int totelem, int free) { CustomDataExternal *external = data->external; int update = 0; @@ -5166,7 +5201,7 @@ void CustomData_blend_write(BlendWriter *writer, CustomData *data, Span<CustomDataLayer> layers_to_write, int count, - CustomDataMask cddata_mask, + eCustomDataMask cddata_mask, ID *id) { /* write external customdata (not for undo) */ @@ -5367,7 +5402,7 @@ namespace blender::bke { /** \name Custom Data C++ API * \{ */ -const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type) +const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type) { switch (type) { case CD_PROP_FLOAT: @@ -5392,7 +5427,7 @@ const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type) return nullptr; } -CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) +eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) { if (type.is<float>()) { return CD_PROP_FLOAT; @@ -5418,7 +5453,7 @@ CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) if (type.is<ColorGeometry4b>()) { return CD_PROP_BYTE_COLOR; } - return static_cast<CustomDataType>(-1); + return static_cast<eCustomDataType>(-1); } /** \} */ diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 48f2d66c1cd..a4262e08e39 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2024,13 +2024,13 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * settings.use_threading = (sData->total_points > 1000); BLI_task_parallel_range( 0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings); - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(result); } /* displace */ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { dynamicPaint_applySurfaceDisplace(surface, result); - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(result); } } } diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index f2915a97746..7722c2fa004 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -868,8 +868,6 @@ static void do_texture_effector(EffectorCache *eff, return; } - result[0].nor = result[1].nor = result[2].nor = result[3].nor = NULL; - strength = eff->pd->f_strength * efd->falloff; copy_v3_v3(tex_co, point->loc); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 952d5df299c..0203620df84 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -229,16 +229,13 @@ FCurve *id_data_find_fcurve( return NULL; } - /* Animation takes priority over drivers. */ - if (adt->action && adt->action->curves.first) { - fcu = BKE_fcurve_find(&adt->action->curves, path, index); - } - - /* If not animated, check if driven. */ - if (fcu == NULL && adt->drivers.first) { - fcu = BKE_fcurve_find(&adt->drivers, path, index); - if (fcu && r_driven) { - *r_driven = true; + /* FIXME: The way drivers are handled here (always NULL-ifying `fcu`) is very weird, this needs + * to be re-checked I think?. */ + bool is_driven = false; + fcu = BKE_animadata_fcurve_find_by_rna_path(adt, path, index, NULL, &is_driven); + if (is_driven) { + if (r_driven != NULL) { + *r_driven = is_driven; } fcu = NULL; } @@ -259,12 +256,11 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i /* Check paths of curves, then array indices... */ for (fcu = list->first; fcu; fcu = fcu->next) { + /* Check indices first, much cheaper than a string comparison. */ /* Simple string-compare (this assumes that they have the same root...) */ - if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) { - /* Now check indices. */ - if (fcu->array_index == array_index) { - return fcu; - } + if (UNLIKELY(fcu->array_index == array_index && fcu->rna_path && + fcu->rna_path[0] == rna_path[0] && STREQ(fcu->rna_path, rna_path))) { + return fcu; } } @@ -339,6 +335,47 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con return matches; } +FCurve *BKE_animadata_fcurve_find_by_rna_path( + AnimData *animdata, const char *rna_path, int rna_index, bAction **r_action, bool *r_driven) +{ + if (r_driven != NULL) { + *r_driven = false; + } + if (r_action != NULL) { + *r_action = NULL; + } + + const bool has_action_fcurves = animdata->action != NULL && + !BLI_listbase_is_empty(&animdata->action->curves); + const bool has_drivers = !BLI_listbase_is_empty(&animdata->drivers); + + /* Animation takes priority over drivers. */ + if (has_action_fcurves) { + FCurve *fcu = BKE_fcurve_find(&animdata->action->curves, rna_path, rna_index); + + if (fcu != NULL) { + if (r_action != NULL) { + *r_action = animdata->action; + } + return fcu; + } + } + + /* If not animated, check if driven. */ + if (has_drivers) { + FCurve *fcu = BKE_fcurve_find(&animdata->drivers, rna_path, rna_index); + + if (fcu != NULL) { + if (r_driven != NULL) { + *r_driven = true; + } + return fcu; + } + } + + return NULL; +} + FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, @@ -360,17 +397,18 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *UNUSED(C), bool *r_driven, bool *r_special) { - FCurve *fcu = NULL; - - *r_driven = false; - *r_special = false; - - if (r_animdata) { + if (r_animdata != NULL) { *r_animdata = NULL; } - if (r_action) { + if (r_action != NULL) { *r_action = NULL; } + if (r_driven != NULL) { + *r_driven = false; + } + if (r_special) { + *r_special = false; + } /* Special case for NLA Control Curves... */ if (BKE_nlastrip_has_curves_for_property(ptr, prop)) { @@ -379,59 +417,46 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *UNUSED(C), /* Set the special flag, since it cannot be a normal action/driver * if we've been told to start looking here... */ - *r_special = true; + if (r_special) { + *r_special = true; + } + + *r_driven = false; + if (r_animdata) { + *r_animdata = NULL; + } + if (r_action) { + *r_action = NULL; + } /* The F-Curve either exists or it doesn't here... */ - fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex); - return fcu; + return BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex); } /* There must be some RNA-pointer + property combo. */ if (!prop || !ptr->owner_id || !RNA_property_animateable(ptr, prop)) { - return fcu; + return NULL; } AnimData *adt = BKE_animdata_from_id(ptr->owner_id); if (adt == NULL) { - return fcu; + return NULL; } - const bool has_action_fcurves = adt->action != NULL && - !BLI_listbase_is_empty(&adt->action->curves); - const bool has_drivers = !BLI_listbase_is_empty(&adt->drivers); - /* XXX This function call can become a performance bottleneck. */ - char *path = RNA_path_from_ID_to_property(ptr, prop); - - /* Standard F-Curve - Animation (Action) or Drivers. */ - /* Animation takes priority over drivers. */ - /* XXX: The logic here is duplicated with a function up above. */ - if (has_action_fcurves) { - fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex); - - if (fcu) { - if (r_action) { - *r_action = adt->action; - } - if (r_animdata) { - *r_animdata = adt; - } - } + char *rna_path = RNA_path_from_ID_to_property(ptr, prop); + if (rna_path == NULL) { + return NULL; } - /* If not animated, check if driven. */ - if (fcu == NULL && has_drivers) { - fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex); + /* Standard F-Curve from animdata - Animation (Action) or Drivers. */ + FCurve *fcu = BKE_animadata_fcurve_find_by_rna_path(adt, rna_path, rnaindex, r_action, r_driven); - if (fcu) { - if (r_animdata) { - *r_animdata = adt; - } - *r_driven = true; - } + if (fcu != NULL && r_animdata != NULL) { + *r_animdata = adt; } - MEM_SAFE_FREE(path); + MEM_freeN(rna_path); return fcu; } @@ -999,9 +1024,8 @@ static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt * \{ */ /* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as - * data imported from BVH/Mocap files), which are specialized for use with high density datasets, - * which BezTriples/Keyframe data are ill equipped to do. - */ + * data imported from BVH/motion-capture files), which are specialized for use with high density + * datasets, which BezTriples/Keyframe data are ill equipped to do. */ float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime) { diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 06d32d5bfd4..5cd5a699dec 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -1942,7 +1942,6 @@ static void sample_mesh(FluidFlowSettings *ffs, tex_co[1] = tex_co[1] * 2.0f - 1.0f; tex_co[2] = ffs->texture_offset; } - texres.nor = NULL; BKE_texture_get_value(NULL, ffs->noise_texture, tex_co, &texres, false); emission_strength *= texres.tin; } diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index a28afc8ddca..898869c3c44 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -114,7 +114,7 @@ void CurveComponentLegacy::ensure_owns_direct_data() /** \name Attribute Access Helper Functions * \{ */ -int CurveComponentLegacy::attribute_domain_num(const AttributeDomain domain) const +int CurveComponentLegacy::attribute_domain_num(const eAttrDomain domain) const { if (curve_ == nullptr) { return 0; @@ -308,10 +308,9 @@ static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArra } // namespace blender::bke -GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl( - const GVArray &varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const +GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(const GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) const { if (!varray) { return {}; @@ -366,7 +365,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { public: BuiltinSplineAttributeProvider(std::string attribute_name, - const CustomDataType attribute_type, + const eCustomDataType attribute_type, const WritableEnum writable, const AsReadAttribute as_read_attribute, const AsWriteAttribute as_write_attribute) @@ -577,7 +576,7 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data, } static GVArray varray_from_initializer(const AttributeInit &initializer, - const CustomDataType data_type, + const eCustomDataType data_type, const Span<SplinePtr> splines) { switch (initializer.type) { @@ -604,7 +603,7 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, static bool create_point_attribute(GeometryComponent &component, const AttributeIDRef &attribute_id, const AttributeInit &initializer, - const CustomDataType data_type) + const eCustomDataType data_type) { CurveEval *curve = get_curve_from_component_for_write(component); if (curve == nullptr || curve->splines().size() == 0) { @@ -1306,8 +1305,8 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { bool try_create(GeometryComponent &component, const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, + const eAttrDomain domain, + const eCustomDataType data_type, const AttributeInit &initializer) const final { BLI_assert(this->type_is_supported(data_type)); @@ -1336,12 +1335,12 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { return true; } - void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final + void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final { callback(ATTR_DOMAIN_POINT); } - bool type_is_supported(CustomDataType data_type) const + bool type_is_supported(eCustomDataType data_type) const { return ((1ULL << data_type) & supported_types_mask) != 0; } diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index 9b023d12a7d..af058534f68 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -12,7 +12,6 @@ #include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" -#include "BKE_spline.hh" #include "attribute_access_intern.hh" @@ -208,7 +207,7 @@ static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves return results; } -VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain) +VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain) { if (!component.has_curves()) { return {}; @@ -244,7 +243,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const Attri * \{ */ static VArray<float> construct_curve_length_gvarray(const CurveComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { if (!component.has_curves()) { return {}; @@ -279,7 +278,7 @@ CurveLengthFieldInput::CurveLengthFieldInput() } GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { @@ -308,7 +307,7 @@ bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const /** \name Attribute Access Helper Functions * \{ */ -int CurveComponent::attribute_domain_num(const AttributeDomain domain) const +int CurveComponent::attribute_domain_num(const eAttrDomain domain) const { if (curves_ == nullptr) { return 0; @@ -325,8 +324,8 @@ int CurveComponent::attribute_domain_num(const AttributeDomain domain) const } GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const + const eAttrDomain from_domain, + const eAttrDomain to_domain) const { return blender::bke::CurvesGeometry::wrap(curves_->geometry) .adapt_domain(varray, from_domain, to_domain); diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index e56a7ca4dd8..653be03b991 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -366,7 +366,7 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const return almost_unique_ids_; } -int InstancesComponent::attribute_domain_num(const AttributeDomain domain) const +int InstancesComponent::attribute_domain_num(const eAttrDomain domain) const { if (domain != ATTR_DOMAIN_INSTANCE) { return 0; diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 5ac9a03f43c..88ea1af8a8d 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -119,7 +119,7 @@ namespace blender::bke { VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, const Mesh &mesh, const IndexMask mask, - const AttributeDomain domain) + const eAttrDomain domain) { switch (domain) { case ATTR_DOMAIN_FACE: { @@ -169,7 +169,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, /** \name Attribute Access * \{ */ -int MeshComponent::attribute_domain_num(const AttributeDomain domain) const +int MeshComponent::attribute_domain_num(const eAttrDomain domain) const { if (mesh_ == nullptr) { return 0; @@ -747,10 +747,9 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v } // namespace blender::bke -blender::GVArray MeshComponent::attribute_try_adapt_domain_impl( - const blender::GVArray &varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const +blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) const { if (!varray) { return {}; @@ -865,11 +864,11 @@ static void set_vertex_position(MVert &vert, float3 position) copy_v3_v3(vert.co, position); } -static void tag_normals_dirty_when_writing_position(GeometryComponent &component) +static void tag_component_positions_changed(GeometryComponent &component) { Mesh *mesh = get_mesh_from_component_for_write(component); if (mesh != nullptr) { - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(mesh); } } @@ -1115,7 +1114,7 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { return true; } - void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final + void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final { callback(ATTR_DOMAIN_POINT); } @@ -1214,7 +1213,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() point_access, make_derived_read_attribute<MVert, float3, get_vertex_position>, make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>, - tag_normals_dirty_when_writing_position); + tag_component_positions_changed); static NormalAttributeProvider normal; diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index 6de123c7cb9..facdbed265d 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -104,7 +104,7 @@ void PointCloudComponent::ensure_owns_direct_data() /** \name Attribute Access * \{ */ -int PointCloudComponent::attribute_domain_num(const AttributeDomain domain) const +int PointCloudComponent::attribute_domain_num(const eAttrDomain domain) const { if (pointcloud_ == nullptr) { return 0; diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 40e36ced199..1a43c4d01b0 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_bounds.hh" #include "BLI_map.hh" #include "BLI_task.hh" @@ -15,7 +16,6 @@ #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_pointcloud.h" -#include "BKE_spline.hh" #include "BKE_volume.h" #include "DNA_collection_types.h" @@ -175,6 +175,7 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const { + using namespace blender; bool have_minmax = false; if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) { have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max); @@ -185,10 +186,16 @@ bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma if (const Volume *volume = this->get_volume_for_read()) { have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max); } - if (const Curves *curves = this->get_curves_for_read()) { - std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves); + if (const Curves *curves_id = this->get_curves_for_read()) { + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); /* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */ - have_minmax |= curve->bounds_min_max(*r_min, *r_max, true); + std::optional<bounds::MinMaxResult<float3>> min_max = bounds::min_max( + curves.evaluated_positions()); + if (min_max) { + have_minmax = true; + *r_min = math::min(*r_min, min_max->min); + *r_max = math::max(*r_max, min_max->max); + } } return have_minmax; } @@ -470,7 +477,7 @@ void GeometrySet::gather_attributes_for_propagation( return; } - AttributeDomain domain = meta_data.domain; + eAttrDomain domain = meta_data.domain; if (dst_component_type != GEO_COMPONENT_TYPE_INSTANCES && domain == ATTR_DOMAIN_INSTANCE) { domain = ATTR_DOMAIN_POINT; } @@ -567,7 +574,7 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback) namespace blender::bke { GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const { if (component.type() == GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index d3c3f41779a..2d6e0e05a97 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -32,9 +32,7 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS if (mesh != nullptr) { BKE_mesh_wrapper_ensure_mdata(mesh); - - MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); - mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); + geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly); } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f86e947910b..3d546c5c36a 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -55,8 +55,6 @@ #include "BLO_read_write.h" -#include "BKE_gpencil.h" - static CLG_LogRef LOG = {"bke.gpencil"}; static void greasepencil_copy_data(Main *UNUSED(bmain), diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index 792474d30ea..0445a1540c7 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -25,8 +25,6 @@ #include "BLI_polyfill_2d.h" #include "BLI_span.hh" -#include "BLT_translation.h" - #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_material_types.h" diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index faafd1e1040..0bf5418ea8f 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -647,32 +647,38 @@ static bGPdata *gpencil_copy_structure_for_eval(bGPdata *gpd) return gpd_eval; } -static void copy_frame_to_eval_cb(bGPDlayer *UNUSED(gpl), +static void copy_frame_to_eval_ex(bGPDframe *gpf_orig, bGPDframe *gpf_eval) +{ + /* Free any existing eval stroke data. This happens in case we have a single user on the data + * block and the strokes have not been deleted. */ + if (!BLI_listbase_is_empty(&gpf_eval->strokes)) { + BKE_gpencil_free_strokes(gpf_eval); + } + /* Copy strokes to eval frame and update internal orig pointers. */ + BKE_gpencil_frame_copy_strokes(gpf_orig, gpf_eval); + BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval); +} + +static void copy_frame_to_eval_cb(bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *UNUSED(gps), void *UNUSED(thunk)) { - /* Early return when callback is not provided with a frame. */ - if (gpf == NULL) { + /* Early return when callback: + * - Is not provided with a frame. + * - When the frame is the layer's active frame (already handled in + * gpencil_copy_visible_frames_to_eval). + */ + if (gpf == NULL || gpf == gpl->actframe) { return; } - /* Free any existing eval stroke data. This happens in case we have a single user on the data - * block and the strokes have not been deleted. */ - if (!BLI_listbase_is_empty(&gpf->strokes)) { - BKE_gpencil_free_strokes(gpf); - } - - /* Get original frame. */ - bGPDframe *gpf_orig = gpf->runtime.gpf_orig; - /* Copy strokes to eval frame and update internal orig pointers. */ - BKE_gpencil_frame_copy_strokes(gpf_orig, gpf); - BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf); + copy_frame_to_eval_ex(gpf->runtime.gpf_orig, gpf); } static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *scene, Object *ob) { - /* Remap layers' active frame with time modifiers applied. */ + /* Remap layers active frame with time modifiers applied. */ bGPdata *gpd_eval = ob->data; LISTBASE_FOREACH (bGPDlayer *, gpl_eval, &gpd_eval->layers) { bGPDframe *gpf_eval = gpl_eval->actframe; @@ -680,9 +686,14 @@ static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *sce if (gpf_eval == NULL || gpf_eval->framenum != remap_cfra) { gpl_eval->actframe = BKE_gpencil_layer_frame_get(gpl_eval, remap_cfra, GP_GETFRAME_USE_PREV); } + /* Always copy active frame to eval, because the modifiers always evaluate the active frame, + * even if it's not visible (e.g. the layer is hidden).*/ + if (gpl_eval->actframe != NULL) { + copy_frame_to_eval_ex(gpl_eval->actframe->runtime.gpf_orig, gpl_eval->actframe); + } } - /* Copy only visible frames to evaluated version. */ + /* Copy visible frames that are not the active one to evaluated version. */ BKE_gpencil_visible_stroke_advanced_iter( NULL, ob, copy_frame_to_eval_cb, NULL, NULL, true, scene->r.cfra); } diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index e99230ef523..35f02c29a00 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -168,7 +168,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) /* NOTE: This code comes from python, here's the corresponding comment. */ /* This over-allocates proportional to the list size, making room - * for additional growth. The over-allocation is mild, but is + * for additional growth. The over-allocation is mild, but is * enough to give linear-time amortized behavior over a long * sequence of appends() in the presence of a poorly-performing * system realloc(). diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 06a5d877882..0c1f01c3796 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -1730,7 +1730,7 @@ static void stampdata_from_template(StampData *stamp_data, stamp_data->file[0] = '\0'; } if (scene->r.stamp & R_STAMP_NOTE) { - SNPRINTF(stamp_data->note, "%s", stamp_data_template->note); + STRNCPY(stamp_data->note, stamp_data_template->note); } else { stamp_data->note[0] = '\0'; @@ -3895,7 +3895,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) } if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) { - IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); + IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]); } for (int i = 0; i < totviews; i++) { @@ -4064,7 +4064,7 @@ static ImBuf *image_load_image_file( /* multi-views/multi-layers OpenEXR files directly populate ima, and return null ibuf... */ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] && tot_viewfiles == 1 && totviews >= 2) { - IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); + IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]); } /* return the original requested ImBuf */ diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index bed79a318e8..6edb9e1b24c 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -718,12 +718,31 @@ static void gpu_texture_update_from_ibuf( int tex_offset = ibuf->channels * (y * ibuf->x + x); const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf); - if (rect_float == nullptr) { - /* Byte pixels. */ - if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { - const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear( - ibuf->rect_colorspace); + if (rect_float) { + /* Float image is already in scene linear colorspace or non-color data by + * convention, no colorspace conversion needed. But we do require 4 channels + * currently. */ + if (ibuf->channels != 4 || scaled || !store_premultiplied) { + rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__); + if (rect_float == nullptr) { + return; + } + tex_stride = w; + tex_offset = 0; + + IMB_colormanagement_imbuf_to_float_texture( + rect_float, x, y, w, h, ibuf, store_premultiplied); + } + } + else { + /* Byte image is in original colorspace from the file, and may need conversion. */ + if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) || + IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) { + /* Non-color data, just store buffer as is. */ + } + else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) { + /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */ rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__); if (rect == nullptr) { return; @@ -734,13 +753,10 @@ static void gpu_texture_update_from_ibuf( /* Convert to scene linear with sRGB compression, and premultiplied for * correct texture interpolation. */ - IMB_colormanagement_imbuf_to_byte_texture( - rect, x, y, w, h, ibuf, compress_as_srgb, store_premultiplied); + IMB_colormanagement_imbuf_to_byte_texture(rect, x, y, w, h, ibuf, store_premultiplied); } - } - else { - /* Float pixels. */ - if (ibuf->channels != 4 || scaled || !store_premultiplied) { + else { + /* Other colorspace, store as float texture to avoid precision loss. */ rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__); if (rect_float == nullptr) { return; diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 6bfdaf9b522..9dda3762553 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -274,6 +274,12 @@ static void image_save_post(ReportList *reports, if (opts->do_newpath) { BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name)); BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath)); + + /* only image path, never ibuf */ + if (opts->relative) { + const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id); + BLI_path_rel(ima->filepath, relbase); /* only after saving */ + } } ibuf->userflags &= ~IB_BITMAPDIRTY; @@ -303,12 +309,6 @@ static void image_save_post(ReportList *reports, ima->type = IMA_TYPE_IMAGE; } - /* only image path, never ibuf */ - if (opts->relative) { - const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id); - BLI_path_rel(ima->filepath, relbase); /* only after saving */ - } - /* Update image file color space when saving to another color space. */ const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype); diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 528681d196e..90a4853fd3e 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -2161,7 +2161,7 @@ bool BKE_id_can_be_asset(const ID *id) BKE_idtype_idcode_is_linkable(GS(id->name)); } -bool BKE_id_is_editable(Main *bmain, ID *id) +bool BKE_id_is_editable(const Main *bmain, const ID *id) { return !(ID_IS_LINKED(id) || BKE_lib_override_library_is_system_defined(bmain, id)); } diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.cc index 50c9514e810..22012662180 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -5,8 +5,8 @@ * \ingroup bke */ -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include "CLG_log.h" @@ -21,8 +21,10 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "BKE_anim_data.h" #include "BKE_armature.h" #include "BKE_collection.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_key.h" @@ -88,16 +90,20 @@ BLI_INLINE void lib_override_object_posemode_transfer(ID *id_dst, ID *id_src) } /** Get override data for a given ID. Needed because of our beloved shape keys snowflake. */ -BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner_id) +BLI_INLINE const IDOverrideLibrary *lib_override_get(const Main *bmain, + const ID *id, + const ID **r_owner_id) { - if (r_owner_id != NULL) { + if (r_owner_id != nullptr) { *r_owner_id = id; } if (id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) { const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); - if (id_type->owner_get != NULL) { - ID *owner_id = id_type->owner_get(bmain, id); - if (r_owner_id != NULL) { + if (id_type->owner_get != nullptr) { + /* The #IDTypeInfo::owner_get callback should not modify the arguments, so casting away const + * is okay. */ + const ID *owner_id = id_type->owner_get(const_cast<Main *>(bmain), const_cast<ID *>(id)); + if (r_owner_id != nullptr) { *r_owner_id = owner_id; } return owner_id->override_library; @@ -107,21 +113,31 @@ BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner return id->override_library; } +BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner_id) +{ + /* Reuse the implementation of the const access function, which does not change the arguments. + * Add const explicitly to make it clear to the compiler to avoid just calling this function. */ + return const_cast<IDOverrideLibrary *>(lib_override_get(const_cast<const Main *>(bmain), + const_cast<const ID *>(id), + const_cast<const ID **>(r_owner_id))); +} + IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id) { - /* If reference_id is NULL, we are creating an override template for purely local data. + /* If reference_id is nullptr, we are creating an override template for purely local data. * Else, reference *must* be linked data. */ - BLI_assert(reference_id == NULL || ID_IS_LINKED(reference_id)); - BLI_assert(local_id->override_library == NULL); + BLI_assert(reference_id == nullptr || ID_IS_LINKED(reference_id)); + BLI_assert(local_id->override_library == nullptr); ID *ancestor_id; - for (ancestor_id = reference_id; ancestor_id != NULL && ancestor_id->override_library != NULL && - ancestor_id->override_library->reference != NULL; + for (ancestor_id = reference_id; + ancestor_id != nullptr && ancestor_id->override_library != nullptr && + ancestor_id->override_library->reference != nullptr; ancestor_id = ancestor_id->override_library->reference) { /* pass */ } - if (ancestor_id != NULL && ancestor_id->override_library != NULL) { + if (ancestor_id != nullptr && ancestor_id->override_library != nullptr) { /* Original ID has a template, use it! */ BKE_lib_override_library_copy(local_id, ancestor_id, true); if (local_id->override_library->reference != reference_id) { @@ -133,7 +149,7 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id) } /* Else, generate new empty override. */ - local_id->override_library = MEM_callocN(sizeof(*local_id->override_library), __func__); + local_id->override_library = MEM_cnew<IDOverrideLibrary>(__func__); local_id->override_library->reference = reference_id; id_us_plus(local_id->override_library->reference); local_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; @@ -148,20 +164,20 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f { BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id) || ID_IS_OVERRIDE_LIBRARY_TEMPLATE(src_id)); - if (dst_id->override_library != NULL) { - if (src_id->override_library == NULL) { + if (dst_id->override_library != nullptr) { + if (src_id->override_library == nullptr) { BKE_lib_override_library_free(&dst_id->override_library, true); return; } BKE_lib_override_library_clear(dst_id->override_library, true); } - else if (src_id->override_library == NULL) { + else if (src_id->override_library == nullptr) { /* Virtual overrides of embedded data does not require any extra work. */ return; } else { - BKE_lib_override_library_init(dst_id, NULL); + BKE_lib_override_library_init(dst_id, nullptr); } /* If source is already overriding data, we copy it but reuse its reference for dest ID. @@ -177,8 +193,10 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f if (do_full_copy) { BLI_duplicatelist(&dst_id->override_library->properties, &src_id->override_library->properties); - for (IDOverrideLibraryProperty *op_dst = dst_id->override_library->properties.first, - *op_src = src_id->override_library->properties.first; + for (IDOverrideLibraryProperty *op_dst = static_cast<IDOverrideLibraryProperty *>( + dst_id->override_library->properties.first), + *op_src = static_cast<IDOverrideLibraryProperty *>( + src_id->override_library->properties.first); op_dst; op_dst = op_dst->next, op_src = op_src->next) { lib_override_library_property_copy(op_dst, op_src); @@ -190,10 +208,10 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_id_user) { - BLI_assert(override != NULL); + BLI_assert(override != nullptr); - if (!ELEM(NULL, override->runtime, override->runtime->rna_path_to_override_properties)) { - BLI_ghash_clear(override->runtime->rna_path_to_override_properties, NULL, NULL); + if (!ELEM(nullptr, override->runtime, override->runtime->rna_path_to_override_properties)) { + BLI_ghash_clear(override->runtime->rna_path_to_override_properties, nullptr, nullptr); } LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) { @@ -207,20 +225,20 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i } } -void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user) +void BKE_lib_override_library_free(IDOverrideLibrary **override, const bool do_id_user) { - BLI_assert(*override != NULL); + BLI_assert(*override != nullptr); - if ((*override)->runtime != NULL) { - if ((*override)->runtime->rna_path_to_override_properties != NULL) { - BLI_ghash_free((*override)->runtime->rna_path_to_override_properties, NULL, NULL); + if ((*override)->runtime != nullptr) { + if ((*override)->runtime->rna_path_to_override_properties != nullptr) { + BLI_ghash_free((*override)->runtime->rna_path_to_override_properties, nullptr, nullptr); } MEM_SAFE_FREE((*override)->runtime); } BKE_lib_override_library_clear(*override, do_id_user); MEM_freeN(*override); - *override = NULL; + *override = nullptr; } static ID *lib_override_library_create_from(Main *bmain, @@ -232,12 +250,12 @@ static ID *lib_override_library_create_from(Main *bmain, * override template, or already an override of some other ref data). */ ID *local_id = BKE_id_copy_ex(bmain, reference_id, - NULL, + nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE | lib_id_copy_flags); - if (local_id == NULL) { - return NULL; + if (local_id == nullptr) { + return nullptr; } id_us_min(local_id); @@ -253,9 +271,9 @@ static ID *lib_override_library_create_from(Main *bmain, * data-blocks, just like root node trees or master collections. Therefore, we never need to * create overrides for them. We need a way to mark them as overrides though. */ Key *reference_key; - if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) { Key *local_key = BKE_key_from_id(local_id); - BLI_assert(local_key != NULL); + BLI_assert(local_key != nullptr); local_key->id.flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE; } @@ -264,7 +282,7 @@ static ID *lib_override_library_create_from(Main *bmain, /* TODO: This could be simplified by storing a flag in #IDOverrideLibrary * during the diffing process? */ -bool BKE_lib_override_library_is_user_edited(struct ID *id) +bool BKE_lib_override_library_is_user_edited(const ID *id) { if (!ID_IS_OVERRIDE_LIBRARY(id)) { @@ -278,8 +296,8 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id) return false; } - LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) { - LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { + LISTBASE_FOREACH (const IDOverrideLibraryProperty *, op, &id->override_library->properties) { + LISTBASE_FOREACH (const IDOverrideLibraryPropertyOperation *, opop, &op->operations) { if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) { continue; } @@ -294,11 +312,10 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id) return false; } -bool BKE_lib_override_library_is_system_defined(Main *bmain, ID *id) +bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id) { - if (ID_IS_OVERRIDE_LIBRARY(id)) { - ID *override_owner_id; + const ID *override_owner_id; lib_override_get(bmain, id, &override_owner_id); return (override_owner_id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) != 0; @@ -306,13 +323,41 @@ bool BKE_lib_override_library_is_system_defined(Main *bmain, ID *id) return false; } +bool BKE_lib_override_library_property_is_animated(const ID *id, + const IDOverrideLibraryProperty *override_prop, + const PropertyRNA *override_rna_prop, + const int rnaprop_index) +{ + AnimData *anim_data = BKE_animdata_from_id(id); + if (anim_data != nullptr) { + struct FCurve *fcurve; + char *index_token_start = const_cast<char *>( + RNA_path_array_index_token_find(override_prop->rna_path, override_rna_prop)); + if (index_token_start != nullptr) { + const char index_token_start_backup = *index_token_start; + *index_token_start = '\0'; + fcurve = BKE_animadata_fcurve_find_by_rna_path( + anim_data, override_prop->rna_path, rnaprop_index, nullptr, nullptr); + *index_token_start = index_token_start_backup; + } + else { + fcurve = BKE_animadata_fcurve_find_by_rna_path( + anim_data, override_prop->rna_path, 0, nullptr, nullptr); + } + if (fcurve != nullptr) { + return true; + } + } + return false; +} + static int foreachid_is_hierarchy_leaf_fn(LibraryIDLinkCallbackData *cb_data) { ID *id_owner = cb_data->id_owner; ID *id = *cb_data->id_pointer; - bool *is_leaf = cb_data->user_data; + bool *is_leaf = static_cast<bool *>(cb_data->user_data); - if (id != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) && + if (id != nullptr && ID_IS_OVERRIDE_LIBRARY_REAL(id) && id->override_library->hierarchy_root == id_owner->override_library->hierarchy_root) { *is_leaf = false; return IDWALK_RET_STOP_ITER; @@ -336,10 +381,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, ID *reference_id, const bool do_tagged_remap) { - BLI_assert(reference_id != NULL); + BLI_assert(reference_id != nullptr); BLI_assert(ID_IS_LINKED(reference_id)); - ID *local_id = lib_override_library_create_from(bmain, NULL, reference_id, 0); + ID *local_id = lib_override_library_create_from(bmain, nullptr, reference_id, 0); /* We cannot allow automatic hierarchy resync on this ID, it is highly likely to generate a giant * mess in case there are a lot of hidden, non-instantiated, non-properly organized dependencies. * Ref T94650. */ @@ -348,10 +393,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, local_id->override_library->hierarchy_root = local_id; if (do_tagged_remap) { - Key *reference_key, *local_key = NULL; - if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + Key *reference_key, *local_key = nullptr; + if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) { local_key = BKE_key_from_id(local_id); - BLI_assert(local_key != NULL); + BLI_assert(local_key != nullptr); } ID *other_id; @@ -364,7 +409,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); - if (reference_key != NULL) { + if (reference_key != nullptr) { BKE_libblock_relink_ex(bmain, other_id, &reference_key->id, @@ -401,16 +446,16 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, const bool do_no_main, const bool do_fully_editable) { - BLI_assert(id_root_reference != NULL && ID_IS_LINKED(id_root_reference)); + BLI_assert(id_root_reference != nullptr && ID_IS_LINKED(id_root_reference)); /* If we do not have any hierarchy root given, then the root reference must be tagged for * override. */ - BLI_assert(id_hierarchy_root != NULL || id_hierarchy_root_reference != NULL || + BLI_assert(id_hierarchy_root != nullptr || id_hierarchy_root_reference != nullptr || (id_root_reference->tag & LIB_TAG_DOIT) != 0); - /* At least one of the hierarchy root pointers must be NULL, passing both is useless and can + /* At least one of the hierarchy root pointers must be nullptr, passing both is useless and can * create confusion. */ - BLI_assert(ELEM(NULL, id_hierarchy_root, id_hierarchy_root_reference)); + BLI_assert(ELEM(nullptr, id_hierarchy_root, id_hierarchy_root_reference)); - if (id_hierarchy_root != NULL) { + if (id_hierarchy_root != nullptr) { /* If the hierarchy root is given, it must be a valid existing override (used during partial * resync process mainly). */ BLI_assert((ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root) && @@ -423,7 +468,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, lib_override_prefill_newid_from_existing_overrides(bmain, id_hierarchy_root); } } - if (!ELEM(id_hierarchy_root_reference, NULL, id_root_reference)) { + if (!ELEM(id_hierarchy_root_reference, nullptr, id_root_reference)) { /* If the reference hierarchy root is given, it must be from the same library as the reference * root, and also tagged for override. */ BLI_assert((id_hierarchy_root_reference->lib == id_root_reference->lib && @@ -435,14 +480,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, ID *reference_id; bool success = true; - ListBase todo_ids = {NULL}; + ListBase todo_ids = {nullptr}; LinkData *todo_id_iter; /* Get all IDs we want to override. */ FOREACH_MAIN_ID_BEGIN (bmain, reference_id) { if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib == reference_library && BKE_idtype_idcode_is_linkable(GS(reference_id->name))) { - todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__); + todo_id_iter = MEM_cnew<LinkData>(__func__); todo_id_iter->data = reference_id; BLI_addtail(&todo_ids, todo_id_iter); } @@ -450,18 +495,19 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, FOREACH_MAIN_ID_END; /* Override the IDs. */ - for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { - reference_id = todo_id_iter->data; + for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr; + todo_id_iter = todo_id_iter->next) { + reference_id = static_cast<ID *>(todo_id_iter->data); /* If `newid` is already set, assume it has been handled by calling code. * Only current use case: re-using proxy ID when converting to liboverride. */ - if (reference_id->newid == NULL) { + if (reference_id->newid == nullptr) { /* NOTE: `no main` case is used during resync procedure, to support recursive resync. * This requires extra care further down the resync process, * see: #BKE_lib_override_library_resync. */ reference_id->newid = lib_override_library_create_from( bmain, owner_library, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0); - if (reference_id->newid == NULL) { + if (reference_id->newid == nullptr) { success = false; break; } @@ -473,11 +519,11 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, reference_id->newid->tag |= LIB_TAG_DOIT; Key *reference_key; - if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) { reference_key->id.tag |= LIB_TAG_DOIT; Key *local_key = BKE_key_from_id(reference_id->newid); - BLI_assert(local_key != NULL); + BLI_assert(local_key != nullptr); reference_key->id.newid = &local_key->id; /* We also tag the new IDs so that in next step we can remap their pointers too. */ local_key->id.tag |= LIB_TAG_DOIT; @@ -487,17 +533,17 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, /* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole * existing linked IDs usages. */ if (success) { - if (id_hierarchy_root_reference != NULL) { + if (id_hierarchy_root_reference != nullptr) { id_hierarchy_root = id_hierarchy_root_reference->newid; } - else if (id_root_reference->newid != NULL && - (id_hierarchy_root == NULL || + else if (id_root_reference->newid != nullptr && + (id_hierarchy_root == nullptr || id_hierarchy_root->override_library->reference == id_root_reference)) { id_hierarchy_root = id_root_reference->newid; } - BLI_assert(id_hierarchy_root != NULL); + BLI_assert(id_hierarchy_root != nullptr); - LinkNode *relinked_ids = NULL; + LinkNode *relinked_ids = nullptr; /* Still checking the whole Main, that way we can tag other local IDs as needing to be * remapped to use newly created overriding IDs, if needed. */ ID *id; @@ -505,14 +551,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, ID *other_id; /* In case we created new overrides as 'no main', they are not accessible directly in this * loop, but we can get to them through their reference's `newid` pointer. */ - if (do_no_main && id->lib == id_root_reference->lib && id->newid != NULL) { + if (do_no_main && id->lib == id_root_reference->lib && id->newid != nullptr) { other_id = id->newid; /* Otherwise we cannot properly distinguish between IDs that are actually from the * linked library (and should not be remapped), and IDs that are overrides re-generated * from the reference from the linked library, and must therefore be remapped. * * This is reset afterwards at the end of this loop. */ - other_id->lib = NULL; + other_id->lib = nullptr; } else { other_id = id; @@ -529,12 +575,13 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, } FOREACH_MAIN_ID_END; - struct IDRemapper *id_remapper = BKE_id_remapper_create(); - for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { - reference_id = todo_id_iter->data; + IDRemapper *id_remapper = BKE_id_remapper_create(); + for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr; + todo_id_iter = todo_id_iter->next) { + reference_id = static_cast<ID *>(todo_id_iter->data); ID *local_id = reference_id->newid; - if (local_id == NULL) { + if (local_id == nullptr) { continue; } @@ -542,10 +589,10 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, BKE_id_remapper_add(id_remapper, reference_id, local_id); - Key *reference_key, *local_key = NULL; - if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { + Key *reference_key, *local_key = nullptr; + if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) { local_key = BKE_key_from_id(reference_id->newid); - BLI_assert(local_key != NULL); + BLI_assert(local_key != nullptr); BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id); } @@ -558,14 +605,15 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT); BKE_id_remapper_free(id_remapper); - BLI_linklist_free(relinked_ids, NULL); + BLI_linklist_free(relinked_ids, nullptr); } else { /* We need to cleanup potentially already created data. */ - for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { - reference_id = todo_id_iter->data; + for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr; + todo_id_iter = todo_id_iter->next) { + reference_id = static_cast<ID *>(todo_id_iter->data); BKE_id_delete(bmain, reference_id->newid); - reference_id->newid = NULL; + reference_id->newid = nullptr; } } @@ -574,7 +622,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, return success; } -typedef struct LibOverrideGroupTagData { +struct LibOverrideGroupTagData { Main *bmain; Scene *scene; ID *id_root; @@ -590,7 +638,7 @@ typedef struct LibOverrideGroupTagData { * Avoids calling #BKE_collection_object_find over and over, this function is very expansive. */ GHash *linked_object_to_instantiating_collections; MemArena *mem_arena; -} LibOverrideGroupTagData; +}; static void lib_override_group_tag_data_object_to_collection_init_collection_process( LibOverrideGroupTagData *data, Collection *collection) @@ -605,8 +653,8 @@ static void lib_override_group_tag_data_object_to_collection_init_collection_pro if (!BLI_ghash_ensure_p(data->linked_object_to_instantiating_collections, ob, (void ***)&collections_linkedlist_p)) { - *collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena, - sizeof(**collections_linkedlist_p)); + *collections_linkedlist_p = static_cast<LinkNodePair *>( + BLI_memarena_calloc(data->mem_arena, sizeof(**collections_linkedlist_p))); } BLI_linklist_append_arena(*collections_linkedlist_p, collection, data->mem_arena); } @@ -623,7 +671,7 @@ static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGro data->linked_object_to_instantiating_collections = BLI_ghash_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - if (data->scene != NULL) { + if (data->scene != nullptr) { lib_override_group_tag_data_object_to_collection_init_collection_process( data, data->scene->master_collection); } @@ -634,7 +682,7 @@ static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGro static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data) { - BLI_ghash_free(data->linked_object_to_instantiating_collections, NULL, NULL); + BLI_ghash_free(data->linked_object_to_instantiating_collections, nullptr, nullptr); BLI_memarena_free(data->mem_arena); memset(data, 0, sizeof(*data)); } @@ -651,8 +699,9 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa ID *id = data->id_root; const bool is_override = data->is_override; - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>( + BLI_ghash_lookup(bmain->relations->relations_from_pointers, id)); + BLI_assert(entry != nullptr); if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { /* This ID has already been processed. */ @@ -662,7 +711,7 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa * relationship hierarchy. */ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; - for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr; to_id_entry = to_id_entry->next) { if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { /* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers) as @@ -671,7 +720,7 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa } /* We only consider IDs from the same library. */ ID *to_id = *to_id_entry->id_pointer.to; - if (to_id == NULL || to_id->lib != id->lib || + if (to_id == nullptr || to_id->lib != id->lib || (is_override && !ID_IS_OVERRIDE_LIBRARY(to_id))) { /* IDs from different libraries, or non-override IDs in case we are processing overrides, are * both barriers of dependency. */ @@ -696,9 +745,9 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat const uint tag = data->tag; const uint missing_tag = data->missing_tag; - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, - id_owner); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>( + BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_owner)); + BLI_assert(entry != nullptr); if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { /* This ID has already been processed. */ @@ -708,7 +757,7 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat * relationship hierarchy. */ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; - for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr; to_id_entry = to_id_entry->next) { if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { /* Never consider non-overridable relationships as actual dependencies. */ @@ -716,7 +765,7 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat } ID *to_id = *to_id_entry->id_pointer.to; - if (ELEM(to_id, NULL, id_owner)) { + if (ELEM(to_id, nullptr, id_owner)) { continue; } /* We only consider IDs from the same library. */ @@ -751,10 +800,12 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv * is not usable here, as it may have become invalid from some previous operation and it should * not be updated here. So instead only use collections' reliable 'raw' data to check if some * object in the hierarchy of the given collection is still tagged for override. */ - for (CollectionObject *collection_object = collection->gobject.first; collection_object != NULL; + for (CollectionObject *collection_object = + static_cast<CollectionObject *>(collection->gobject.first); + collection_object != nullptr; collection_object = collection_object->next) { Object *object = collection_object->ob; - if (object == NULL) { + if (object == nullptr) { continue; } if ((object->id.tag & data->tag) != 0) { @@ -762,7 +813,9 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv } } - for (CollectionChild *collection_child = collection->children.first; collection_child != NULL; + for (CollectionChild *collection_child = + static_cast<CollectionChild *>(collection->children.first); + collection_child != nullptr; collection_child = collection_child->next) { if (lib_override_linked_group_tag_collections_keep_tagged_check_recursive( data, collection_child->collection)) { @@ -781,9 +834,11 @@ static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGr /* Remove (untag) bone shape objects, they shall never need to be to directly/explicitly * overridden. */ LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { - if (pchan->custom != NULL && &pchan->custom->id != id_root) { + if (ob->type == OB_ARMATURE && ob->pose != nullptr && (ob->id.tag & data->tag)) { + for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); + pchan != nullptr; + pchan = pchan->next) { + if (pchan->custom != nullptr && &pchan->custom->id != id_root) { pchan->custom->id.tag &= ~data->tag; } } @@ -860,17 +915,18 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data) } LISTBASE_FOREACH (Object *, ob, &bmain->objects) { if (ID_IS_LINKED(ob) && (ob->id.tag & data->tag) != 0) { - Collection *instantiating_collection = NULL; - Collection *instantiating_collection_override_candidate = NULL; + Collection *instantiating_collection = nullptr; + Collection *instantiating_collection_override_candidate = nullptr; /* Loop over all collections instantiating the object, if we already have a 'locale' one we * have nothing to do, otherwise try to find a 'linked' one that we can override too. */ - LinkNodePair *instantiating_collection_linklist = BLI_ghash_lookup( - data->linked_object_to_instantiating_collections, ob); - if (instantiating_collection_linklist != NULL) { + LinkNodePair *instantiating_collection_linklist = static_cast<LinkNodePair *>( + BLI_ghash_lookup(data->linked_object_to_instantiating_collections, ob)); + if (instantiating_collection_linklist != nullptr) { for (LinkNode *instantiating_collection_linknode = instantiating_collection_linklist->list; - instantiating_collection_linknode != NULL; + instantiating_collection_linknode != nullptr; instantiating_collection_linknode = instantiating_collection_linknode->next) { - instantiating_collection = instantiating_collection_linknode->link; + instantiating_collection = static_cast<Collection *>( + instantiating_collection_linknode->link); if (!ID_IS_LINKED(instantiating_collection)) { /* There is a local collection instantiating the linked object to override, nothing * else to be done here. */ @@ -882,12 +938,12 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data) break; } instantiating_collection_override_candidate = instantiating_collection; - instantiating_collection = NULL; + instantiating_collection = nullptr; } } - if (instantiating_collection == NULL && - instantiating_collection_override_candidate != NULL) { + if (instantiating_collection == nullptr && + instantiating_collection_override_candidate != nullptr) { if (instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING) { instantiating_collection_override_candidate->id.tag |= data->missing_tag; } @@ -916,9 +972,9 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData * const uint tag = data->tag; const uint missing_tag = data->missing_tag; - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, - id_owner); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>( + BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_owner)); + BLI_assert(entry != nullptr); if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { /* This ID has already been processed. */ @@ -928,7 +984,7 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData * * relationship hierarchy. */ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; - for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr; to_id_entry = to_id_entry->next) { if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { /* Never consider non-overridable relationships as actual dependencies. */ @@ -936,7 +992,7 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData * } ID *to_id = *to_id_entry->id_pointer.to; - if (ELEM(to_id, NULL, id_owner)) { + if (ELEM(to_id, nullptr, id_owner)) { continue; } /* Different libraries or different hierarchy roots are break points in override hierarchies. @@ -949,8 +1005,8 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData * continue; } - Library *reference_lib = lib_override_get(bmain, id_owner, NULL)->reference->lib; - ID *to_id_reference = lib_override_get(bmain, to_id, NULL)->reference; + const Library *reference_lib = lib_override_get(bmain, id_owner, nullptr)->reference->lib; + const ID *to_id_reference = lib_override_get(bmain, to_id, nullptr)->reference; if (to_id_reference->lib != reference_lib) { /* We do not override data-blocks from other libraries, nor do we process them. */ continue; @@ -978,7 +1034,7 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data) BLI_assert(data->is_override); ID *id_hierarchy_root = data->hierarchy_root_id; - BLI_assert(id_hierarchy_root != NULL); + BLI_assert(id_hierarchy_root != nullptr); BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root)); UNUSED_VARS_NDEBUG(id_hierarchy_root); @@ -1001,13 +1057,14 @@ static bool lib_override_library_create_do(Main *bmain, const bool do_fully_editable) { BKE_main_relations_create(bmain, 0); - LibOverrideGroupTagData data = {.bmain = bmain, - .scene = scene, - .id_root = id_root_reference, - .tag = LIB_TAG_DOIT, - .missing_tag = LIB_TAG_MISSING, - .is_override = false, - .is_resync = false}; + LibOverrideGroupTagData data{}; + data.bmain = bmain; + data.scene = scene; + data.id_root = id_root_reference; + data.tag = LIB_TAG_DOIT; + data.missing_tag = LIB_TAG_MISSING; + data.is_override = false; + data.is_resync = false; lib_override_group_tag_data_object_to_collection_init(&data); lib_override_linked_group_tag(&data); @@ -1026,7 +1083,7 @@ static bool lib_override_library_create_do(Main *bmain, owner_library, id_root_reference, id_hierarchy_root_reference, - NULL, + nullptr, false, do_fully_editable); } @@ -1034,7 +1091,7 @@ static bool lib_override_library_create_do(Main *bmain, success = BKE_lib_override_library_create_from_tag(bmain, owner_library, id_root_reference, - NULL, + nullptr, id_hierarchy_root_reference, false, do_fully_editable); @@ -1064,25 +1121,25 @@ static void lib_override_library_create_post_process(Main *bmain, /* We create a set of all objects referenced into the scene by its hierarchy of collections. * NOTE: This is different that the list of bases, since objects in excluded collections etc. * won't have a base, but are still considered as instanced from our point of view. */ - GSet *all_objects_in_scene = BKE_scene_objects_as_gset(scene, NULL); + GSet *all_objects_in_scene = BKE_scene_objects_as_gset(scene, nullptr); /* Instantiating the root collection or object should never be needed in resync case, since the * old override would be remapped to the new one. */ - if (!is_resync && id_root != NULL && id_root->newid != NULL && + if (!is_resync && id_root != nullptr && id_root->newid != nullptr && (!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) { switch (GS(id_root->name)) { case ID_GR: { - Object *ob_reference = id_instance_hint != NULL && GS(id_instance_hint->name) == ID_OB ? + Object *ob_reference = id_instance_hint != nullptr && GS(id_instance_hint->name) == ID_OB ? (Object *)id_instance_hint : - NULL; + nullptr; Collection *collection_new = ((Collection *)id_root->newid); if (is_resync && BKE_collection_is_in_scene(collection_new)) { break; } - if (ob_reference != NULL) { + if (ob_reference != nullptr) { BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new); } - else if (id_instance_hint != NULL) { + else if (id_instance_hint != nullptr) { BLI_assert(GS(id_instance_hint->name) == ID_GR); BKE_collection_add_from_collection( bmain, scene, ((Collection *)id_instance_hint), collection_new); @@ -1099,7 +1156,7 @@ static void lib_override_library_create_post_process(Main *bmain, } case ID_OB: { Object *ob_new = (Object *)id_root->newid; - if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) { + if (BLI_gset_lookup(all_objects_in_scene, ob_new) == nullptr) { BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new); all_objects_in_scene = BKE_scene_objects_as_gset(scene, all_objects_in_scene); } @@ -1114,16 +1171,16 @@ static void lib_override_library_create_post_process(Main *bmain, Collection *default_instantiating_collection = residual_storage; LISTBASE_FOREACH (Object *, ob, &bmain->objects) { Object *ob_new = (Object *)ob->id.newid; - if (ob_new == NULL || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) { + if (ob_new == nullptr || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) { continue; } - BLI_assert(ob_new->id.override_library != NULL && + BLI_assert(ob_new->id.override_library != nullptr && ob_new->id.override_library->reference == &ob->id); - if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) { - if (id_root != NULL && default_instantiating_collection == NULL) { - ID *id_ref = id_root->newid != NULL ? id_root->newid : id_root; + 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; switch (GS(id_ref->name)) { case ID_GR: { /* Adding the object to a specific collection outside of the root overridden one is a @@ -1136,7 +1193,8 @@ static void lib_override_library_create_post_process(Main *bmain, if (ID_REAL_USERS(ob_new) != 0) { continue; } - default_instantiating_collection = BKE_id_new(bmain, ID_GR, "OVERRIDE_HIDDEN"); + default_instantiating_collection = static_cast<Collection *>( + BKE_id_new(bmain, ID_GR, "OVERRIDE_HIDDEN")); id_us_min(&default_instantiating_collection->id); /* Hide the collection from viewport and render. */ default_instantiating_collection->flag |= COLLECTION_HIDE_VIEWPORT | @@ -1149,7 +1207,7 @@ static void lib_override_library_create_post_process(Main *bmain, Object *ob_ref = (Object *)id_ref; LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { if (BKE_collection_has_object(collection, ob_ref) && - (view_layer != NULL ? + (view_layer != nullptr ? BKE_view_layer_has_collection(view_layer, collection) : BKE_collection_has_collection(scene->master_collection, collection)) && !ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) { @@ -1162,7 +1220,7 @@ static void lib_override_library_create_post_process(Main *bmain, break; } } - if (default_instantiating_collection == NULL) { + if (default_instantiating_collection == nullptr) { default_instantiating_collection = scene->master_collection; } @@ -1171,8 +1229,9 @@ static void lib_override_library_create_post_process(Main *bmain, } } - if (id_root != NULL && !ELEM(default_instantiating_collection, NULL, scene->master_collection)) { - ID *id_ref = id_root->newid != NULL ? id_root->newid : id_root; + if (id_root != nullptr && + !ELEM(default_instantiating_collection, nullptr, scene->master_collection)) { + ID *id_ref = id_root->newid != nullptr ? id_root->newid : id_root; switch (GS(id_ref->name)) { case ID_GR: BKE_collection_add_from_collection( @@ -1180,12 +1239,13 @@ static void lib_override_library_create_post_process(Main *bmain, break; default: /* Add to master collection. */ - BKE_collection_add_from_collection(bmain, scene, NULL, default_instantiating_collection); + BKE_collection_add_from_collection( + bmain, scene, nullptr, default_instantiating_collection); break; } } - BLI_gset_free(all_objects_in_scene, NULL); + BLI_gset_free(all_objects_in_scene, nullptr); } bool BKE_lib_override_library_create(Main *bmain, @@ -1198,11 +1258,11 @@ bool BKE_lib_override_library_create(Main *bmain, ID **r_id_root_override, const bool do_fully_editable) { - if (r_id_root_override != NULL) { - *r_id_root_override = NULL; + if (r_id_root_override != nullptr) { + *r_id_root_override = nullptr; } - if (id_hierarchy_root_reference == NULL) { + if (id_hierarchy_root_reference == nullptr) { id_hierarchy_root_reference = id_root_reference; } @@ -1217,12 +1277,18 @@ bool BKE_lib_override_library_create(Main *bmain, return success; } - if (r_id_root_override != NULL) { + if (r_id_root_override != nullptr) { *r_id_root_override = id_root_reference->newid; } - lib_override_library_create_post_process( - bmain, scene, view_layer, owner_library, id_root_reference, id_instance_hint, NULL, false); + lib_override_library_create_post_process(bmain, + scene, + view_layer, + owner_library, + id_root_reference, + id_instance_hint, + nullptr, + false); /* Cleanup. */ BKE_main_id_newptr_and_tag_clear(bmain); @@ -1234,7 +1300,7 @@ bool BKE_lib_override_library_create(Main *bmain, return success; } -bool BKE_lib_override_library_template_create(struct ID *id) +bool BKE_lib_override_library_template_create(ID *id) { if (ID_IS_LINKED(id)) { return false; @@ -1243,7 +1309,7 @@ bool BKE_lib_override_library_template_create(struct ID *id) return false; } - BKE_lib_override_library_init(id, NULL); + BKE_lib_override_library_init(id, nullptr); return true; } @@ -1254,16 +1320,17 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int "Levels of dependency relationships between library overrides IDs is way too high, " "skipping further processing loops (involves at least '%s')", id->name); - return NULL; + return nullptr; } if (!ID_IS_OVERRIDE_LIBRARY(id)) { BLI_assert_unreachable(); - return NULL; + return nullptr; } - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>( + BLI_ghash_lookup(bmain->relations->relations_from_pointers, id)); + BLI_assert(entry != nullptr); if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { @@ -1285,7 +1352,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int int best_level_candidate = curr_level; ID *best_root_id_candidate = id; - for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL; + for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr; from_id_entry = from_id_entry->next) { if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { /* Never consider non-overridable relationships as actual dependencies. */ @@ -1293,7 +1360,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int } ID *from_id = from_id_entry->id_pointer.from; - if (ELEM(from_id, NULL, id)) { + if (ELEM(from_id, nullptr, id)) { continue; } if (!ID_IS_OVERRIDE_LIBRARY(from_id) || (from_id->lib != id->lib)) { @@ -1304,7 +1371,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int /* Recursively process the parent. */ ID *root_id_candidate = lib_override_root_find( bmain, from_id, curr_level + 1, &level_candidate); - if (level_candidate > best_level_candidate && root_id_candidate != NULL) { + if (level_candidate > best_level_candidate && root_id_candidate != nullptr) { best_root_id_candidate = root_id_candidate; best_level_candidate = level_candidate; } @@ -1319,7 +1386,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int bmain, id_owner, curr_level + 1, &best_level_placeholder); } - BLI_assert(best_root_id_candidate != NULL); + BLI_assert(best_root_id_candidate != nullptr); BLI_assert((best_root_id_candidate->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) == 0); *r_best_level = best_level_candidate; @@ -1337,14 +1404,14 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID /* Hierarchy root already set, and not matching currently proposed one, try to find which is * best. */ - if (id->override_library->hierarchy_root != NULL) { + if (id->override_library->hierarchy_root != nullptr) { /* Check if given `id_from` matches with the hierarchy of the linked reference ID, in which * case we assume that the given hierarchy root is the 'real' one. * * NOTE: This can fail if user mixed dependencies between several overrides of a same * reference linked hierarchy. Not much to be done in that case, it's virtually impossible to * fix this automatically in a reliable way. */ - if (id_from == NULL || !ID_IS_OVERRIDE_LIBRARY_REAL(id_from)) { + if (id_from == nullptr || !ID_IS_OVERRIDE_LIBRARY_REAL(id_from)) { /* Too complicated to deal with for now. */ CLOG_WARN(&LOG, "Inconsistency in library override hierarchy of ID '%s'.\n" @@ -1357,12 +1424,12 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID } ID *id_from_ref = id_from->override_library->reference; - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, - id->override_library->reference); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(BLI_ghash_lookup( + bmain->relations->relations_from_pointers, id->override_library->reference)); + BLI_assert(entry != nullptr); bool do_replace_root = false; - for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL; + for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr; from_id_entry = from_id_entry->next) { if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { /* Never consider non-overridable relationships as actual dependencies. */ @@ -1399,10 +1466,11 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID id->override_library->hierarchy_root = id_root; } - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>( + BLI_ghash_lookup(bmain->relations->relations_from_pointers, id)); + BLI_assert(entry != nullptr); - for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr; to_id_entry = to_id_entry->next) { if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { /* Never consider non-overridable relationships as actual dependencies. */ @@ -1410,7 +1478,7 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID } ID *to_id = *to_id_entry->id_pointer.to; - if (ELEM(to_id, NULL, id)) { + if (ELEM(to_id, nullptr, id)) { continue; } if (!ID_IS_OVERRIDE_LIBRARY(to_id) || (to_id->lib != id->lib)) { @@ -1432,18 +1500,18 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { continue; } - if (id->override_library->hierarchy_root != NULL) { + if (id->override_library->hierarchy_root != nullptr) { if (!ID_IS_OVERRIDE_LIBRARY_REAL(id->override_library->hierarchy_root) || id->override_library->hierarchy_root->lib != id->lib) { CLOG_ERROR( &LOG, "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a " "new valid one", - id->override_library->hierarchy_root != NULL ? + id->override_library->hierarchy_root != nullptr ? id->override_library->hierarchy_root->name : "<NONE>", id->name); - id->override_library->hierarchy_root = NULL; + id->override_library->hierarchy_root = nullptr; } else { continue; @@ -1455,7 +1523,7 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) int best_level = 0; ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level); - if (!ELEM(id_root->override_library->hierarchy_root, id_root, NULL)) { + if (!ELEM(id_root->override_library->hierarchy_root, id_root, nullptr)) { CLOG_WARN(&LOG, "Potential inconsistency in library override hierarchy of ID '%s', detected as " "part of the hierarchy of '%s', which has a different root '%s'", @@ -1465,9 +1533,9 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) continue; } - lib_override_root_hierarchy_set(bmain, id_root, id, NULL); + lib_override_root_hierarchy_set(bmain, id_root, id, nullptr); - BLI_assert(id->override_library->hierarchy_root != NULL); + BLI_assert(id->override_library->hierarchy_root != nullptr); } FOREACH_MAIN_ID_END; @@ -1479,14 +1547,14 @@ static void lib_override_library_remap(Main *bmain, GHash *linkedref_to_old_override) { ID *id; - struct IDRemapper *remapper = BKE_id_remapper_create(); - LinkNode *nomain_ids = NULL; + IDRemapper *remapper = BKE_id_remapper_create(); + LinkNode *nomain_ids = nullptr; FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { + if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && id->lib == id_root_reference->lib) { ID *id_override_new = id->newid; - ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); - if (id_override_old == NULL) { + ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id)); + if (id_override_old == nullptr) { continue; } @@ -1498,7 +1566,8 @@ static void lib_override_library_remap(Main *bmain, /* Remap no-main override IDs we just created too. */ GHashIterator linkedref_to_old_override_iter; GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) { - ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter); + ID *id_override_old_iter = static_cast<ID *>( + BLI_ghashIterator_getValue(&linkedref_to_old_override_iter)); if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) { continue; } @@ -1514,7 +1583,7 @@ static void lib_override_library_remap(Main *bmain, remapper, ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE); BKE_id_remapper_free(remapper); - BLI_linklist_free(nomain_ids, NULL); + BLI_linklist_free(nomain_ids, nullptr); } static bool lib_override_library_resync(Main *bmain, @@ -1534,7 +1603,7 @@ static bool lib_override_library_resync(Main *bmain, ID *id; if (id_root_reference->tag & LIB_TAG_MISSING) { - BKE_reportf(reports != NULL ? reports->reports : NULL, + BKE_reportf(reports != nullptr ? reports->reports : nullptr, RPT_ERROR, "Impossible to resync data-block %s and its dependencies, as its linked reference " "is missing", @@ -1543,14 +1612,15 @@ static bool lib_override_library_resync(Main *bmain, } BKE_main_relations_create(bmain, 0); - LibOverrideGroupTagData data = {.bmain = bmain, - .scene = scene, - .id_root = id_root, - .hierarchy_root_id = id_root->override_library->hierarchy_root, - .tag = LIB_TAG_DOIT, - .missing_tag = LIB_TAG_MISSING, - .is_override = true, - .is_resync = true}; + LibOverrideGroupTagData data{}; + data.bmain = bmain; + data.scene = scene; + data.id_root = id_root; + data.hierarchy_root_id = id_root->override_library->hierarchy_root; + data.tag = LIB_TAG_DOIT; + data.missing_tag = LIB_TAG_MISSING; + data.is_override = true; + data.is_resync = true; lib_override_group_tag_data_object_to_collection_init(&data); /* Mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, populated from @@ -1560,9 +1630,9 @@ static bool lib_override_library_resync(Main *bmain, /* Only tag linked IDs from related linked reference hierarchy that are actually part of * the sub-trees of each detected sub-roots needing resync. */ - for (LinkNode *resync_root_link = id_resync_roots; resync_root_link != NULL; + for (LinkNode *resync_root_link = id_resync_roots; resync_root_link != nullptr; resync_root_link = resync_root_link->next) { - ID *id_resync_root = resync_root_link->link; + ID *id_resync_root = static_cast<ID *>(resync_root_link->link); BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_resync_root)); if ((id_resync_root->tag & LIB_TAG_NO_MAIN) != 0) { @@ -1584,12 +1654,12 @@ static bool lib_override_library_resync(Main *bmain, if (id_resync_root_reference->tag & LIB_TAG_MISSING) { BKE_reportf( - reports != NULL ? reports->reports : NULL, + reports != nullptr ? reports->reports : nullptr, RPT_ERROR, "Impossible to resync data-block %s and its dependencies, as its linked reference " "is missing", id_root->name + 2); - BLI_ghash_free(linkedref_to_old_override, NULL, NULL); + BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr); BKE_main_relations_free(bmain); lib_override_group_tag_data_clear(&data); return false; @@ -1628,7 +1698,7 @@ static bool lib_override_library_resync(Main *bmain, /* While this should not happen in typical cases (and won't be properly supported here), * user is free to do all kind of very bad things, including having different local * overrides of a same linked ID in a same hierarchy. */ - IDOverrideLibrary *id_override_library = lib_override_get(bmain, id, NULL); + IDOverrideLibrary *id_override_library = lib_override_get(bmain, id, nullptr); ID *reference_id = id_override_library->reference; if (GS(reference_id->name) != GS(id->name)) { switch (GS(id->name)) { @@ -1701,24 +1771,24 @@ static bool lib_override_library_resync(Main *bmain, * above). */ const bool success = BKE_lib_override_library_create_from_tag( bmain, - NULL, + nullptr, id_root_reference, id_root->override_library->hierarchy_root, - NULL, + nullptr, true, false); if (!success) { - BLI_ghash_free(linkedref_to_old_override, NULL, NULL); + BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr); return success; } ListBase *lb; FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) { FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) { - if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { + if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && id->lib == id_root_reference->lib) { ID *id_override_new = id->newid; - ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); + ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id)); BLI_assert((id_override_new->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0); @@ -1726,14 +1796,14 @@ static bool lib_override_library_resync(Main *bmain, * duplicated from the reference ID with 'no main' option, it should currently be the same * as the reference ID one). */ BLI_assert(/*!ID_IS_LINKED(id_override_new) || */ id_override_new->lib == id->lib); - BLI_assert(id_override_old == NULL || id_override_old->lib == id_root->lib); + BLI_assert(id_override_old == nullptr || id_override_old->lib == id_root->lib); id_override_new->lib = id_root->lib; /* Remap step below will tag directly linked ones properly as needed. */ if (ID_IS_LINKED(id_override_new)) { id_override_new->tag |= LIB_TAG_INDIRECT; } - if (id_override_old != NULL) { + if (id_override_old != nullptr) { /* Swap the names between old override ID and new one. */ char id_name_buf[MAX_ID_NAME]; memcpy(id_name_buf, id_override_old->name, sizeof(id_name_buf)); @@ -1754,10 +1824,10 @@ static bool lib_override_library_resync(Main *bmain, /* Copy over overrides rules from old override ID to new one. */ BLI_duplicatelist(&id_override_new->override_library->properties, &id_override_old->override_library->properties); - IDOverrideLibraryProperty *op_new = - id_override_new->override_library->properties.first; - IDOverrideLibraryProperty *op_old = - id_override_old->override_library->properties.first; + IDOverrideLibraryProperty *op_new = static_cast<IDOverrideLibraryProperty *>( + id_override_new->override_library->properties.first); + IDOverrideLibraryProperty *op_old = static_cast<IDOverrideLibraryProperty *>( + id_override_old->override_library->properties.first); for (; op_new; op_new = op_new->next, op_old = op_old->next) { lib_override_library_property_copy(op_new, op_old); } @@ -1782,20 +1852,20 @@ static bool lib_override_library_resync(Main *bmain, BKE_main_collection_sync(bmain); - LinkNode *id_override_old_list = NULL; + LinkNode *id_override_old_list = nullptr; /* We need to apply override rules in a separate loop, after all ID pointers have been properly * remapped, and all new local override IDs have gotten their proper original names, otherwise * override operations based on those ID names would fail. */ FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) { + if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && id->lib == id_root_reference->lib) { ID *id_override_new = id->newid; if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_override_new)) { continue; } - ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); + ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id)); - if (id_override_old == NULL) { + if (id_override_old == nullptr) { continue; } if (ID_IS_OVERRIDE_LIBRARY_REAL(id_override_old)) { @@ -1826,7 +1896,7 @@ static bool lib_override_library_resync(Main *bmain, RNA_struct_override_apply(bmain, &rnaptr_dst, &rnaptr_src, - NULL, + nullptr, id_override_new->override_library, do_hierarchy_enforce ? RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS : @@ -1841,18 +1911,18 @@ static bool lib_override_library_resync(Main *bmain, /* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages * of the old one. * This is necessary in case said old ID is not in Main anymore. */ - struct IDRemapper *id_remapper = BKE_id_remapper_create(); + IDRemapper *id_remapper = BKE_id_remapper_create(); BKE_libblock_relink_multiple(bmain, id_override_old_list, ID_REMAP_TYPE_CLEANUP, id_remapper, ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE); - for (LinkNode *ln_iter = id_override_old_list; ln_iter != NULL; ln_iter = ln_iter->next) { - ID *id_override_old = ln_iter->link; + for (LinkNode *ln_iter = id_override_old_list; ln_iter != nullptr; ln_iter = ln_iter->next) { + ID *id_override_old = static_cast<ID *>(ln_iter->link); id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT; } BKE_id_remapper_free(id_remapper); - BLI_linklist_free(id_override_old_list, NULL); + BLI_linklist_free(id_override_old_list, nullptr); /* Delete old override IDs. * Note that we have to use tagged group deletion here, since ID deletion also uses @@ -1863,10 +1933,10 @@ static bool lib_override_library_resync(Main *bmain, /* Note that this works because linked IDs are always after local ones (including * overrides), so we will only ever tag an old override ID after we have already checked it * in this loop, hence we cannot untag it later. */ - if (id->newid != NULL && id->lib == id_root_reference->lib) { - ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); + if (id->newid != nullptr && id->lib == id_root_reference->lib) { + ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id)); - if (id_override_old != NULL) { + if (id_override_old != nullptr) { id->newid->tag &= ~LIB_TAG_DOIT; id_override_old->tag |= LIB_TAG_DOIT; if (id_override_old->tag & LIB_TAG_NO_MAIN) { @@ -1910,19 +1980,19 @@ static bool lib_override_library_resync(Main *bmain, FOREACH_MAIN_ID_END; /* Cleanup, many pointers in this GHash are already invalid now. */ - BLI_ghash_free(linkedref_to_old_override, NULL, NULL); + BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr); BKE_id_multi_tagged_delete(bmain); /* At this point, `id_root` may have been resynced, therefore deleted. In that case we need to * update it to its new version. */ - if (id_root_reference->newid != NULL) { + if (id_root_reference->newid != nullptr) { id_root = id_root_reference->newid; } if (user_edited_overrides_deletion_count > 0) { - BKE_reportf(reports != NULL ? reports->reports : NULL, + BKE_reportf(reports != nullptr ? reports->reports : nullptr, RPT_WARNING, "During resync of data-block %s, %d obsolete overrides were deleted, that had " "local changes defined by user", @@ -1939,7 +2009,7 @@ static bool lib_override_library_resync(Main *bmain, lib_override_library_create_post_process(bmain, scene, view_layer, - NULL, + nullptr, id_root_reference, id_root, override_resync_residual_storage, @@ -1961,8 +2031,10 @@ bool BKE_lib_override_library_resync(Main *bmain, const bool do_hierarchy_enforce, BlendFileReadReport *reports) { - ListBase no_main_ids_list = {NULL}; - LinkNode id_resync_roots = {.link = id_root, .next = NULL}; + ListBase no_main_ids_list = {nullptr}; + LinkNode id_resync_roots{}; + id_resync_roots.link = id_root; + id_resync_roots.next = nullptr; const bool success = lib_override_library_resync(bmain, scene, @@ -1996,14 +2068,14 @@ static ID *lib_override_library_main_resync_root_get(Main *bmain, ID *id) { if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); - if (id_type->owner_get != NULL) { + if (id_type->owner_get != nullptr) { id = id_type->owner_get(bmain, id); } BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id)); } ID *hierarchy_root_id = id->override_library->hierarchy_root; - BLI_assert(hierarchy_root_id != NULL); + BLI_assert(hierarchy_root_id != nullptr); BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(hierarchy_root_id)); return hierarchy_root_id; } @@ -2038,8 +2110,9 @@ static bool lib_override_resync_tagging_finalize_recurse( return false; } - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>( + BLI_ghash_lookup(bmain->relations->relations_from_pointers, id)); + BLI_assert(entry != nullptr); if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { /* This ID has already been processed. */ @@ -2073,7 +2146,7 @@ static bool lib_override_resync_tagging_finalize_recurse( id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; bool is_ancestor_tagged_for_resync = false; - for (MainIDRelationsEntryItem *entry_item = entry->from_ids; entry_item != NULL; + for (MainIDRelationsEntryItem *entry_item = entry->from_ids; entry_item != nullptr; entry_item = entry_item->next) { if (entry_item->usage_flag & (IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE | IDWALK_CB_LOOPBACK)) { @@ -2130,11 +2203,11 @@ static bool lib_override_resync_tagging_finalize_recurse( CLOG_INFO(&LOG, 4, "Found root ID '%s' for resync root ID '%s'", id_root->name, id->name); - BLI_assert(id_root->override_library != NULL); + BLI_assert(id_root->override_library != nullptr); LinkNodePair **id_resync_roots_p; if (!BLI_ghash_ensure_p(id_roots, id_root, (void ***)&id_resync_roots_p)) { - *id_resync_roots_p = MEM_callocN(sizeof(**id_resync_roots_p), __func__); + *id_resync_roots_p = MEM_cnew<LinkNodePair>(__func__); } BLI_linklist_append(*id_resync_roots_p, id); @@ -2169,13 +2242,14 @@ static void lib_override_library_main_resync_on_library_indirect_level( /* Detect all linked data that would need to be overridden if we had to create an override from * those used by current existing overrides. */ - LibOverrideGroupTagData data = {.bmain = bmain, - .scene = scene, - .id_root = NULL, - .tag = LIB_TAG_DOIT, - .missing_tag = LIB_TAG_MISSING, - .is_override = false, - .is_resync = true}; + LibOverrideGroupTagData data = {}; + data.bmain = bmain; + data.scene = scene; + data.id_root = nullptr; + data.tag = LIB_TAG_DOIT; + data.missing_tag = LIB_TAG_MISSING; + data.is_override = false; + data.is_resync = true; lib_override_group_tag_data_object_to_collection_init(&data); ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { @@ -2228,10 +2302,11 @@ static void lib_override_library_main_resync_on_library_indirect_level( continue; } - MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); - BLI_assert(entry != NULL); + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>( + BLI_ghash_lookup(bmain->relations->relations_from_pointers, id)); + BLI_assert(entry != nullptr); - for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != NULL; + for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != nullptr; entry_item = entry_item->next) { if (entry_item->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) { continue; @@ -2264,13 +2339,14 @@ static void lib_override_library_main_resync_on_library_indirect_level( BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); GHashIterator *id_roots_iter = BLI_ghashIterator_new(id_roots); while (!BLI_ghashIterator_done(id_roots_iter)) { - ID *id_root = BLI_ghashIterator_getKey(id_roots_iter); - LinkNodePair *id_resync_roots = BLI_ghashIterator_getValue(id_roots_iter); + ID *id_root = static_cast<ID *>(BLI_ghashIterator_getKey(id_roots_iter)); + LinkNodePair *id_resync_roots = static_cast<LinkNodePair *>( + BLI_ghashIterator_getValue(id_roots_iter)); CLOG_INFO( &LOG, 2, "Checking validity of computed TODO data for root '%s'... \n", id_root->name); - for (LinkNode *id_resync_root_iter = id_resync_roots->list; id_resync_root_iter != NULL; + for (LinkNode *id_resync_root_iter = id_resync_roots->list; id_resync_root_iter != nullptr; id_resync_root_iter = id_resync_root_iter->next) { - ID *id_resync_root = id_resync_root_iter->link; + ID *id_resync_root = static_cast<ID *>(id_resync_root_iter->link); BLI_assert(id_resync_root == id_root || !BLI_ghash_haskey(id_roots, id_resync_root)); if (id_resync_root == id_root) { BLI_assert(id_resync_root_iter == id_resync_roots->list && @@ -2288,13 +2364,14 @@ static void lib_override_library_main_resync_on_library_indirect_level( BKE_main_relations_free(bmain); BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - ListBase no_main_ids_list = {NULL}; + ListBase no_main_ids_list = {nullptr}; GHashIterator *id_roots_iter = BLI_ghashIterator_new(id_roots); while (!BLI_ghashIterator_done(id_roots_iter)) { - ID *id_root = BLI_ghashIterator_getKey(id_roots_iter); + ID *id_root = static_cast<ID *>(BLI_ghashIterator_getKey(id_roots_iter)); Library *library = id_root->lib; - LinkNodePair *id_resync_roots = BLI_ghashIterator_getValue(id_roots_iter); + LinkNodePair *id_resync_roots = static_cast<LinkNodePair *>( + BLI_ghashIterator_getValue(id_roots_iter)); if (ID_IS_LINKED(id_root)) { id_root->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED; @@ -2326,7 +2403,7 @@ static void lib_override_library_main_resync_on_library_indirect_level( } } - BLI_linklist_free(id_resync_roots->list, NULL); + BLI_linklist_free(id_resync_roots->list, nullptr); BLI_ghashIterator_step(id_roots_iter); } BLI_ghashIterator_free(id_roots_iter); @@ -2354,10 +2431,10 @@ static void lib_override_library_main_resync_on_library_indirect_level( } FOREACH_MAIN_ID_END; - BLI_ghash_free(id_roots, NULL, MEM_freeN); + BLI_ghash_free(id_roots, nullptr, MEM_freeN); /* In some fairly rare (and degenerate) cases, some root ID from other liboverrides may have been - * freed, and therefore set to NULL. Attempt to fix this as best as possible. */ + * freed, and therefore set to nullptr. Attempt to fix this as best as possible. */ BKE_lib_override_library_main_hierarchy_root_ensure(bmain); if (do_reports_recursive_resync_timing) { @@ -2372,10 +2449,10 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data) } ID *id_owner = cb_data->id_owner; ID *id = *cb_data->id_pointer; - if (id != NULL && ID_IS_LINKED(id) && id->lib != id_owner->lib) { + if (id != nullptr && ID_IS_LINKED(id) && id->lib != id_owner->lib) { const int owner_library_indirect_level = ID_IS_LINKED(id_owner) ? id_owner->lib->temp_index : 0; - if (owner_library_indirect_level > 200) { + if (owner_library_indirect_level > 100) { CLOG_ERROR(&LOG, "Levels of indirect usages of libraries is way too high, there are most likely " "dependency loops, skipping further building loops (involves at least '%s' from " @@ -2386,6 +2463,16 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data) id->lib->filepath); return IDWALK_RET_NOP; } + if (owner_library_indirect_level > 90) { + CLOG_WARN( + &LOG, + "Levels of indirect usages of libraries is suspiciously too high, there are most likely " + "dependency loops (involves at least '%s' from '%s' and '%s' from '%s')", + id_owner->name, + id_owner->lib->filepath, + id->name, + id->lib->filepath); + } if (owner_library_indirect_level >= id->lib->temp_index) { id->lib->temp_index = owner_library_indirect_level + 1; @@ -2433,12 +2520,13 @@ void BKE_lib_override_library_main_resync(Main *bmain, /* We use a specific collection to gather/store all 'orphaned' override collections and objects * generated by re-sync-process. This avoids putting them in scene's master collection. */ #define OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME "OVERRIDE_RESYNC_LEFTOVERS" - Collection *override_resync_residual_storage = BLI_findstring( - &bmain->collections, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME, offsetof(ID, name) + 2); - if (override_resync_residual_storage != NULL && ID_IS_LINKED(override_resync_residual_storage)) { - override_resync_residual_storage = NULL; + Collection *override_resync_residual_storage = static_cast<Collection *>(BLI_findstring( + &bmain->collections, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME, offsetof(ID, name) + 2)); + if (override_resync_residual_storage != nullptr && + ID_IS_LINKED(override_resync_residual_storage)) { + override_resync_residual_storage = nullptr; } - if (override_resync_residual_storage == NULL) { + if (override_resync_residual_storage == nullptr) { override_resync_residual_storage = BKE_collection_add( bmain, scene->master_collection, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME); /* Hide the collection from viewport and render. */ @@ -2466,7 +2554,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, /* Essentially ensures that potentially new overrides of new objects will be instantiated. */ lib_override_library_create_post_process( - bmain, scene, view_layer, NULL, NULL, NULL, override_resync_residual_storage, true); + bmain, scene, view_layer, nullptr, nullptr, nullptr, override_resync_residual_storage, true); if (BKE_collection_is_empty(override_resync_residual_storage)) { BKE_collection_delete(bmain, override_resync_residual_storage, true); @@ -2489,14 +2577,15 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root) /* Tag all library overrides in the chains of dependencies from the given root one. */ BKE_main_relations_create(bmain, 0); - LibOverrideGroupTagData data = {.bmain = bmain, - .scene = NULL, - .id_root = id_root, - .hierarchy_root_id = id_root->override_library->hierarchy_root, - .tag = LIB_TAG_DOIT, - .missing_tag = LIB_TAG_MISSING, - .is_override = true, - .is_resync = false}; + LibOverrideGroupTagData data{}; + data.bmain = bmain; + data.scene = nullptr; + data.id_root = id_root; + data.hierarchy_root_id = id_root->override_library->hierarchy_root; + data.tag = LIB_TAG_DOIT; + data.missing_tag = LIB_TAG_MISSING; + data.is_override = true; + data.is_resync = false; lib_override_group_tag_data_object_to_collection_init(&data); lib_override_overrides_group_tag(&data); @@ -2538,19 +2627,19 @@ void BKE_lib_override_library_make_local(ID *id) BKE_lib_override_library_free(&id->override_library, true); Key *shape_key = BKE_key_from_id(id); - if (shape_key != NULL) { + if (shape_key != nullptr) { shape_key->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE; } if (GS(id->name) == ID_SCE) { Collection *master_collection = ((Scene *)id)->master_collection; - if (master_collection != NULL) { + if (master_collection != nullptr) { master_collection->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE; } } bNodeTree *node_tree = ntreeFromID(id); - if (node_tree != NULL) { + if (node_tree != nullptr) { node_tree->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE; } } @@ -2558,8 +2647,8 @@ void BKE_lib_override_library_make_local(ID *id) BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure( IDOverrideLibrary *override) { - if (override->runtime == NULL) { - override->runtime = MEM_callocN(sizeof(*override->runtime), __func__); + if (override->runtime == nullptr) { + override->runtime = MEM_cnew<IDOverrideLibraryRuntime>(__func__); } return override->runtime; } @@ -2568,10 +2657,13 @@ BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure( BLI_INLINE GHash *override_library_rna_path_mapping_ensure(IDOverrideLibrary *override) { IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_runtime_ensure(override); - if (override_runtime->rna_path_to_override_properties == NULL) { + if (override_runtime->rna_path_to_override_properties == nullptr) { override_runtime->rna_path_to_override_properties = BLI_ghash_new( BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__); - for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) { + for (IDOverrideLibraryProperty *op = + static_cast<IDOverrideLibraryProperty *>(override->properties.first); + op != nullptr; + op = op->next) { BLI_ghash_insert(override_runtime->rna_path_to_override_properties, op->rna_path, op); } } @@ -2583,7 +2675,7 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibr const char *rna_path) { GHash *override_runtime = override_library_rna_path_mapping_ensure(override); - return BLI_ghash_lookup(override_runtime, rna_path); + return static_cast<IDOverrideLibraryProperty *>(BLI_ghash_lookup(override_runtime, rna_path)); } IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibrary *override, @@ -2592,8 +2684,8 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra { IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path); - if (op == NULL) { - op = MEM_callocN(sizeof(IDOverrideLibraryProperty), __func__); + if (op == nullptr) { + op = MEM_cnew<IDOverrideLibraryProperty>(__func__); op->rna_path = BLI_strdup(rna_path); BLI_addtail(&override->properties, op); @@ -2614,11 +2706,12 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra bool BKE_lib_override_rna_property_find(PointerRNA *idpoin, const IDOverrideLibraryProperty *library_prop, PointerRNA *r_override_poin, - PropertyRNA **r_override_prop) + PropertyRNA **r_override_prop, + int *r_index) { BLI_assert(RNA_struct_is_ID(idpoin->type) && ID_IS_OVERRIDE_LIBRARY(idpoin->data)); - return RNA_path_resolve_property( - idpoin, library_prop->rna_path, r_override_poin, r_override_prop); + return RNA_path_resolve_property_full( + idpoin, library_prop->rna_path, r_override_poin, r_override_prop, r_index); } void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst, @@ -2627,8 +2720,9 @@ void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst, op_dst->rna_path = BLI_strdup(op_src->rna_path); BLI_duplicatelist(&op_dst->operations, &op_src->operations); - for (IDOverrideLibraryPropertyOperation *opop_dst = op_dst->operations.first, - *opop_src = op_src->operations.first; + for (IDOverrideLibraryPropertyOperation * + opop_dst = static_cast<IDOverrideLibraryPropertyOperation *>(op_dst->operations.first), + *opop_src = static_cast<IDOverrideLibraryPropertyOperation *>(op_src->operations.first); opop_dst; opop_dst = opop_dst->next, opop_src = opop_src->next) { lib_override_library_property_operation_copy(opop_dst, opop_src); @@ -2637,7 +2731,7 @@ void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst, void lib_override_library_property_clear(IDOverrideLibraryProperty *op) { - BLI_assert(op->rna_path != NULL); + BLI_assert(op->rna_path != nullptr); MEM_freeN(op->rna_path); @@ -2650,11 +2744,11 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op) void BKE_lib_override_library_property_delete(IDOverrideLibrary *override, IDOverrideLibraryProperty *override_property) { - if (!ELEM(NULL, override->runtime, override->runtime->rna_path_to_override_properties)) { + if (!ELEM(nullptr, override->runtime, override->runtime->rna_path_to_override_properties)) { BLI_ghash_remove(override->runtime->rna_path_to_override_properties, override_property->rna_path, - NULL, - NULL); + nullptr, + nullptr); } lib_override_library_property_clear(override_property); BLI_freelinkN(&override->properties, override_property); @@ -2676,74 +2770,75 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_ *r_strict = true; } - if (subitem_locname != NULL) { - opop = BLI_findstring_ptr(&override_property->operations, - subitem_locname, - offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name)); + if (subitem_locname != nullptr) { + opop = static_cast<IDOverrideLibraryPropertyOperation *>( + BLI_findstring_ptr(&override_property->operations, + subitem_locname, + offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name))); - if (opop == NULL) { - return NULL; + if (opop == nullptr) { + return nullptr; } - if (subitem_refname == NULL || opop->subitem_reference_name == NULL) { - return subitem_refname == opop->subitem_reference_name ? opop : NULL; + if (subitem_refname == nullptr || opop->subitem_reference_name == nullptr) { + return subitem_refname == opop->subitem_reference_name ? opop : nullptr; } - return (subitem_refname != NULL && opop->subitem_reference_name != NULL && + return (subitem_refname != nullptr && opop->subitem_reference_name != nullptr && STREQ(subitem_refname, opop->subitem_reference_name)) ? opop : - NULL; + nullptr; } - if (subitem_refname != NULL) { - opop = BLI_findstring_ptr( - &override_property->operations, - subitem_refname, - offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name)); + if (subitem_refname != nullptr) { + opop = static_cast<IDOverrideLibraryPropertyOperation *>( + BLI_findstring_ptr(&override_property->operations, + subitem_refname, + offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name))); - if (opop == NULL) { - return NULL; + if (opop == nullptr) { + return nullptr; } - if (subitem_locname == NULL || opop->subitem_local_name == NULL) { - return subitem_locname == opop->subitem_local_name ? opop : NULL; + if (subitem_locname == nullptr || opop->subitem_local_name == nullptr) { + return subitem_locname == opop->subitem_local_name ? opop : nullptr; } - return (subitem_locname != NULL && opop->subitem_local_name != NULL && + return (subitem_locname != nullptr && opop->subitem_local_name != nullptr && STREQ(subitem_locname, opop->subitem_local_name)) ? opop : - NULL; + nullptr; } - if ((opop = BLI_listbase_bytes_find( + if ((opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find( &override_property->operations, &subitem_locindex, sizeof(subitem_locindex), - offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) { - return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL; + offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index))))) { + return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : nullptr; } - if ((opop = BLI_listbase_bytes_find( + if ((opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find( &override_property->operations, &subitem_refindex, sizeof(subitem_refindex), - offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_index)))) { - return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL; + offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_index))))) { + return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : nullptr; } /* `index == -1` means all indices, that is a valid fallback in case we requested specific index. */ if (!strict && (subitem_locindex != subitem_defindex) && - (opop = BLI_listbase_bytes_find( + (opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find( &override_property->operations, &subitem_defindex, sizeof(subitem_defindex), - offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) { + offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index))))) { if (r_strict) { *r_strict = false; } return opop; } - return NULL; + return nullptr; } IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get( @@ -2766,8 +2861,8 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_ strict, r_strict); - if (opop == NULL) { - opop = MEM_callocN(sizeof(IDOverrideLibraryPropertyOperation), __func__); + if (opop == nullptr) { + opop = MEM_cnew<IDOverrideLibraryPropertyOperation>(__func__); opop->operation = operation; if (subitem_locname) { opop->subitem_local_name = BLI_strdup(subitem_locname); @@ -2821,13 +2916,13 @@ void BKE_lib_override_library_property_operation_delete( } bool BKE_lib_override_library_property_operation_operands_validate( - struct IDOverrideLibraryPropertyOperation *override_property_operation, - struct PointerRNA *ptr_dst, - struct PointerRNA *ptr_src, - struct PointerRNA *ptr_storage, - struct PropertyRNA *prop_dst, - struct PropertyRNA *prop_src, - struct PropertyRNA *prop_storage) + IDOverrideLibraryPropertyOperation *override_property_operation, + PointerRNA *ptr_dst, + PointerRNA *ptr_src, + PointerRNA *ptr_storage, + PropertyRNA *prop_dst, + PropertyRNA *prop_src, + PropertyRNA *prop_storage) { switch (override_property_operation->operation) { case IDOVERRIDE_LIBRARY_OP_NOOP: @@ -2837,7 +2932,7 @@ bool BKE_lib_override_library_property_operation_operands_validate( case IDOVERRIDE_LIBRARY_OP_SUBTRACT: ATTR_FALLTHROUGH; case IDOVERRIDE_LIBRARY_OP_MULTIPLY: - if (ptr_storage == NULL || ptr_storage->data == NULL || prop_storage == NULL) { + if (ptr_storage == nullptr || ptr_storage->data == nullptr || prop_storage == nullptr) { BLI_assert_msg(0, "Missing data to apply differential override operation."); return false; } @@ -2847,8 +2942,8 @@ bool BKE_lib_override_library_property_operation_operands_validate( case IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE: ATTR_FALLTHROUGH; case IDOVERRIDE_LIBRARY_OP_REPLACE: - if ((ptr_dst == NULL || ptr_dst->data == NULL || prop_dst == NULL) || - (ptr_src == NULL || ptr_src->data == NULL || prop_src == NULL)) { + if ((ptr_dst == nullptr || ptr_dst->data == nullptr || prop_dst == nullptr) || + (ptr_src == nullptr || ptr_src->data == nullptr || prop_src == nullptr)) { BLI_assert_msg(0, "Missing data to apply override operation."); return false; } @@ -2859,10 +2954,10 @@ bool BKE_lib_override_library_property_operation_operands_validate( void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports) { - if (id->override_library == NULL) { + if (id->override_library == nullptr) { return; } - if (id->override_library->reference == NULL) { + if (id->override_library->reference == nullptr) { /* This is a template ID, could be linked or local, not an override. */ return; } @@ -2873,7 +2968,7 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList * RPT_ERROR, "Data corruption: data-block '%s' is using itself as library override reference", id->name); - id->override_library->reference = NULL; + id->override_library->reference = nullptr; return; } if (!ID_IS_LINKED(id->override_library->reference)) { @@ -2885,7 +2980,7 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList * "library override reference", id->name, id->override_library->reference->name); - id->override_library->reference = NULL; + id->override_library->reference = nullptr; return; } } @@ -2895,7 +2990,7 @@ void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports) ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (id->override_library != NULL) { + if (id->override_library != nullptr) { BKE_lib_override_library_validate(bmain, id, reports); } } @@ -2908,7 +3003,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) ID *reference = local->override_library->reference; - if (reference == NULL) { + if (reference == nullptr) { /* This is an override template, local status is always OK! */ return true; } @@ -2922,10 +3017,10 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) Object *ob_local = (Object *)local; if (ob_local->type == OB_ARMATURE) { Object *ob_reference = (Object *)local->override_library->reference; - BLI_assert(ob_local->data != NULL); - BLI_assert(ob_reference->data != NULL); - BKE_pose_ensure(bmain, ob_local, ob_local->data, true); - BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true); + BLI_assert(ob_local->data != nullptr); + BLI_assert(ob_reference->data != nullptr); + BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true); + BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true); } } @@ -2935,15 +3030,16 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local) RNA_id_pointer_create(local, &rnaptr_local); RNA_id_pointer_create(reference, &rnaptr_reference); - if (!RNA_struct_override_matches(bmain, - &rnaptr_local, - &rnaptr_reference, - NULL, - 0, - local->override_library, - RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | - RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, - NULL)) { + if (!RNA_struct_override_matches( + bmain, + &rnaptr_local, + &rnaptr_reference, + nullptr, + 0, + local->override_library, + (eRNAOverrideMatch)(RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | + RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN), + nullptr)) { local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; return false; } @@ -2957,7 +3053,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) ID *reference = local->override_library->reference; - if (reference == NULL) { + if (reference == nullptr) { /* This is an override template, reference is virtual, so its status is always OK! */ return true; } @@ -2981,10 +3077,10 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) Object *ob_local = (Object *)local; if (ob_local->type == OB_ARMATURE) { Object *ob_reference = (Object *)local->override_library->reference; - BLI_assert(ob_local->data != NULL); - BLI_assert(ob_reference->data != NULL); - BKE_pose_ensure(bmain, ob_local, ob_local->data, true); - BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true); + BLI_assert(ob_local->data != nullptr); + BLI_assert(ob_reference->data != nullptr); + BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true); + BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true); } } @@ -2995,11 +3091,11 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) if (!RNA_struct_override_matches(bmain, &rnaptr_local, &rnaptr_reference, - NULL, + nullptr, 0, local->override_library, RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, - NULL)) { + nullptr)) { local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK; return false; } @@ -3010,8 +3106,8 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local) bool BKE_lib_override_library_operations_create(Main *bmain, ID *local) { BLI_assert(!ID_IS_LINKED(local)); - BLI_assert(local->override_library != NULL); - const bool is_template = (local->override_library->reference == NULL); + BLI_assert(local->override_library != nullptr); + const bool is_template = (local->override_library->reference == nullptr); bool created = false; if (!is_template) { @@ -3029,10 +3125,10 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local) Object *ob_local = (Object *)local; if (ob_local->type == OB_ARMATURE) { Object *ob_reference = (Object *)local->override_library->reference; - BLI_assert(ob_local->data != NULL); - BLI_assert(ob_reference->data != NULL); - BKE_pose_ensure(bmain, ob_local, ob_local->data, true); - BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true); + BLI_assert(ob_local->data != nullptr); + BLI_assert(ob_reference->data != nullptr); + BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true); + BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true); } } @@ -3040,15 +3136,16 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local) RNA_id_pointer_create(local, &rnaptr_local); RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference); - eRNAOverrideMatchResult report_flags = 0; - RNA_struct_override_matches(bmain, - &rnaptr_local, - &rnaptr_reference, - NULL, - 0, - local->override_library, - RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, - &report_flags); + eRNAOverrideMatchResult report_flags = (eRNAOverrideMatchResult)0; + RNA_struct_override_matches( + bmain, + &rnaptr_local, + &rnaptr_reference, + nullptr, + 0, + local->override_library, + (eRNAOverrideMatch)(RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE), + &report_flags); if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { created = true; @@ -3074,8 +3171,9 @@ struct LibOverrideOpCreateData { static void lib_override_library_operations_create_cb(TaskPool *__restrict pool, void *taskdata) { - struct LibOverrideOpCreateData *create_data = BLI_task_pool_user_data(pool); - ID *id = taskdata; + LibOverrideOpCreateData *create_data = static_cast<LibOverrideOpCreateData *>( + BLI_task_pool_user_data(pool)); + ID *id = static_cast<ID *>(taskdata); if (BKE_lib_override_library_operations_create(create_data->bmain, id)) { /* Technically no need for atomic, all jobs write the same value and we only care if one did @@ -3104,12 +3202,14 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for * #BKE_lib_override_library_operations_create is not a problem then. */ LISTBASE_FOREACH (Object *, ob, &bmain->objects) { if (ob->type == OB_ARMATURE) { - BLI_assert(ob->data != NULL); - BKE_pose_ensure(bmain, ob, ob->data, true); + BLI_assert(ob->data != nullptr); + BKE_pose_ensure(bmain, ob, static_cast<bArmature *>(ob->data), true); } } - struct LibOverrideOpCreateData create_pool_data = {.bmain = bmain, .changed = false}; + LibOverrideOpCreateData create_pool_data{}; + create_pool_data.bmain = bmain; + create_pool_data.changed = false; TaskPool *task_pool = BLI_task_pool_create(&create_pool_data, TASK_PRIORITY_HIGH); FOREACH_MAIN_ID_BEGIN (bmain, id) { @@ -3120,14 +3220,15 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for if (GS(id->name) == ID_OB) { Object *ob = (Object *)id; if (ob->type == OB_ARMATURE) { - BLI_assert(ob->data != NULL); - BKE_pose_ensure(bmain, ob, ob->data, true); + BLI_assert(ob->data != nullptr); + BKE_pose_ensure(bmain, ob, static_cast<bArmature *>(ob->data), true); } } /* Only check overrides if we do have the real reference data available, and not some empty * 'placeholder' for missing data (broken links). */ if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) { - BLI_task_pool_push(task_pool, lib_override_library_operations_create_cb, id, false, NULL); + BLI_task_pool_push( + task_pool, lib_override_library_operations_create_cb, id, false, nullptr); } else { BKE_lib_override_library_properties_tag( @@ -3198,10 +3299,10 @@ static bool lib_override_library_id_reset_do(Main *bmain, ptr = RNA_property_pointer_get(&ptr, prop); ptr_lib = RNA_property_pointer_get(&ptr_lib, prop_lib); } - if (ptr.owner_id != NULL && ptr_lib.owner_id != NULL) { + if (ptr.owner_id != nullptr && ptr_lib.owner_id != nullptr) { BLI_assert(ptr.type == ptr_lib.type); do_op_delete = !(RNA_struct_is_ID(ptr.type) && - ptr.owner_id->override_library != NULL && + ptr.owner_id->override_library != nullptr && ptr.owner_id->override_library->reference == ptr_lib.owner_id); } } @@ -3233,7 +3334,7 @@ void BKE_lib_override_library_id_reset(Main *bmain, } if (lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override)) { - if (id_root->override_library->runtime != NULL && + if (id_root->override_library->runtime != nullptr && (id_root->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) != 0) { BKE_lib_override_library_update(bmain, id_root); @@ -3251,13 +3352,13 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, } void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root); - if (entry_vp == NULL) { + if (entry_vp == nullptr) { /* This ID is not used by nor using any other ID. */ lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override); return; } - MainIDRelationsEntry *entry = *entry_vp; + MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(*entry_vp); if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) { /* This ID has already been processed. */ return; @@ -3269,7 +3370,7 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, * relationship hierarchy. */ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; - for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr; to_id_entry = to_id_entry->next) { if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { /* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers) as @@ -3277,9 +3378,9 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, continue; } /* We only consider IDs from the same library. */ - if (*to_id_entry->id_pointer.to != NULL) { + if (*to_id_entry->id_pointer.to != nullptr) { ID *to_id = *to_id_entry->id_pointer.to; - if (to_id->override_library != NULL) { + if (to_id->override_library != nullptr) { lib_override_library_id_hierarchy_recursive_reset(bmain, to_id, do_reset_system_override); } } @@ -3298,7 +3399,7 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || id->override_library->runtime == NULL || + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || id->override_library->runtime == nullptr || (id->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) == 0) { continue; } @@ -3308,11 +3409,11 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, FOREACH_MAIN_ID_END; } -void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property, +void BKE_lib_override_library_operations_tag(IDOverrideLibraryProperty *override_property, const short tag, const bool do_set) { - if (override_property != NULL) { + if (override_property != nullptr) { if (do_set) { override_property->tag |= tag; } @@ -3331,18 +3432,18 @@ void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *o } } -void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override, +void BKE_lib_override_library_properties_tag(IDOverrideLibrary *override, const short tag, const bool do_set) { - if (override != NULL) { + if (override != nullptr) { LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) { BKE_lib_override_library_operations_tag(op, tag, do_set); } } } -void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set) +void BKE_lib_override_library_main_tag(Main *bmain, const short tag, const bool do_set) { ID *id; @@ -3354,7 +3455,7 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons FOREACH_MAIN_ID_END; } -void BKE_lib_override_library_id_unused_cleanup(struct ID *local) +void BKE_lib_override_library_id_unused_cleanup(ID *local) { if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) { LISTBASE_FOREACH_MUTABLE ( @@ -3373,7 +3474,7 @@ void BKE_lib_override_library_id_unused_cleanup(struct ID *local) } } -void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain) +void BKE_lib_override_library_main_unused_cleanup(Main *bmain) { ID *id; @@ -3429,10 +3530,10 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) ID *tmp_id = BKE_id_copy_ex(bmain, local->override_library->reference, - NULL, + nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG); - if (tmp_id == NULL) { + if (tmp_id == nullptr) { return; } @@ -3448,12 +3549,12 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) * collections' parents are fully runtime and reconstructed later. */ Key *local_key = BKE_key_from_id(local); Key *tmp_key = BKE_key_from_id(tmp_id); - if (local_key != NULL && tmp_key != NULL) { + if (local_key != nullptr && tmp_key != nullptr) { tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE); tmp_key->id.lib = local_key->id.lib; } - PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; + PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = nullptr; RNA_id_pointer_create(local, &rnaptr_src); RNA_id_pointer_create(tmp_id, &rnaptr_dst); if (local->override_library->storage) { @@ -3474,7 +3575,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) * So when we'll free tmp_id, we'll actually free old, outdated data from local. */ lib_override_id_swap(bmain, local, tmp_id); - if (local_key != NULL && tmp_key != NULL) { + if (local_key != nullptr && tmp_key != nullptr) { /* This is some kind of hard-coded 'always enforced override'. */ lib_override_id_swap(bmain, &local_key->id, &tmp_key->id); tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE); @@ -3494,7 +3595,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) /* Fun times again, thanks to bone pointers in pose data of objects. We keep same ID addresses, * but internal data has changed for sure, so we need to invalidate pose-bones caches. */ LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->pose != NULL && ob->data == local) { + if (ob->pose != nullptr && ob->data == local) { BLI_assert(ob->type == OB_ARMATURE); ob->pose->flag |= POSE_RECALC; /* We need to clear pose bone pointers immediately, some code may access those before pose @@ -3509,7 +3610,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) /* XXX For until we get fully shadow copies, we still need to ensure storage releases * its usage of any ID pointers it may have. */ BKE_id_free_ex(bmain, local->override_library->storage, LIB_ID_FREE_NO_UI_USER, true); - local->override_library->storage = NULL; + local->override_library->storage = nullptr; } local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK; @@ -3533,7 +3634,7 @@ void BKE_lib_override_library_main_update(Main *bmain) G_MAIN = bmain; FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (id->override_library != NULL) { + if (id->override_library != nullptr) { BKE_lib_override_library_update(bmain, id); } } @@ -3542,7 +3643,7 @@ void BKE_lib_override_library_main_update(Main *bmain) G_MAIN = orig_gmain; } -bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id) +bool BKE_lib_override_library_id_is_user_deletable(Main *bmain, ID *id) { /* The only strong known case currently are objects used by override collections. */ /* TODO: There are most likely other cases... This may need to be addressed in a better way at @@ -3591,11 +3692,11 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, /* This is actually purely local data with an override template, or one of those embedded IDs * (root node trees, master collections or shape-keys) that cannot have their own override. * Nothing to do here! */ - return NULL; + return nullptr; } BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local)); - BLI_assert(override_storage != NULL); + BLI_assert(override_storage != nullptr); UNUSED_VARS_NDEBUG(override_storage); /* Forcefully ensure we know about all needed override operations. */ @@ -3623,7 +3724,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, * actually a (performances) issue here, before doing it. */ storage_id = BKE_id_copy((Main *)override_storage, local); - if (storage_id != NULL) { + if (storage_id != nullptr) { PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage; RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference); RNA_id_pointer_create(local, &rnaptr_final); @@ -3632,11 +3733,11 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain, if (!RNA_struct_override_store( bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_library)) { BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true); - storage_id = NULL; + storage_id = nullptr; } } #else - storage_id = NULL; + storage_id = nullptr; #endif local->override_library->storage = storage_id; @@ -3654,7 +3755,7 @@ void BKE_lib_override_library_operations_store_end( /* Nothing else to do here really, we need to keep all temp override storage data-blocks in * memory until whole file is written anyway (otherwise we'd get mem pointers overlap). */ - local->override_library->storage = NULL; + local->override_library->storage = nullptr; } void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage) diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 2600a40153c..246999a1179 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -454,7 +454,7 @@ static void libblock_remap_reset_remapping_status_callback(ID *old_id, * \param old_id: the data-block to dereference (may be NULL if \a id is non-NULL). * \param new_id: the new data-block to replace \a old_id references with (may be NULL). * \param r_id_remap_data: if non-NULL, the IDRemap struct to use - * (uselful to retrieve info about remapping process). + * (useful to retrieve info about remapping process). */ ATTR_NONNULL(1) static void libblock_remap_data(Main *bmain, diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index c0eb1955fdf..12a661d139b 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -55,7 +55,7 @@ static void linestyle_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const FreestyleLineStyle *linestyle_dst = (FreestyleLineStyle *)id_dst; const FreestyleLineStyle *linestyle_src = (const FreestyleLineStyle *)id_src; - /* We never handle usercount here for own data. */ + /* We never handle user-count here for own data. */ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; /* We always need allocation of our private ID data. */ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index e5b875cadf9..04a07fb42be 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -1448,7 +1448,7 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata) slot->attribute_name = storage->name; if (storage->type == SHD_ATTRIBUTE_GEOMETRY) { const Mesh *mesh = (const Mesh *)fill_data->ob->data; - CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name); + const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name); slot->valid = layer != NULL; } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 15953c5068b..65586621489 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -121,7 +121,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int CustomData_MeshMasks mask = CD_MASK_MESH; if (mesh_src->id.tag & LIB_TAG_NO_MAIN) { - /* For copies in depsgraph, keep data like origindex and orco. */ + /* For copies in depsgraph, keep data like #CD_ORIGINDEX and #CD_ORCO. */ CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH); } @@ -1726,7 +1726,7 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) mul_m3_v3(m3, *lnors); } } - BKE_mesh_normals_tag_dirty(me); + BKE_mesh_tag_coords_changed(me); } void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) @@ -1748,6 +1748,7 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) } } } + BKE_mesh_tag_coords_changed_uniformly(me); } void BKE_mesh_tessface_ensure(Mesh *mesh) @@ -1946,7 +1947,7 @@ void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3(mv->co, vert_coords[i]); } - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(mesh); } void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, @@ -1960,7 +1961,7 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, for (int i = 0; i < mesh->totvert; i++, mv++) { mul_v3_m4v3(mv->co, mat, vert_coords[i]); } - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(mesh); } void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index 11b00caa611..bc0e8aa0644 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -789,7 +789,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, Span<Array<short>> material_remaps, const bool use_self, const bool hole_tolerant, - const int boolean_mode) + const int boolean_mode, + Vector<int> *r_intersecting_edges) { #ifdef WITH_GMP BLI_assert(meshes.size() == transforms.size()); @@ -826,7 +827,23 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, write_obj_mesh(m_out, "m_out"); } - return imesh_to_mesh(&m_out, mim); + Mesh *result = imesh_to_mesh(&m_out, mim); + + /* Store intersecting edge indices. */ + if (r_intersecting_edges != nullptr) { + for (int fi : m_out.face_index_range()) { + const Face &face = *m_out.face(fi); + const MPoly &poly = result->mpoly[fi]; + for (int corner_i : face.index_range()) { + if (face.is_intersect[corner_i]) { + int e_index = result->mloop[poly.loopstart + corner_i].e; + r_intersecting_edges->append(e_index); + } + } + } + } + + return result; #else // WITH_GMP UNUSED_VARS(meshes, transforms, @@ -834,7 +851,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, target_transform, use_self, hole_tolerant, - boolean_mode); + boolean_mode, + r_intersecting_edges); return nullptr; #endif // WITH_GMP } diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc index 5895eb7fd71..31e20750cf2 100644 --- a/source/blender/blenkernel/intern/mesh_calc_edges.cc +++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc @@ -81,7 +81,7 @@ static void add_existing_edges_to_hash_maps(Mesh *mesh, { /* Assume existing edges are valid. */ threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { - const int task_index = &edge_map - &edge_maps[0]; + const int task_index = &edge_map - edge_maps.data(); for (const MEdge &edge : Span(mesh->medge, mesh->totedge)) { OrderedEdge ordered_edge{edge.v1, edge.v2}; /* Only add the edge when it belongs into this map. */ @@ -98,7 +98,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh, { const Span<MLoop> loops{mesh->mloop, mesh->totloop}; threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { - const int task_index = &edge_map - &edge_maps[0]; + const int task_index = &edge_map - edge_maps.data(); for (const MPoly &poly : Span(mesh->mpoly, mesh->totpoly)) { Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop); const MLoop *prev_loop = &poly_loops.last(); @@ -131,7 +131,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg } threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { - const int task_index = &edge_map - &edge_maps[0]; + const int task_index = &edge_map - edge_maps.data(); int new_edge_index = edge_index_offsets[task_index]; for (EdgeMap::MutableItem item : edge_map.items()) { diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 9c1af72b1c8..476a9467887 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -41,7 +41,6 @@ #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" -#include "BKE_spline.hh" /* these 2 are only used by conversion functions */ #include "BKE_curve.h" /* -- */ diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index ba1004e8371..2366b7526a1 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -345,7 +345,7 @@ void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert, const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] { - if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) { + if (!BKE_mesh_vertex_normals_are_dirty(mesh)) { BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0); return mesh->runtime.vert_normals; } @@ -356,7 +356,7 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex; BLI_mutex_lock(normals_mutex); - if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) { + if (!BKE_mesh_vertex_normals_are_dirty(mesh)) { BLI_assert(mesh->runtime.vert_normals != nullptr); BLI_mutex_unlock(normals_mutex); return mesh->runtime.vert_normals; diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index c960a7f35f1..85aed01ce52 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -375,7 +375,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) while ((layer = BKE_id_attribute_from_index( const_cast<ID *>(&source->id), i++, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL))) { - AttributeDomain domain = BKE_id_attribute_domain(&source->id, layer); + eAttrDomain domain = BKE_id_attribute_domain(&source->id, layer); CustomData *target_cdata = domain == ATTR_DOMAIN_POINT ? &target->vdata : &target->ldata; const CustomData *source_cdata = domain == ATTR_DOMAIN_POINT ? &source->vdata : &source->ldata; diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc index 90e9a2a2ff6..d4bc47d5fd4 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.cc +++ b/source/blender/blenkernel/intern/mesh_runtime.cc @@ -244,11 +244,8 @@ bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh) void BKE_mesh_runtime_clear_geometry(Mesh *mesh) { - if (mesh->runtime.bvh_cache) { - bvhcache_free(mesh->runtime.bvh_cache); - mesh->runtime.bvh_cache = nullptr; - } - MEM_SAFE_FREE(mesh->runtime.looptris.array); + BKE_mesh_tag_coords_changed(mesh); + /* TODO(sergey): Does this really belong here? */ if (mesh->runtime.subdiv_ccg != nullptr) { BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg); @@ -259,6 +256,24 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) MEM_SAFE_FREE(mesh->runtime.subsurf_face_dot_tags); } +void BKE_mesh_tag_coords_changed(Mesh *mesh) +{ + BKE_mesh_normals_tag_dirty(mesh); + MEM_SAFE_FREE(mesh->runtime.looptris.array); + if (mesh->runtime.bvh_cache) { + bvhcache_free(mesh->runtime.bvh_cache); + mesh->runtime.bvh_cache = nullptr; + } +} + +void BKE_mesh_tag_coords_changed_uniformly(Mesh *mesh) +{ + BKE_mesh_tag_coords_changed(mesh); + /* The normals didn't change, since all vertices moved by the same amount. */ + BKE_mesh_poly_normals_clear_dirty(mesh); + BKE_mesh_vertex_normals_clear_dirty(mesh); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index 33b051c792c..106c4c610ba 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -2,12 +2,15 @@ #include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" +#include "BKE_bvhutils.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BLI_rand.hh" + namespace blender::bke::mesh_surface_sample { template<typename T> @@ -204,7 +207,7 @@ Span<float3> MeshAttributeInterpolator::ensure_nearest_weights() } void MeshAttributeInterpolator::sample_data(const GVArray &src, - const AttributeDomain domain, + const eAttrDomain domain, const eAttributeMapMode mode, const GMutableSpan dst) { @@ -259,4 +262,173 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_ } } +int sample_surface_points_spherical(RandomNumberGenerator &rng, + const Mesh &mesh, + const Span<int> looptri_indices_to_sample, + const float3 &sample_pos, + const float sample_radius, + const float approximate_density, + Vector<float3> &r_bary_coords, + Vector<int> &r_looptri_indices, + Vector<float3> &r_positions) +{ + const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), + BKE_mesh_runtime_looptri_len(&mesh)}; + + const float sample_radius_sq = pow2f(sample_radius); + const float sample_plane_area = M_PI * sample_radius_sq; + /* Used for switching between two triangle sampling strategies. */ + const float area_threshold = sample_plane_area; + + const int old_num = r_bary_coords.size(); + + for (const int looptri_index : looptri_indices_to_sample) { + const MLoopTri &looptri = looptris[looptri_index]; + + const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co; + const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co; + const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co; + + const float looptri_area = area_tri_v3(v0, v1, v2); + + if (looptri_area < area_threshold) { + /* The triangle is small compared to the sample radius. Sample by generating random + * barycentric coordinates. */ + const int amount = rng.round_probabilistic(approximate_density * looptri_area); + for ([[maybe_unused]] const int i : IndexRange(amount)) { + const float3 bary_coord = rng.get_barycentric_coordinates(); + const float3 point_pos = attribute_math::mix3(bary_coord, v0, v1, v2); + const float dist_to_sample_sq = math::distance_squared(point_pos, sample_pos); + if (dist_to_sample_sq > sample_radius_sq) { + continue; + } + + r_bary_coords.append(bary_coord); + r_looptri_indices.append(looptri_index); + r_positions.append(point_pos); + } + } + else { + /* The triangle is large compared to the sample radius. Sample by generating random points + * on the triangle plane within the sample radius. */ + float3 normal; + normal_tri_v3(normal, v0, v1, v2); + + float3 sample_pos_proj = sample_pos; + project_v3_plane(sample_pos_proj, normal, v0); + + const float proj_distance_sq = math::distance_squared(sample_pos_proj, sample_pos); + const float sample_radius_factor_sq = 1.0f - + std::min(1.0f, proj_distance_sq / sample_radius_sq); + const float radius_proj_sq = sample_radius_sq * sample_radius_factor_sq; + const float radius_proj = std::sqrt(radius_proj_sq); + const float circle_area = M_PI * radius_proj; + + const int amount = rng.round_probabilistic(approximate_density * circle_area); + + const float3 axis_1 = math::normalize(v1 - v0) * radius_proj; + const float3 axis_2 = math::normalize(math::cross(axis_1, math::cross(axis_1, v2 - v0))) * + radius_proj; + + for ([[maybe_unused]] const int i : IndexRange(amount)) { + const float r = std::sqrt(rng.get_float()); + const float angle = rng.get_float() * 2.0f * M_PI; + const float x = r * std::cos(angle); + const float y = r * std::sin(angle); + const float3 point_pos = sample_pos_proj + axis_1 * x + axis_2 * y; + if (!isect_point_tri_prism_v3(point_pos, v0, v1, v2)) { + /* Sampled point is not in the triangle. */ + continue; + } + + float3 bary_coord; + interp_weights_tri_v3(bary_coord, v0, v1, v2, point_pos); + + r_bary_coords.append(bary_coord); + r_looptri_indices.append(looptri_index); + r_positions.append(point_pos); + } + } + } + return r_bary_coords.size() - old_num; +} + +int sample_surface_points_projected( + RandomNumberGenerator &rng, + const Mesh &mesh, + BVHTreeFromMesh &mesh_bvhtree, + const float2 &sample_pos_re, + const float sample_radius_re, + const FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)> + region_position_to_ray, + const bool front_face_only, + const int tries_num, + const int max_points, + Vector<float3> &r_bary_coords, + Vector<int> &r_looptri_indices, + Vector<float3> &r_positions) +{ + const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), + BKE_mesh_runtime_looptri_len(&mesh)}; + + int point_count = 0; + for ([[maybe_unused]] const int _ : IndexRange(tries_num)) { + if (point_count == max_points) { + break; + } + + const float r = sample_radius_re * std::sqrt(rng.get_float()); + const float angle = rng.get_float() * 2.0f * M_PI; + float3 ray_start, ray_end; + const float2 pos_re = sample_pos_re + r * float2(std::cos(angle), std::sin(angle)); + region_position_to_ray(pos_re, ray_start, ray_end); + const float3 ray_direction = math::normalize(ray_end - ray_start); + + BVHTreeRayHit ray_hit; + ray_hit.dist = FLT_MAX; + ray_hit.index = -1; + BLI_bvhtree_ray_cast(mesh_bvhtree.tree, + ray_start, + ray_direction, + 0.0f, + &ray_hit, + mesh_bvhtree.raycast_callback, + &mesh_bvhtree); + + if (ray_hit.index == -1) { + continue; + } + + if (front_face_only) { + const float3 normal = ray_hit.no; + if (math::dot(ray_direction, normal) >= 0.0f) { + continue; + } + } + + const int looptri_index = ray_hit.index; + const float3 pos = ray_hit.co; + + const float3 bary_coords = compute_bary_coord_in_triangle(mesh, looptris[looptri_index], pos); + + r_positions.append(pos); + r_bary_coords.append(bary_coords); + r_looptri_indices.append(looptri_index); + point_count++; + } + return point_count; +} + +float3 compute_bary_coord_in_triangle(const Mesh &mesh, + const MLoopTri &looptri, + const float3 &position) +{ + const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co; + const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co; + const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co; + float3 bary_coords; + interp_weights_tri_v3(bary_coords, v0, v1, v2, position); + return bary_coords; +} + } // namespace blender::bke::mesh_surface_sample diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c index c0b2b33c47c..a677a0d6ebb 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.c +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -167,7 +167,7 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, if (!loopuvs) { BKE_reportf(reports, RPT_ERROR, - "Tangent space computation needs an UVMap, \"%s\" not found, aborting", + "Tangent space computation needs a UV Map, \"%s\" not found, aborting", uvmap); return; } diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c index 7cb656d2357..71d5722cb0e 100644 --- a/source/blender/blenkernel/intern/mesh_tessellate.c +++ b/source/blender/blenkernel/intern/mesh_tessellate.c @@ -138,7 +138,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata, } } -int BKE_mesh_tessface_calc_ex(CustomData *fdata, +static int mesh_tessface_calc(CustomData *fdata, CustomData *ldata, CustomData *pdata, MVert *mvert, @@ -382,13 +382,13 @@ int BKE_mesh_tessface_calc_ex(CustomData *fdata, void BKE_mesh_tessface_calc(Mesh *mesh) { - mesh->totface = BKE_mesh_tessface_calc_ex(&mesh->fdata, - &mesh->ldata, - &mesh->pdata, - mesh->mvert, - mesh->totface, - mesh->totloop, - mesh->totpoly); + mesh->totface = mesh_tessface_calc(&mesh->fdata, + &mesh->ldata, + &mesh->pdata, + mesh->mvert, + mesh->totface, + mesh->totloop, + mesh->totpoly); BKE_mesh_update_customdata_pointers(mesh, true); } diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index d16f7eaf588..9b2697ecc84 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -926,7 +926,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, } static bool mesh_validate_customdata(CustomData *data, - CustomDataMask mask, + eCustomDataMask mask, const uint totitems, const bool do_verbose, const bool do_fixes, @@ -953,7 +953,7 @@ static bool mesh_validate_customdata(CustomData *data, } if (mask != 0) { - CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type); + eCustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type); if ((layer_typemask & mask) == 0) { PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n", layer->type); ok = false; diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index c505a74724b..fdebf1d6a26 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -314,28 +314,23 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me) return me; } + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + if (runtime_data == nullptr || runtime_data->settings.level == 0) { + return me; + } + /* Initialize the settings before ensuring the descriptor as this is checked to decide whether * subdivision is needed at all, and checking the descriptor status might involve checking if the * data is out-of-date, which is a very expensive operation. */ SubdivToMeshSettings mesh_settings; - mesh_settings.resolution = me->runtime.subsurf_resolution; - mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display; + mesh_settings.resolution = runtime_data->resolution; + mesh_settings.use_optimal_display = runtime_data->use_optimal_display; if (mesh_settings.resolution < 3) { return me; } - const bool apply_render = me->runtime.subsurf_apply_render; - - SubdivSettings subdiv_settings; - BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render); - if (subdiv_settings.level == 0) { - return me; - } - - SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd); - - Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false); + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, me, false); if (subdiv == nullptr) { /* Happens on bad topology, but also on empty input mesh. */ return me; @@ -358,7 +353,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me) CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } - else if (me->runtime.subsurf_do_loop_normals) { + else if (runtime_data->calc_loop_normals) { BKE_mesh_calc_normals_split(subdiv_mesh); } diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c index 837b64affa8..f7d29806353 100644 --- a/source/blender/blenkernel/intern/multires_reshape_apply_base.c +++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c @@ -156,7 +156,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape /* Vertices were moved around, need to update normals after all the vertices are updated * Probably this is possible to do in the loop above, but this is rather tricky because * we don't know all needed vertices' coordinates there yet. */ - BKE_mesh_normals_tag_dirty(base_mesh); + BKE_mesh_tag_coords_changed(base_mesh); } void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context) diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index a5f6c453ed4..10abb8f20df 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -244,27 +244,50 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const } } -static void update_active_strip_from_listbase(AnimData *adt_dest, - NlaTrack *track_dest, - const NlaStrip *active_strip, - const ListBase /* NlaStrip */ *strips_source) +/** + * Find `active_strip` in `strips_source`, then return the strip with the same + * index from `strips_dest`. + */ +static NlaStrip *find_active_strip_from_listbase(const NlaStrip *active_strip, + const ListBase /* NlaStrip */ *strips_source, + const ListBase /* NlaStrip */ *strips_dest) { - NlaStrip *strip_dest = track_dest->strips.first; + BLI_assert_msg(BLI_listbase_count(strips_source) == BLI_listbase_count(strips_dest), + "Expecting the same number of source and destination strips"); + + NlaStrip *strip_dest = strips_dest->first; LISTBASE_FOREACH (const NlaStrip *, strip_source, strips_source) { - if (strip_source == active_strip) { - adt_dest->actstrip = strip_dest; - return; + if (strip_dest == NULL) { + /* The tracks are assumed to have an equal number of strips, but this is + * not the case. Not sure when this might happen, but it's better to not + * crash. */ + break; } - - if (strip_source->type == NLASTRIP_TYPE_META) { - update_active_strip_from_listbase(adt_dest, track_dest, active_strip, &strip_source->strips); + if (strip_source == active_strip) { + return strip_dest; + } + + const bool src_is_meta = strip_source->type == NLASTRIP_TYPE_META; + const bool dst_is_meta = strip_dest->type == NLASTRIP_TYPE_META; + BLI_assert_msg(src_is_meta == dst_is_meta, + "Expecting topology of source and destination strips to be equal"); + if (src_is_meta && dst_is_meta) { + NlaStrip *found_in_meta = find_active_strip_from_listbase( + active_strip, &strip_source->strips, &strip_dest->strips); + if (found_in_meta != NULL) { + return found_in_meta; + } } strip_dest = strip_dest->next; } + + return NULL; } -/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */ +/* Set adt_dest->actstrip to the strip with the same index as + * adt_source->actstrip. Note that this always sets `adt_dest->actstrip`; sets + * to NULL when `adt_source->actstrip` cannot be found. */ static void update_active_strip(AnimData *adt_dest, NlaTrack *track_dest, const AnimData *adt_source, @@ -272,13 +295,20 @@ static void update_active_strip(AnimData *adt_dest, { BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips)); - update_active_strip_from_listbase( - adt_dest, track_dest, adt_source->actstrip, &track_source->strips); + NlaStrip *active_strip = find_active_strip_from_listbase( + adt_source->actstrip, &track_source->strips, &track_dest->strips); + adt_dest->actstrip = active_strip; } /* Set adt_dest->act_track to the track with the same index as adt_source->act_track. */ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source) { + adt_dest->act_track = NULL; + adt_dest->actstrip = NULL; + if (adt_source->act_track == NULL && adt_source->actstrip == NULL) { + return; + } + BLI_assert(BLI_listbase_count(&adt_source->nla_tracks) == BLI_listbase_count(&adt_dest->nla_tracks)); @@ -287,7 +317,11 @@ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source) if (track_source == adt_source->act_track) { adt_dest->act_track = track_dest; } - update_active_strip(adt_dest, track_dest, adt_source, track_source); + + /* Only search for the active strip if it hasn't been found yet. */ + if (adt_dest->actstrip == NULL && adt_source->actstrip != NULL) { + update_active_strip(adt_dest, track_dest, adt_source, track_source); + } track_dest = track_dest->next; } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index cf50e8a3b43..e02d3b6486c 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4764,6 +4764,8 @@ static void registerGeometryNodes() register_node_type_geo_input_curve_tilt(); register_node_type_geo_input_id(); register_node_type_geo_input_index(); + register_node_type_geo_input_instance_rotation(); + register_node_type_geo_input_instance_scale(); register_node_type_geo_input_material_index(); register_node_type_geo_input_material(); register_node_type_geo_input_mesh_edge_angle(); @@ -4834,6 +4836,7 @@ static void registerGeometryNodes() register_node_type_geo_translate_instances(); register_node_type_geo_triangulate(); register_node_type_geo_viewer(); + register_node_type_geo_volume_cube(); register_node_type_geo_volume_to_mesh(); } diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 55b9951c52d..c8b87c27697 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -2271,10 +2271,14 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char Object *ob = object_add_common(bmain, view_layer, type, name); LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); - BKE_collection_object_add(bmain, layer_collection->collection, ob); + BKE_collection_viewlayer_object_add(bmain, view_layer, layer_collection->collection, ob); + /* Note: There is no way to be sure that #BKE_collection_viewlayer_object_add will actually + * manage to find a valid collection in given `view_layer` to add the new object to. */ Base *base = BKE_view_layer_base_find(view_layer, ob); - BKE_view_layer_base_select_and_set_active(view_layer, base); + if (base != nullptr) { + BKE_view_layer_base_select_and_set_active(view_layer, base); + } return ob; } @@ -2479,21 +2483,16 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag) * BKE_library_remap stuff, but... * the flush_constraint_targets callback am not sure about, so will delay that for now. */ LISTBASE_FOREACH (bConstraint *, con, &chan->constraints) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {nullptr, nullptr}; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { if (ct->tar == ob) { ct->tar = obn; } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, false); - } + BKE_constraint_targets_flush(con, &targets, false); } } } @@ -5484,11 +5483,9 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph, /* also update constraint targets */ LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {nullptr, nullptr}; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); + if (BKE_constraint_targets_get(con, &targets)) { LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { if (ct->tar) { BKE_object_modifier_update_subframe( @@ -5496,9 +5493,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph, } } /* free temp targets */ - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, false); - } + BKE_constraint_targets_flush(con, &targets, false); } } } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index cff7eb20b05..8c91ea2b369 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1485,8 +1485,6 @@ void BKE_sculptsession_free(Object *ob) BM_log_free(ss->bm_log); } - MEM_SAFE_FREE(ss->texcache); - if (ss->tex_pool) { BKE_image_pool_free(ss->tex_pool); } @@ -1674,7 +1672,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); CustomDataLayer *layer; - AttributeDomain domain; + eAttrDomain domain; if (BKE_pbvh_get_color_layer(me, &layer, &domain)) { if (layer->type == CD_PROP_COLOR) { @@ -2117,7 +2115,7 @@ 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 a sculpt session is active, ensure we have its faceset data porperly up-to-date. */ + /* 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); /* NOTE: In theory we could add that on the fly when required by sculpt code. @@ -2284,7 +2282,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg) subdiv_ccg->grid_hidden); } -bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d) +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) { @@ -2293,8 +2291,8 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d) if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { /* Regular mesh only draws from PBVH without modifiers and shape keys. */ - const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID)); - return !(ss->shapekey_active || ss->deform_modifiers_active || full_shading); + + return !(ss->shapekey_active || ss->deform_modifiers_active); } /* Multires and dyntopo always draw directly from the PBVH. */ diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index a5f7f73af70..b44b70bcd55 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2276,7 +2276,7 @@ void psys_emitter_customdata_mask(ParticleSystem *psys, CustomData_MeshMasks *r_ r_cddata_masks->fmask |= CD_MASK_MTFACE; } - /* ask for vertexgroups if we need them */ + /* Ask for vertex-groups if we need them. */ for (i = 0; i < PSYS_TOT_VG; i++) { if (psys->vgroup[i]) { r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 4be48efb2b5..c461b7f108d 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -1216,8 +1216,8 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, MEM_freeN(element_sum); MEM_freeN(element_map); - /* For hair, sort by origindex (allows optimization's in rendering), */ - /* however with virtual parents the children need to be in random order. */ + /* For hair, sort by #CD_ORIGINDEX (allows optimization's in rendering), + * however with virtual parents the children need to be in random order. */ if (part->type == PART_HAIR && !(part->childtype == PART_CHILD_FACES && part->parents != 0.0f)) { const int *orig_index = NULL; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index a7ab1536b1f..3ad770c5429 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3121,7 +3121,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa col.cfra = cfra; col.old_cfra = sim->psys->cfra; - /* get acceleration (from gravity, forcefields etc. to be re-applied in collision response) */ + /* Get acceleration (from gravity, force-fields etc. to be re-applied in collision response). */ sub_v3_v3v3(col.acc, pa->state.vel, pa->prev_state.vel); mul_v3_fl(col.acc, 1.0f / col.total_time); @@ -4962,7 +4962,7 @@ void particle_system_update(struct Depsgraph *depsgraph, } /* Save matrix for duplicators, - * at rendertime the actual dupliobject's matrix is used so don't update! */ + * at render-time the actual dupli-object's matrix is used so don't update! */ invert_m4_m4(psys->imat, ob->obmat); BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 1d4fbb92fa0..3b20bdc826c 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -714,6 +714,10 @@ void BKE_pbvh_free(PBVH *pbvh) MEM_SAFE_FREE(pbvh->vert_bitmap); + if (pbvh->vbo_id) { + GPU_pbvh_free_format(pbvh->vbo_id); + } + MEM_freeN(pbvh); } @@ -1264,7 +1268,7 @@ static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh)) return update_flags; } -bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, AttributeDomain *r_attr) +bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_attr) { CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)me); @@ -1274,7 +1278,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, Attribu return false; } - AttributeDomain domain = BKE_id_attribute_domain((ID *)me, layer); + eAttrDomain domain = BKE_id_attribute_domain((ID *)me, layer); if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { *r_layer = NULL; @@ -1299,6 +1303,17 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, PBVH *pbvh = data->pbvh; PBVHNode *node = data->nodes[n]; + CustomData *vdata, *ldata; + + if (!pbvh->bm) { + vdata = pbvh->vdata; + ldata = pbvh->ldata; + } + else { + vdata = &pbvh->bm->vdata; + ldata = &pbvh->bm->ldata; + } + if (node->flag & PBVH_RebuildDrawBuffers) { switch (pbvh->type) { case PBVH_GRIDS: @@ -1326,7 +1341,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, const int update_flags = pbvh_get_buffers_update_flags(pbvh); switch (pbvh->type) { case PBVH_GRIDS: - GPU_pbvh_grid_buffers_update(node->draw_buffers, + GPU_pbvh_grid_buffers_update(pbvh->vbo_id, + node->draw_buffers, pbvh->subdiv_ccg, pbvh->grids, pbvh->grid_flag_mats, @@ -1339,26 +1355,22 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, update_flags); break; case PBVH_FACES: { - CustomDataLayer *layer = NULL; - AttributeDomain domain; - - BKE_pbvh_get_color_layer(pbvh->mesh, &layer, &domain); - - GPU_pbvh_mesh_buffers_update(node->draw_buffers, + GPU_pbvh_mesh_buffers_update(pbvh->vbo_id, + node->draw_buffers, pbvh->verts, - pbvh->vert_normals, + vdata, + ldata, CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK), - layer ? layer->data : NULL, - layer ? layer->type : -1, - layer ? domain : ATTR_DOMAIN_AUTO, CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), pbvh->face_sets_color_seed, pbvh->face_sets_color_default, - update_flags); + update_flags, + pbvh->vert_normals); break; } case PBVH_BMESH: - GPU_pbvh_bmesh_buffers_update(node->draw_buffers, + GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id, + node->draw_buffers, pbvh->bm, node->bm_faces, node->bm_unique_verts, @@ -1379,8 +1391,79 @@ void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node) } } +static void pbvh_check_draw_layout(PBVH *pbvh) +{ + const CustomData *vdata; + const CustomData *ldata; + + if (!pbvh->vbo_id) { + pbvh->vbo_id = GPU_pbvh_make_format(); + } + + switch (pbvh->type) { + case PBVH_BMESH: + if (!pbvh->bm) { + /* BMesh hasn't been created yet */ + return; + } + + vdata = &pbvh->bm->vdata; + ldata = &pbvh->bm->ldata; + break; + case PBVH_FACES: + vdata = pbvh->vdata; + ldata = pbvh->ldata; + break; + case PBVH_GRIDS: + ldata = vdata = NULL; + break; + } + + /* Rebuild all draw buffers if attribute layout changed. + * + * NOTE: The optimization where we only send active attributes + * to the GPU in workbench mode is disabled due to bugs + * (there's no guarantee there isn't another EEVEE viewport which would + * free the draw buffers and corrupt the draw cache). + */ + if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) { + /* attribute layout changed; force rebuild */ + for (int i = 0; i < pbvh->totnode; i++) { + PBVHNode *node = pbvh->nodes + i; + + if (node->flag & PBVH_Leaf) { + node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; + } + } + } +} + static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag) { + const CustomData *vdata; + + if (!pbvh->vbo_id) { + pbvh->vbo_id = GPU_pbvh_make_format(); + } + + switch (pbvh->type) { + case PBVH_BMESH: + if (!pbvh->bm) { + /* BMesh hasn't been created yet */ + return; + } + + vdata = &pbvh->bm->vdata; + break; + case PBVH_FACES: + vdata = pbvh->vdata; + break; + case PBVH_GRIDS: + vdata = NULL; + break; + } + UNUSED_VARS(vdata); + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) { /* Free buffers uses OpenGL, so not in parallel. */ for (int n = 0; n < totnode; n++) { @@ -2540,7 +2623,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh, } if (origco) { - /* intersect with backuped original coordinates */ + /* Intersect with backed-up original coordinates. */ hit |= ray_face_nearest_tri(ray_start, ray_normal, origco[face_verts[0]], @@ -2783,7 +2866,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, PBVHFrustumPlanes *update_frustum, PBVHFrustumPlanes *draw_frustum, void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), - void *user_data) + void *user_data, + bool UNUSED(full_render)) { PBVHNode **nodes; int totnode; @@ -2806,6 +2890,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers; } + pbvh_check_draw_layout(pbvh); + /* Update draw buffers. */ if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) { pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag); @@ -3156,6 +3242,11 @@ bool BKE_pbvh_is_drawing(const PBVH *pbvh) return pbvh->is_drawing; } +bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh) +{ + return pbvh->draw_cache_invalid; +} + void BKE_pbvh_is_drawing_set(PBVH *pbvh, bool val) { pbvh->is_drawing = val; @@ -3229,8 +3320,3 @@ void BKE_pbvh_ensure_node_loops(PBVH *pbvh) MEM_SAFE_FREE(visit); } - -bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh) -{ - return pbvh->draw_cache_invalid; -} diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index be6e95426c2..dec93826b9b 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -44,7 +44,7 @@ using blender::IndexRange; namespace blender::bke { template<typename Func> -inline void to_static_color_type(const CustomDataType type, const Func &func) +inline void to_static_color_type(const eCustomDataType type, const Func &func) { switch (type) { case CD_PROP_COLOR: @@ -146,7 +146,7 @@ static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4]) extern "C" { void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) { - blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) { + blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); blender::bke::pbvh_vertex_color_get<T>(*pbvh, vertex, r_color); }); @@ -154,7 +154,7 @@ void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]) { - blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) { + blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); blender::bke::pbvh_vertex_color_set<T>(*pbvh, vertex, color); }); @@ -165,7 +165,7 @@ void BKE_pbvh_swap_colors(PBVH *pbvh, const int indices_num, float (*r_colors)[4]) { - blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) { + blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data); for (const int i : IndexRange(indices_num)) { @@ -181,7 +181,7 @@ void BKE_pbvh_store_colors(PBVH *pbvh, const int indices_num, float (*r_colors)[4]) { - blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) { + blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data); for (const int i : IndexRange(indices_num)) { @@ -199,7 +199,7 @@ void BKE_pbvh_store_colors_vertex(PBVH *pbvh, BKE_pbvh_store_colors(pbvh, indices, indices_num, r_colors); } else { - blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) { + blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); for (const int i : IndexRange(indices_num)) { blender::bke::pbvh_vertex_color_get<T>(*pbvh, indices[i], r_colors[i]); diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index d4c6dcfbc96..112fd01c699 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -376,6 +376,9 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index) return false; } + /* Trigger draw manager cache invalidation. */ + pbvh->draw_cache_invalid = true; + /* For each BMFace, store the AABB and AABB centroid */ BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC"); diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index a86663a9c74..a4ac2744a73 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -2,6 +2,8 @@ #pragma once +struct PBVHGPUFormat; + /** \file * \ingroup bke */ @@ -123,9 +125,7 @@ struct PBVHNode { PBVHPixelsNode pixels; }; -typedef enum { - PBVH_DYNTOPO_SMOOTH_SHADING = 1, -} PBVHFlags; +typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags; typedef struct PBVHBMeshLog PBVHBMeshLog; @@ -198,12 +198,14 @@ struct PBVH { const struct MeshElemMap *pmap; CustomDataLayer *color_layer; - AttributeDomain color_domain; + eAttrDomain color_domain; bool is_drawing; /* Used by DynTopo to invalidate the draw cache. */ bool draw_cache_invalid; + + struct PBVHGPUFormat *vbo_id; }; /* pbvh.c */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 2467ca16670..d7bdfe08ab9 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3232,7 +3232,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) scene, pid->calldata, &cache->startframe, &cache->endframe); } - /* XXX workaround for regression inroduced in ee3fadd, needs looking into */ + /* XXX: workaround for regression introduced in ee3fadd, needs looking into. */ if (pid->type == PTCACHE_TYPE_RIGIDBODY) { if ((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID) == 0) && diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 9720c61e3b9..e38c20d8eb7 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -315,9 +315,9 @@ void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud) CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, POINTCLOUD_ATTR_RADIUS)); } -bool BKE_pointcloud_customdata_required(PointCloud *UNUSED(pointcloud), CustomDataLayer *layer) +bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), const char *name) { - return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, POINTCLOUD_ATTR_POSITION); + return STREQ(name, POINTCLOUD_ATTR_POSITION); } /* Dependency Graph */ diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 60cc4ce83af..821976f8e0e 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1660,8 +1660,7 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) rigidbody_update_ob_array(rbw); } -static void rigidbody_update_sim_ob( - Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) +static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyOb *rbo) { /* only update if rigid body exists */ if (rbo->shared->physics_object == NULL) { @@ -1712,54 +1711,6 @@ static void rigidbody_update_sim_ob( RB_body_set_mass(rbo->shared->physics_object, 0.0f); } - /* update influence of effectors - but don't do it on an effector */ - /* only dynamic bodies need effector update */ - else if (rbo->type == RBO_TYPE_ACTIVE && - ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { - EffectorWeights *effector_weights = rbw->effector_weights; - EffectedPoint epoint; - ListBase *effectors; - - /* get effectors present in the group specified by effector_weights */ - effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false); - if (effectors) { - float eff_force[3] = {0.0f, 0.0f, 0.0f}; - float eff_loc[3], eff_vel[3]; - - /* create dummy 'point' which represents last known position of object as result of sim */ - /* XXX: this can create some inaccuracies with sim position, - * but is probably better than using un-simulated values? */ - RB_body_get_position(rbo->shared->physics_object, eff_loc); - RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel); - - pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint); - - /* Calculate net force of effectors, and apply to sim object: - * - we use 'central force' since apply force requires a "relative position" - * which we don't have... */ - BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL); - if (G.f & G_DEBUG) { - printf("\tapplying force (%f,%f,%f) to '%s'\n", - eff_force[0], - eff_force[1], - eff_force[2], - ob->id.name + 2); - } - /* activate object in case it is deactivated */ - if (!is_zero_v3(eff_force)) { - RB_body_activate(rbo->shared->physics_object); - } - RB_body_apply_central_force(rbo->shared->physics_object, eff_force); - } - else if (G.f & G_DEBUG) { - printf("\tno forces to apply to '%s'\n", ob->id.name + 2); - } - - /* cleanup */ - BKE_effectors_free(effectors); - } - /* NOTE: passive objects don't need to be updated since they don't move */ - /* NOTE: no other settings need to be explicitly updated here, * since RNA setters take care of the rest :) */ @@ -1854,7 +1805,7 @@ static void rigidbody_update_simulation(Depsgraph *depsgraph, rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); /* update simulation object... */ - rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo); + rigidbody_update_sim_ob(depsgraph, ob, rbo); } } FOREACH_COLLECTION_OBJECT_RECURSIVE_END; @@ -1986,6 +1937,69 @@ static void rigidbody_update_kinematic_obj_substep(ListBase *substep_targets, fl } } +static void rigidbody_update_external_forces(Depsgraph *depsgraph, + Scene *scene, + RigidBodyWorld *rbw) +{ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { + /* only update if rigid body exists */ + RigidBodyOb *rbo = ob->rigidbody_object; + if (ob->type != OB_MESH || rbo->shared->physics_object == NULL) { + continue; + } + + /* update influence of effectors - but don't do it on an effector */ + /* only dynamic bodies need effector update */ + if (rbo->type == RBO_TYPE_ACTIVE && + ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { + EffectorWeights *effector_weights = rbw->effector_weights; + EffectedPoint epoint; + ListBase *effectors; + + /* get effectors present in the group specified by effector_weights */ + effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false); + if (effectors) { + float eff_force[3] = {0.0f, 0.0f, 0.0f}; + float eff_loc[3], eff_vel[3]; + + /* create dummy 'point' which represents last known position of object as result of sim + */ + /* XXX: this can create some inaccuracies with sim position, + * but is probably better than using un-simulated values? */ + RB_body_get_position(rbo->shared->physics_object, eff_loc); + RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel); + + pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint); + + /* Calculate net force of effectors, and apply to sim object: + * - we use 'central force' since apply force requires a "relative position" + * which we don't have... */ + BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL); + if (G.f & G_DEBUG) { + printf("\tapplying force (%f,%f,%f) to '%s'\n", + eff_force[0], + eff_force[1], + eff_force[2], + ob->id.name + 2); + } + /* activate object in case it is deactivated */ + if (!is_zero_v3(eff_force)) { + RB_body_activate(rbo->shared->physics_object); + } + RB_body_apply_central_force(rbo->shared->physics_object, eff_force); + } + else if (G.f & G_DEBUG) { + printf("\tno forces to apply to '%s'\n", ob->id.name + 2); + } + + /* cleanup */ + BKE_effectors_free(effectors); + } + /* NOTE: passive objects don't need to be updated since they don't move */ + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; +} + static void rigidbody_free_substep_data(ListBase *substep_targets) { LISTBASE_FOREACH (LinkData *, link, substep_targets) { @@ -2220,26 +2234,27 @@ void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime BKE_ptcache_write(&pid, startframe); } - /* update and validate simulation */ - rigidbody_update_simulation(depsgraph, scene, rbw, false); - const float frame_diff = ctime - rbw->ltime; /* calculate how much time elapsed since last step in seconds */ const float timestep = 1.0f / (float)FPS * frame_diff * rbw->time_scale; const float substep = timestep / rbw->substeps_per_frame; - ListBase substep_targets = rigidbody_create_substep_data(rbw); + ListBase kinematic_substep_targets = rigidbody_create_substep_data(rbw); const float interp_step = 1.0f / rbw->substeps_per_frame; float cur_interp_val = interp_step; + /* update and validate simulation */ + rigidbody_update_simulation(depsgraph, scene, rbw, false); + for (int i = 0; i < rbw->substeps_per_frame; i++) { - rigidbody_update_kinematic_obj_substep(&substep_targets, cur_interp_val); + rigidbody_update_external_forces(depsgraph, scene, rbw); + rigidbody_update_kinematic_obj_substep(&kinematic_substep_targets, cur_interp_val); RB_dworld_step_simulation(rbw->shared->physics_world, substep, 0, substep); cur_interp_val += interp_step; } - rigidbody_free_substep_data(&substep_targets); + rigidbody_free_substep_data(&kinematic_substep_targets); rigidbody_update_simulation_post_step(depsgraph, rbw); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index de5589cf5dc..5bafce15b34 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -54,6 +54,7 @@ #include "SEQ_sequencer.h" #include "SEQ_sound.h" +#include "SEQ_time.h" static void sound_free_audio(bSound *sound); @@ -719,8 +720,8 @@ void *BKE_sound_scene_add_scene_sound_defaults(Scene *scene, Sequence *sequence) { return BKE_sound_scene_add_scene_sound(scene, sequence, - sequence->startdisp, - sequence->enddisp, + SEQ_time_left_handle_frame_get(sequence), + SEQ_time_right_handle_frame_get(sequence), sequence->startofs + sequence->anim_startofs); } @@ -745,8 +746,8 @@ void *BKE_sound_add_scene_sound_defaults(Scene *scene, Sequence *sequence) { return BKE_sound_add_scene_sound(scene, sequence, - sequence->startdisp, - sequence->enddisp, + SEQ_time_left_handle_frame_get(sequence), + SEQ_time_right_handle_frame_get(sequence), sequence->startofs + sequence->anim_startofs); } @@ -760,8 +761,12 @@ void BKE_sound_mute_scene_sound(void *handle, char mute) AUD_SequenceEntry_setMuted(handle, mute); } -void BKE_sound_move_scene_sound( - Scene *scene, void *handle, int startframe, int endframe, int frameskip, double audio_offset) +void BKE_sound_move_scene_sound(const Scene *scene, + void *handle, + int startframe, + int endframe, + int frameskip, + double audio_offset) { sound_verify_evaluated_id(&scene->id); const double fps = FPS; @@ -774,8 +779,8 @@ void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence) if (sequence->scene_sound) { BKE_sound_move_scene_sound(scene, sequence->scene_sound, - sequence->startdisp, - sequence->enddisp, + SEQ_time_left_handle_frame_get(sequence), + SEQ_time_right_handle_frame_get(sequence), sequence->startofs + sequence->anim_startofs, 0.0); } @@ -1344,7 +1349,7 @@ 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_move_scene_sound(Scene *UNUSED(scene), +void BKE_sound_move_scene_sound(const Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe), int UNUSED(endframe), diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.c b/source/blender/blenkernel/intern/subdiv_ccg_mask.c index 04a274d0215..1290f1e0834 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg_mask.c +++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.c @@ -155,7 +155,7 @@ static void mask_init_functions(SubdivCCGMaskEvaluator *mask_evaluator) bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator, const struct Mesh *mesh) { - if (CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK)) { + if (!CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK)) { return false; } /* Allocate all required memory. */ diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c index 1996273b681..fda833ffd27 100644 --- a/source/blender/blenkernel/intern/subdiv_eval.c +++ b/source/blender/blenkernel/intern/subdiv_eval.c @@ -247,7 +247,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv, } /* Set coordinates of base mesh vertices. */ set_coarse_positions(subdiv, mesh, coarse_vertex_cos); - /* Set face-varyign data to UV maps. */ + /* Set face-varying data to UV maps. */ const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) { const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index); diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 651905cce8d..22479f70433 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -5,9 +5,6 @@ * \ingroup bke */ -#include "BKE_mesh.h" -#include "BKE_subdiv_mesh.h" - #include "atomic_ops.h" #include "DNA_key_types.h" @@ -24,6 +21,7 @@ #include "BKE_subdiv.h" #include "BKE_subdiv_eval.h" #include "BKE_subdiv_foreach.h" +#include "BKE_subdiv_mesh.h" #include "MEM_guardedalloc.h" @@ -44,7 +42,7 @@ typedef struct SubdivMeshContext { /* UV layers interpolation. */ int num_uv_layers; MLoopUV *uv_layers[MAX_MTFACE]; - /* Orco interpolation. */ + /* Original coordinates (ORCO) interpolation. */ float (*orco)[3]; float (*cloth_orco)[3]; /* Per-subdivided vertex counter of averaged values. */ diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c index e43da956ce5..57af0192d59 100644 --- a/source/blender/blenkernel/intern/subdiv_modifier.c +++ b/source/blender/blenkernel/intern/subdiv_modifier.c @@ -3,8 +3,6 @@ #include "BKE_subdiv_modifier.h" -#include "BLI_session_uuid.h" - #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" @@ -21,22 +19,39 @@ #include "opensubdiv_capi.h" -void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings, - const SubsurfModifierData *smd, - const bool use_render_params) +bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, const bool use_render_params) { const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels; - settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE); - settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision); - settings->level = settings->is_simple ? - 1 : - (settings->is_adaptive ? smd->quality : requested_levels); - settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease); - settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( + SubdivSettings settings; + settings.is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE); + settings.is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision); + settings.level = settings.is_simple ? 1 : + (settings.is_adaptive ? smd->quality : requested_levels); + settings.use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease); + settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( smd->boundary_smooth); - settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( + settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( smd->uv_smooth); + + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + if (settings.level == 0) { + /* Modifier is effectively disabled, but still update settings if runtime data + * was already allocated. */ + if (runtime_data) { + runtime_data->settings = settings; + } + + return false; + } + + /* Allocate runtime data if it did not exist yet. */ + if (runtime_data == NULL) { + runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); + smd->modifier.runtime = runtime_data; + } + runtime_data->settings = settings; + return true; } static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene, @@ -133,37 +148,27 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene, bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh) { - return BLI_session_uuid_is_generated(&mesh->runtime.subsurf_session_uuid); + SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data; + return runtime_data && runtime_data->has_gpu_subdiv; } void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL; -Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd, - const SubdivSettings *subdiv_settings, +Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data, const Mesh *mesh, const bool for_draw_code) { - SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) { BKE_subdiv_free(runtime_data->subdiv); runtime_data->subdiv = NULL; } - Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh); + Subdiv *subdiv = BKE_subdiv_update_from_mesh( + runtime_data->subdiv, &runtime_data->settings, mesh); runtime_data->subdiv = subdiv; runtime_data->set_by_draw_code = for_draw_code; return subdiv; } -SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd) -{ - SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; - if (runtime_data == NULL) { - runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); - smd->modifier.runtime = runtime_data; - } - return runtime_data; -} - int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode) { if (is_final_render) { diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 58a0c46a339..966ef0af1fc 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -926,11 +926,9 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) int x; for (x = 1; x < edgeSize - 1; x++) { - /* This gives errors with -debug-fpe - * the normals don't seem to be unit length. - * this is most likely caused by edges with no - * faces which are now zerod out, see comment in: - * ccgSubSurf__calcVertNormals(), - campbell */ + /* NOTE(@campbellbarton): This gives errors with `--debug-fpe` the normals don't seem to be + * unit length. This is most likely caused by edges with no faces which are now zeroed out, + * see comment in: `ccgSubSurf__calcVertNormals()`. */ vd = ccgSubSurf_getEdgeData(ss, e, x); ccgDM_to_MVert(&mvert[i++], &key, vd); } diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index f9d3a44e5cb..8b462cba7ed 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -336,7 +336,11 @@ void BKE_tracking_settings_init(MovieTracking *tracking) tracking->stabilization.filter = TRACKING_FILTER_BILINEAR; tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS; - BKE_tracking_object_add(tracking, "Camera"); + /* Descending order of average error: tracks with the highest error are on top. */ + tracking->dopesheet.sort_method = TRACKING_DOPE_SORT_AVERAGE_ERROR; + tracking->dopesheet.flag |= TRACKING_DOPE_SORT_INVERSE; + + BKE_tracking_object_add(tracking, DATA_("Camera")); } ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking) @@ -2904,6 +2908,10 @@ static int channels_average_error_sort(const void *a, const void *b) return 1; } + if (channel_a->track->error == channel_b->track->error) { + return channels_alpha_sort(a, b); + } + return 0; } diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index d86a0c10f01..e2e0b4227e3 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -362,7 +362,7 @@ static MovieTrackingMarker *get_tracking_data_point(StabContext *ctx, * * As a simple default, we use the weighted average of the location markers * of the current frame as pivot point. TODO: It is planned to add further - * options, like e.g. anchoring the pivot point at the canvas. Moreover, + * options, like e.g. anchoring the pivot point at the canvas. Moreover, * it is planned to allow for a user controllable offset. */ static void setup_pivot(const float ref_pos[2], float r_pivot[2]) diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 30e02e5411b..b31632f0234 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -460,11 +460,20 @@ static size_t unit_as_string(char *str, } double value_conv = (value / unit->scalar) - unit->bias; + bool strip_skip = false; + + /* Negative precision is used to disable stripping of zeroes. + * This reduces text jumping when changing values. */ + if (prec < 0) { + strip_skip = true; + prec *= -1; + } /* Adjust precision to expected number of significant digits. * Note that here, we shall not have to worry about very big/small numbers, units are expected * to replace 'scientific notation' in those cases. */ prec -= integer_digits_d(value_conv); + CLAMP(prec, 0, 6); /* Convert to a string. */ @@ -478,12 +487,14 @@ static size_t unit_as_string(char *str, size_t i = len - 1; if (prec > 0) { - while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */ - str[i--] = pad; - } + if (!strip_skip) { + while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */ + str[i--] = pad; + } - if (i > 0 && str[i] == '.') { /* 10. -> 10 */ - str[i--] = pad; + if (i > 0 && str[i] == '.') { /* 10. -> 10 */ + str[i--] = pad; + } } } diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h index 9bb7f3bfa8b..4a7fae6e98c 100644 --- a/source/blender/blenlib/BLI_assert.h +++ b/source/blender/blenlib/BLI_assert.h @@ -73,7 +73,7 @@ void _BLI_assert_unreachable_print(const char *file, int line, const char *funct # define BLI_STATIC_ASSERT(a, msg) _STATIC_ASSERT(a); # endif #elif defined(__COVERITY__) -/* Workaround error with coverity */ +/* Workaround error with COVERITY. */ # define BLI_STATIC_ASSERT(a, msg) #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ diff --git a/source/blender/blenlib/BLI_bounds.hh b/source/blender/blenlib/BLI_bounds.hh index d20382ed500..f5a18a0ea48 100644 --- a/source/blender/blenlib/BLI_bounds.hh +++ b/source/blender/blenlib/BLI_bounds.hh @@ -28,10 +28,11 @@ template<typename T> static std::optional<MinMaxResult<T>> min_max(Span<T> value if (values.is_empty()) { return std::nullopt; } + const MinMaxResult<T> init{values.first(), values.first()}; return threading::parallel_reduce( values.index_range(), 1024, - MinMaxResult<T>(), + init, [&](IndexRange range, const MinMaxResult<T> &init) { MinMaxResult<T> result = init; for (const int i : range) { @@ -55,10 +56,11 @@ static std::optional<MinMaxResult<T>> min_max_with_radii(Span<T> values, Span<Ra if (values.is_empty()) { return std::nullopt; } + const MinMaxResult<T> init{values.first(), values.first()}; return threading::parallel_reduce( values.index_range(), 1024, - MinMaxResult<T>(), + init, [&](IndexRange range, const MinMaxResult<T> &init) { MinMaxResult<T> result = init; for (const int i : range) { diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh index 98fd7d0f15d..b1b9aeb17f1 100644 --- a/source/blender/blenlib/BLI_color.hh +++ b/source/blender/blenlib/BLI_color.hh @@ -79,7 +79,7 @@ enum class eSpace { }; std::ostream &operator<<(std::ostream &stream, const eSpace &space); -/** Template class to store RGBA values with different precision, space and alpha association. */ +/** Template class to store RGBA values with different precision, space, and alpha association. */ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA { public: ChannelStorageType r, g, b, a; @@ -167,7 +167,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al } /** - * Convert to its byte encoded counter space. + * Convert to its byte encoded counterpart. */ ColorSceneLinearByteEncoded4b<Alpha> encode() const { @@ -179,7 +179,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al /** * Convert color and alpha association to premultiplied alpha. * - * Does nothing when color has already a premultiplied alpha. + * Does nothing when color already has a premultiplied alpha. */ ColorSceneLinear4f<eAlpha::Premultiplied> premultiply_alpha() const { @@ -196,7 +196,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al /** * Convert color and alpha association to straight alpha. * - * Does nothing when color has straighten alpha. + * Does nothing when color has straight alpha. */ ColorSceneLinear4f<eAlpha::Straight> unpremultiply_alpha() const { @@ -228,7 +228,7 @@ class ColorSceneLinearByteEncoded4b final } /** - * Convert to back to float color. + * Convert to a float color. */ ColorSceneLinear4f<Alpha> decode() const { diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh index d02760d9178..985d914f4a4 100644 --- a/source/blender/blenlib/BLI_generic_virtual_array.hh +++ b/source/blender/blenlib/BLI_generic_virtual_array.hh @@ -61,7 +61,9 @@ class GVArrayImpl { /* A generic version of #VMutableArrayImpl. */ class GVMutableArrayImpl : public GVArrayImpl { public: - GVMutableArrayImpl(const CPPType &type, int64_t size); + GVMutableArrayImpl(const CPPType &type, int64_t size) : GVArrayImpl(type, size) + { + } virtual void set_by_copy(int64_t index, const void *value); virtual void set_by_relocate(int64_t index, void *value); @@ -105,7 +107,7 @@ class GVArrayCommon { Storage storage_; protected: - GVArrayCommon(); + GVArrayCommon() = default; GVArrayCommon(const GVArrayCommon &other); GVArrayCommon(GVArrayCommon &&other) noexcept; GVArrayCommon(const GVArrayImpl *impl); @@ -186,6 +188,10 @@ class GVArray : public GVArrayCommon { GVArray(const GVArrayImpl *impl); GVArray(std::shared_ptr<const GVArrayImpl> impl); + GVArray(varray_tag::span /* tag */, GSpan span); + GVArray(varray_tag::single_ref /* tag */, const CPPType &type, int64_t size, const void *value); + GVArray(varray_tag::single /* tag */, const CPPType &type, int64_t size, const void *value); + template<typename T> GVArray(const VArray<T> &varray); template<typename T> VArray<T> typed() const; @@ -643,10 +649,18 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl { const int64_t element_size_; public: - GVArrayImpl_For_GSpan(const GMutableSpan span); + GVArrayImpl_For_GSpan(const GMutableSpan span) + : GVMutableArrayImpl(span.type(), span.size()), + data_(span.data()), + element_size_(span.type().size()) + { + } protected: - GVArrayImpl_For_GSpan(const CPPType &type, int64_t size); + GVArrayImpl_For_GSpan(const CPPType &type, int64_t size) + : GVMutableArrayImpl(type, size), element_size_(type.size()) + { + } public: void get(int64_t index, void *r_value) const override; @@ -667,6 +681,61 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl { void *dst) const override; }; +class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan { + public: + using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVArrayImpl_For_SingleValueRef. + * \{ */ + +class GVArrayImpl_For_SingleValueRef : public GVArrayImpl { + protected: + const void *value_ = nullptr; + + public: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) + : GVArrayImpl(type, size), value_(value) + { + } + + protected: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size) + { + } + + void get(const int64_t index, void *r_value) const override; + void get_to_uninitialized(const int64_t index, void *r_value) const override; + bool is_span() const override; + GSpan get_internal_span() const override; + bool is_single() const override; + void get_internal_single(void *r_value) const override; + void materialize(const IndexMask mask, void *dst) const override; + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override; + void materialize_compressed(const IndexMask mask, void *dst) const override; + void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override; +}; + +class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef { + public: + using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + /** \} */ /* -------------------------------------------------------------------- */ @@ -809,6 +878,22 @@ inline bool GVArrayCommon::is_empty() const /** \name Inline methods for #GVArray. * \{ */ +inline GVArray::GVArray(varray_tag::span /* tag */, const GSpan span) +{ + /* Use const-cast because the underlying virtual array implementation is shared between const + * and non const data. */ + GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()}; + this->emplace<GVArrayImpl_For_GSpan_final>(mutable_span); +} + +inline GVArray::GVArray(varray_tag::single_ref /* tag */, + const CPPType &type, + const int64_t size, + const void *value) +{ + this->emplace<GVArrayImpl_For_SingleValueRef_final>(type, size, value); +} + namespace detail { template<typename StorageT> constexpr GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get() { @@ -849,15 +934,15 @@ template<typename T> inline GVArray::GVArray(const VArray<T> &varray) if (varray.try_assign_GVArray(*this)) { return; } - /* Need to check this before the span/single special cases, because otherwise we might loose - * ownership to the referenced data when #varray goes out of scope. */ - if (varray.may_have_ownership()) { - *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); - } - else if (varray.is_single()) { + if (varray.is_single()) { T value = varray.get_internal_single(); *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value); } + /* Need to check this before the span special case, because otherwise we might loose + * ownership to the referenced data when #varray goes out of scope. */ + else if (varray.may_have_ownership()) { + *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); + } else if (varray.is_span()) { Span<T> data = varray.get_internal_span(); *this = GVArray::ForSpan(data); @@ -877,14 +962,14 @@ template<typename T> inline VArray<T> GVArray::typed() const if (this->try_assign_VArray(varray)) { return varray; } - if (this->may_have_ownership()) { - return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); - } if (this->is_single()) { T value; this->get_internal_single(&value); return VArray<T>::ForSingle(value, this->size()); } + if (this->may_have_ownership()) { + return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); + } if (this->is_span()) { const Span<T> span = this->get_internal_span().typed<T>(); return VArray<T>::ForSpan(span); diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 7f90ec20b66..8743b135dff 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -562,7 +562,7 @@ bool BLI_ghashutil_ptrcmp(const void *a, const void *b); /** * This function implements the widely used `djb` hash apparently posted - * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit + * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit * unsigned hash value starts at 5381 and for each byte 'c' in the * string, is updated: `hash = hash * 33 + c`. * This function uses the signed value of each byte. diff --git a/source/blender/blenlib/BLI_hash_tables.hh b/source/blender/blenlib/BLI_hash_tables.hh index 334634613a2..156fe481828 100644 --- a/source/blender/blenlib/BLI_hash_tables.hh +++ b/source/blender/blenlib/BLI_hash_tables.hh @@ -209,11 +209,11 @@ template<typename Key, Key EmptyValue, Key RemovedValue> struct TemplatedKeyInfo }; /** - * 0xffff...ffff indicates an empty slot. - * 0xffff...fffe indicates a removed slot. + * `0xffff...ffff` indicates an empty slot. + * `0xffff...fffe` indicates a removed slot. * * Those specific values are used, because with them a single comparison is enough to check whether - * a slot is occupied. The keys 0x0000...0000 and 0x0000...0001 also satisfy this constraint. + * a slot is occupied. The keys `0x0000...0000` and `0x0000...0001` also satisfy this constraint. * However, nullptr is much more likely to be used as valid key. */ template<typename Pointer> struct PointerKeyInfo { diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh index b87ab0afc98..22bdf090181 100644 --- a/source/blender/blenlib/BLI_index_mask.hh +++ b/source/blender/blenlib/BLI_index_mask.hh @@ -278,7 +278,7 @@ class IndexMask { * before each range in the return value starts. */ Vector<IndexRange> extract_ranges_invert(const IndexRange full_range, - Vector<int64_t> *r_skip_amounts) const; + Vector<int64_t> *r_skip_amounts = nullptr) const; }; } // namespace blender diff --git a/source/blender/blenlib/BLI_index_mask_ops.hh b/source/blender/blenlib/BLI_index_mask_ops.hh index 48a1f27a2fa..f67abb1d550 100644 --- a/source/blender/blenlib/BLI_index_mask_ops.hh +++ b/source/blender/blenlib/BLI_index_mask_ops.hh @@ -13,6 +13,7 @@ #include "BLI_index_mask.hh" #include "BLI_task.hh" #include "BLI_vector.hh" +#include "BLI_virtual_array.hh" namespace blender::index_mask_ops { @@ -57,4 +58,17 @@ inline IndexMask find_indices_based_on_predicate(const IndexMask indices_to_chec return detail::find_indices_based_on_predicate__merge(indices_to_check, sub_masks, r_indices); } +/** + * Find the true indices in a virtual array. This is a version of + * #find_indices_based_on_predicate optimised for a virtual array input. + * + * \param parallel_grain_size: The grain size for when the virtual array isn't a span or a single + * value internally. This should be adjusted based on the expected cost of evaluating the virtual + * array-- more expensive virtual arrays should have smaller grain sizes. + */ +IndexMask find_indices_from_virtual_array(IndexMask indices_to_check, + const VArray<bool> &virtual_array, + int64_t parallel_grain_size, + Vector<int64_t> &r_indices); + } // namespace blender::index_mask_ops diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh index 034c6968c94..b15179f75b6 100644 --- a/source/blender/blenlib/BLI_math_base.hh +++ b/source/blender/blenlib/BLI_math_base.hh @@ -14,19 +14,9 @@ #include "BLI_math_base_safe.h" #include "BLI_utildefines.h" -#ifdef WITH_GMP -# include "BLI_math_mpq.hh" -#endif - namespace blender::math { -template<typename T> -inline constexpr bool is_math_float_type = (std::is_floating_point_v<T> -#ifdef WITH_GMP - || std::is_same_v<T, mpq_class> -#endif -); - +template<typename T> inline constexpr bool is_math_float_type = std::is_floating_point_v<T>; template<typename T> inline constexpr bool is_math_integral_type = std::is_integral_v<T>; template<typename T> inline bool is_zero(const T &a) @@ -54,6 +44,16 @@ template<typename T> inline T max(const T &a, const T &b) return std::max(a, b); } +template<typename T> inline void max_inplace(T &a, const T &b) +{ + a = math::max(a, b); +} + +template<typename T> inline void min_inplace(T &a, const T &b) +{ + a = math::min(a, b); +} + template<typename T> inline T clamp(const T &a, const T &min, const T &max) { return std::clamp(a, min, max); diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index 64b820a22b0..6386a7f76f8 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -123,7 +123,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c * one of the primaries, it lies outside the color gamut * accessible from the given triple of primaries. Desaturate * it by adding white, equal quantities of R, G, and B, enough - * to make RGB all positive. The function returns 1 if the + * to make RGB all positive. The function returns 1 if the * components were modified, zero otherwise. */ int constrain_rgb(float *r, float *g, float *b); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 5c1b6c8d774..93b413ab755 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -136,7 +136,7 @@ bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], bool is_poly_convex_v2(const float verts[][2], unsigned int nr); /** * Check if either of the diagonals along this quad create flipped triangles - * (normals pointing away from eachother). + * (normals pointing away from each other). * - (1 << 0): (v1-v3) is flipped. * - (1 << 1): (v2-v4) is flipped. */ diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index edfe53bc938..2cd2a299d53 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -374,7 +374,7 @@ void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[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 zerod. + * 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]); diff --git a/source/blender/blenlib/BLI_math_mpq.hh b/source/blender/blenlib/BLI_math_mpq.hh index 7b43c90da84..02c92705323 100644 --- a/source/blender/blenlib/BLI_math_mpq.hh +++ b/source/blender/blenlib/BLI_math_mpq.hh @@ -19,4 +19,10 @@ */ # include "gmpxx.h" +# include "BLI_math_base.hh" + +namespace blender::math { +template<> inline constexpr bool is_math_float_type<mpq_class> = true; +} + #endif /* WITH_GMP */ diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh index e36bbedee32..7f20881dfa3 100644 --- a/source/blender/blenlib/BLI_math_vec_types.hh +++ b/source/blender/blenlib/BLI_math_vec_types.hh @@ -14,10 +14,6 @@ #include "BLI_utildefines.h" -#ifdef WITH_GMP -# include "BLI_math_mpq.hh" -#endif - namespace blender { /* clang-format off */ diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh index 7983bbccb35..384c4b49070 100644 --- a/source/blender/blenlib/BLI_math_vector.hh +++ b/source/blender/blenlib/BLI_math_vector.hh @@ -159,6 +159,39 @@ inline T safe_mod(const vec_base<T, Size> &a, const T &b) return result; } +/** + * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a . + * In other words, it is equivalent to `divide_ceil(a, b) * b`. + * It is undefined if \a a is negative or \b b is not strictly positive. + */ +template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))> +inline vec_base<T, Size> ceil_to_multiple(const vec_base<T, Size> &a, const vec_base<T, Size> &b) +{ + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { + BLI_assert(a[i] >= 0); + BLI_assert(b[i] > 0); + result[i] = ((a[i] + b[i] - 1) / b[i]) * b[i]; + } + return result; +} + +/** + * Integer division that returns the ceiling, instead of flooring like normal C division. + * It is undefined if \a a is negative or \b b is not strictly positive. + */ +template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))> +inline vec_base<T, Size> divide_ceil(const vec_base<T, Size> &a, const vec_base<T, Size> &b) +{ + vec_base<T, Size> result; + for (int i = 0; i < Size; i++) { + BLI_assert(a[i] >= 0); + BLI_assert(b[i] > 0); + result[i] = (a[i] + b[i] - 1) / b[i]; + } + return result; +} + template<typename T, int Size> inline void min_max(const vec_base<T, Size> &vector, vec_base<T, Size> &min, diff --git a/source/blender/blenlib/BLI_utildefines_iter.h b/source/blender/blenlib/BLI_utildefines_iter.h index 870e90bd971..03dc775a66b 100644 --- a/source/blender/blenlib/BLI_utildefines_iter.h +++ b/source/blender/blenlib/BLI_utildefines_iter.h @@ -21,7 +21,7 @@ * (100, 3) -> [16, 49, 83] * (100, 100) -> [0..99] * </pre> - * \note this is mainly useful for numbers that might not divide evenly into eachother. + * \note this is mainly useful for numbers that might not divide evenly into each other. */ #define BLI_FOREACH_SPARSE_RANGE(src, dst, i) \ for (int _src = (src), _src2 = _src * 2, _dst2 = (dst)*2, _error = _dst2 - _src, i = 0, _delta; \ diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 6efd1d6d769..8f228ea188e 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -872,6 +872,22 @@ template<typename T> class VArrayCommon { template<typename T> class VMutableArray; /** + * Various tags to disambiguate constructors of virtual arrays. + * Generally it is easier to use `VArray::For*` functions to construct virtual arrays, but + * sometimes being able to use the constructor can result in better performance For example, when + * constructing the virtual array directly in a vector. Without the constructor one would have to + * construct the virtual array first and then move it into the vector. + */ +namespace varray_tag { +struct span { +}; +struct single_ref { +}; +struct single { +}; +} // namespace varray_tag + +/** * A #VArray wraps a virtual array implementation and provides easy access to its elements. It can * be copied and moved. While it is relatively small, it should still be passed by reference if * possible (other than e.g. #Span). @@ -892,6 +908,19 @@ template<typename T> class VArray : public VArrayCommon<T> { { } + VArray(varray_tag::span /* tag */, Span<T> span) + { + /* Cast const away, because the virtual array implementation for const and non const spans is + * shared. */ + MutableSpan<T> mutable_span{const_cast<T *>(span.data()), span.size()}; + this->template emplace<VArrayImpl_For_Span_final<T>>(mutable_span); + } + + VArray(varray_tag::single /* tag */, T value, const int64_t size) + { + this->template emplace<VArrayImpl_For_Single<T>>(std::move(value), size); + } + /** * Construct a new virtual array for a custom #VArrayImpl. */ @@ -908,7 +937,7 @@ template<typename T> class VArray : public VArrayCommon<T> { */ static VArray ForSingle(T value, const int64_t size) { - return VArray::For<VArrayImpl_For_Single<T>>(std::move(value), size); + return VArray(varray_tag::single{}, std::move(value), size); } /** @@ -917,10 +946,7 @@ template<typename T> class VArray : public VArrayCommon<T> { */ static VArray ForSpan(Span<T> values) { - /* Cast const away, because the virtual array implementation for const and non const spans is - * shared. */ - MutableSpan<T> span{const_cast<T *>(values.data()), values.size()}; - return VArray::For<VArrayImpl_For_Span_final<T>>(span); + return VArray(varray_tag::span{}, values); } /** @@ -1112,6 +1138,8 @@ template<typename T> class VArray_Span final : public Span<T> { Array<T> owned_data_; public: + VArray_Span() = default; + VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray)) { this->size_ = varray_.size(); @@ -1125,6 +1153,30 @@ template<typename T> class VArray_Span final : public Span<T> { this->data_ = owned_data_.data(); } } + + VArray_Span(VArray_Span &&other) + : varray_(std::move(other.varray_)), owned_data_(std::move(other.owned_data_)) + { + this->size_ = varray_.size(); + if (varray_.is_span()) { + this->data_ = varray_.get_internal_span().data(); + } + else { + this->data_ = owned_data_.data(); + } + other.data_ = nullptr; + other.size_ = 0; + } + + VArray_Span &operator=(VArray_Span &&other) + { + if (this == &other) { + return *this; + } + std::destroy_at(this); + new (this) VArray_Span(std::move(other)); + return *this; + } }; /** diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 109230ebfa7..95b4987596e 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -445,6 +445,7 @@ if(WITH_GTESTS) tests/BLI_index_range_test.cc tests/BLI_inplace_priority_queue_test.cc tests/BLI_kdopbvh_test.cc + tests/BLI_kdtree_test.cc tests/BLI_length_parameterize_test.cc tests/BLI_linear_allocator_test.cc tests/BLI_linklist_lockfree_test.cc diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc index ece22bcf82e..db6cb0824dc 100644 --- a/source/blender/blenlib/intern/delaunay_2d.cc +++ b/source/blender/blenlib/intern/delaunay_2d.cc @@ -2637,6 +2637,7 @@ void prepare_cdt_for_output(CDT_state<T> *cdt_state, const CDT_output_type outpu remove_faces_in_holes(cdt_state); } else if (output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES) { + remove_outer_edges_until_constraints(cdt_state); remove_non_constraint_edges_leave_valid_bmesh(cdt_state); remove_faces_in_holes(cdt_state); } diff --git a/source/blender/blenlib/intern/generic_virtual_array.cc b/source/blender/blenlib/intern/generic_virtual_array.cc index a3a17952a97..a6fbf4bff5b 100644 --- a/source/blender/blenlib/intern/generic_virtual_array.cc +++ b/source/blender/blenlib/intern/generic_virtual_array.cc @@ -85,11 +85,6 @@ bool GVArrayImpl::may_have_ownership() const /** \name #GVMutableArrayImpl * \{ */ -GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size) - : GVArrayImpl(type, size) -{ -} - void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value) { BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); @@ -141,18 +136,6 @@ bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const /** \name #GVArrayImpl_For_GSpan * \{ */ -GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GMutableSpan span) - : GVMutableArrayImpl(span.type(), span.size()), - data_(span.data()), - element_size_(span.type().size()) -{ -} - -GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size) - : GVMutableArrayImpl(type, size), element_size_(type.size()) -{ -} - void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const { type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value); @@ -209,17 +192,6 @@ void GVArrayImpl_For_GSpan::materialize_compressed_to_uninitialized(const IndexM type_->copy_construct_compressed(data_, dst, mask); } -class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan { - public: - using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan; - - private: - bool may_have_ownership() const override - { - return false; - } -}; - /** \} */ /* -------------------------------------------------------------------- */ @@ -227,79 +199,56 @@ class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan { * \{ */ /* Generic virtual array where each element has the same value. The value is not owned. */ -class GVArrayImpl_For_SingleValueRef : public GVArrayImpl { - protected: - const void *value_ = nullptr; - public: - GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) - : GVArrayImpl(type, size), value_(value) - { - } - - protected: - GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size) - { - } - - void get(const int64_t UNUSED(index), void *r_value) const override - { - type_->copy_assign(value_, r_value); - } - void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override - { - type_->copy_construct(value_, r_value); - } - - bool is_span() const override - { - return size_ == 1; - } - GSpan get_internal_span() const override - { - return GSpan{*type_, value_, 1}; - } - - bool is_single() const override - { - return true; - } - void get_internal_single(void *r_value) const override - { - type_->copy_assign(value_, r_value); - } +void GVArrayImpl_For_SingleValueRef::get(const int64_t UNUSED(index), void *r_value) const +{ + type_->copy_assign(value_, r_value); +} +void GVArrayImpl_For_SingleValueRef::get_to_uninitialized(const int64_t UNUSED(index), + void *r_value) const +{ + type_->copy_construct(value_, r_value); +} - void materialize(const IndexMask mask, void *dst) const override - { - type_->fill_assign_indices(value_, dst, mask); - } +bool GVArrayImpl_For_SingleValueRef::is_span() const +{ + return size_ == 1; +} +GSpan GVArrayImpl_For_SingleValueRef::get_internal_span() const +{ + return GSpan{*type_, value_, 1}; +} - void materialize_to_uninitialized(const IndexMask mask, void *dst) const override - { - type_->fill_construct_indices(value_, dst, mask); - } +bool GVArrayImpl_For_SingleValueRef::is_single() const +{ + return true; +} +void GVArrayImpl_For_SingleValueRef::get_internal_single(void *r_value) const +{ + type_->copy_assign(value_, r_value); +} - void materialize_compressed(const IndexMask mask, void *dst) const override - { - type_->fill_assign_n(value_, dst, mask.size()); - } +void GVArrayImpl_For_SingleValueRef::materialize(const IndexMask mask, void *dst) const +{ + type_->fill_assign_indices(value_, dst, mask); +} - void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override - { - type_->fill_construct_n(value_, dst, mask.size()); - } -}; +void GVArrayImpl_For_SingleValueRef::materialize_to_uninitialized(const IndexMask mask, + void *dst) const +{ + type_->fill_construct_indices(value_, dst, mask); +} -class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef { - public: - using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef; +void GVArrayImpl_For_SingleValueRef::materialize_compressed(const IndexMask mask, void *dst) const +{ + type_->fill_assign_n(value_, dst, mask.size()); +} - private: - bool may_have_ownership() const override - { - return false; - } -}; +void GVArrayImpl_For_SingleValueRef::materialize_compressed_to_uninitialized(const IndexMask mask, + void *dst) const +{ + type_->fill_construct_n(value_, dst, mask.size()); +} /** \} */ @@ -529,8 +478,6 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl { /** \name #GVArrayCommon * \{ */ -GVArrayCommon::GVArrayCommon() = default; - GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_) { impl_ = this->impl_from_storage(); @@ -672,17 +619,27 @@ GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::m { } -GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value) +GVArray::GVArray(varray_tag::single /* tag */, + const CPPType &type, + int64_t size, + const void *value) { if (type.is_trivial() && type.size() <= 16 && type.alignment() <= 8) { - return GVArray::For<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value); + this->emplace<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value); } - return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value); + else { + this->emplace<GVArrayImpl_For_SingleValue>(type, size, value); + } +} + +GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value) +{ + return GVArray(varray_tag::single{}, type, size, value); } GVArray GVArray::ForSingleRef(const CPPType &type, const int64_t size, const void *value) { - return GVArray::For<GVArrayImpl_For_SingleValueRef_final>(type, size, value); + return GVArray(varray_tag::single_ref{}, type, size, value); } GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size) @@ -692,10 +649,7 @@ GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size) GVArray GVArray::ForSpan(GSpan span) { - /* Use const-cast because the underlying virtual array implementation is shared between const - * and non const data. */ - GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()}; - return GVArray::For<GVArrayImpl_For_GSpan_final>(mutable_span); + return GVArray(varray_tag::span{}, span); } class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan { diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c index 9da8c0a0941..d57f859eb1b 100644 --- a/source/blender/blenlib/intern/hash_md5.c +++ b/source/blender/blenlib/intern/hash_md5.c @@ -143,7 +143,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct (void)0 /* Before we start, one word to the strange constants. They are defined in RFC 1321 as: - * T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + * `T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64` */ /* Round 1. */ @@ -315,7 +315,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock) break; } - /* Process buffer with BLOCKSIZE bytes. Note that BLOCKSIZE % 64 == 0. */ + /* Process buffer with BLOCKSIZE bytes. Note that `BLOCKSIZE % 64 == 0`. */ md5_process_block(buffer, BLOCKSIZE, &ctx); } @@ -323,7 +323,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock) * 'fillbuf' contains the needed bits. */ memcpy(&buffer[sum], fillbuf, 64); - /* Compute amount of padding bytes needed. Alignment is done to (N + PAD) % 64 == 56. + /* Compute amount of padding bytes needed. Alignment is done to `(N + PAD) % 64 == 56`. * There is always at least one byte padded, i.e. if the alignment is correctly aligned, * 64 padding bytes are added. */ diff --git a/source/blender/blenlib/intern/index_mask.cc b/source/blender/blenlib/intern/index_mask.cc index 1e301bc5fb9..f3590e4a41c 100644 --- a/source/blender/blenlib/intern/index_mask.cc +++ b/source/blender/blenlib/intern/index_mask.cc @@ -128,7 +128,9 @@ Vector<IndexRange> IndexMask::extract_ranges_invert(const IndexRange full_range, } // namespace blender -namespace blender::index_mask_ops::detail { +namespace blender::index_mask_ops { + +namespace detail { IndexMask find_indices_based_on_predicate__merge( IndexMask indices_to_check, @@ -193,4 +195,47 @@ IndexMask find_indices_based_on_predicate__merge( return r_indices.as_span(); } -} // namespace blender::index_mask_ops::detail +} // namespace detail + +IndexMask find_indices_from_virtual_array(const IndexMask indices_to_check, + const VArray<bool> &virtual_array, + const int64_t parallel_grain_size, + Vector<int64_t> &r_indices) +{ + if (virtual_array.is_single()) { + return virtual_array.get_internal_single() ? indices_to_check : IndexMask(0); + } + if (virtual_array.is_span()) { + const Span<bool> span = virtual_array.get_internal_span(); + return find_indices_based_on_predicate( + indices_to_check, 4096, r_indices, [&](const int64_t i) { return span[i]; }); + } + + threading::EnumerableThreadSpecific<Vector<bool>> materialize_buffers; + threading::EnumerableThreadSpecific<Vector<Vector<int64_t>>> sub_masks; + + threading::parallel_for( + indices_to_check.index_range(), parallel_grain_size, [&](const IndexRange range) { + const IndexMask sliced_mask = indices_to_check.slice(range); + + /* To avoid virtual function call overhead from accessing the virtual array, + * materialize the necessary indices for this chunk into a reused buffer. */ + Vector<bool> &buffer = materialize_buffers.local(); + buffer.reinitialize(sliced_mask.size()); + virtual_array.materialize_compressed(sliced_mask, buffer); + + Vector<int64_t> masked_indices; + sliced_mask.to_best_mask_type([&](auto best_mask) { + for (const int64_t i : IndexRange(best_mask.size())) { + if (buffer[i]) { + masked_indices.append(best_mask[i]); + } + } + }); + sub_masks.local().append(std::move(masked_indices)); + }); + + return detail::find_indices_based_on_predicate__merge(indices_to_check, sub_masks, r_indices); +} + +} // namespace blender::index_mask_ops diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h index d9ae826093c..6614f1bf964 100644 --- a/source/blender/blenlib/intern/kdtree_impl.h +++ b/source/blender/blenlib/intern/kdtree_impl.h @@ -927,6 +927,14 @@ int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree, /** \name BLI_kdtree_3d_deduplicate * \{ */ +static int kdtree_cmp_bool(const bool a, const bool b) +{ + if (a == b) { + return 0; + } + return b ? -1 : 1; +} + static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p) { const KDTreeNode *n0 = n0_p; @@ -939,17 +947,16 @@ static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p) return 1; } } - /* Sort by pointer so the first added will be used. - * assignment below ignores const correctness, - * however the values aren't used for sorting and are to be discarded. */ - if (n0 < n1) { - ((KDTreeNode *)n1)->d = KD_DIMS; /* tag invalid */ - return -1; - } - else { - ((KDTreeNode *)n0)->d = KD_DIMS; /* tag invalid */ - return 1; + + if (n0->d != KD_DIMS && n1->d != KD_DIMS) { + /* Two nodes share identical `co` + * Both are still valid. + * Cast away `const` and tag one of them as invalid. */ + ((KDTreeNode *)n1)->d = KD_DIMS; } + + /* Keep sorting until each unique value has one and only one valid node. */ + return kdtree_cmp_bool(n0->d == KD_DIMS, n1->d == KD_DIMS); } /** diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index a983821f15e..4a213f5fe74 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -767,6 +767,20 @@ MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg) return _mm_mul_ps(x, _mm_mul_ps(x, x)); } +MALWAYS_INLINE __m128 _bli_math_rsqrt(__m128 in) +{ + __m128 r = _mm_rsqrt_ps(in); + /* Only do additional Newton-Raphson iterations when using actual SSE + * code path. When we are emulating SSE on NEON via sse2neon, the + * additional NR iterations are already done inside _mm_rsqrt_ps + * emulation. */ +# if defined(__SSE2__) + r = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r), + _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(in, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r))); +# endif + return r; +} + /* Calculate powf(x, 1.0f / 2.4) */ MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg) { @@ -776,14 +790,14 @@ MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg) */ __m128 xf = _bli_math_fastpow(0x3f2aaaab, 0x5eb504f3, arg); __m128 xover = _mm_mul_ps(arg, xf); - __m128 xfm1 = _mm_rsqrt_ps(xf); + __m128 xfm1 = _bli_math_rsqrt(xf); __m128 x2 = _mm_mul_ps(arg, arg); __m128 xunder = _mm_mul_ps(x2, xfm1); /* sqrt2 * over + 2 * sqrt2 * under */ __m128 xavg = _mm_mul_ps(_mm_set1_ps(1.0f / (3.0f * 0.629960524947437f) * 0.999852f), _mm_add_ps(xover, xunder)); - xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg)); - xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg)); + xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg)); + xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg)); return xavg; } diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c index 2352d687061..b5650410a70 100644 --- a/source/blender/blenlib/intern/math_solvers.c +++ b/source/blender/blenlib/intern/math_solvers.c @@ -99,8 +99,8 @@ bool BLI_tridiagonal_solve_cyclic( /* Degenerate case that works but can be simplified. */ if (count == 2) { - float a2[2] = {0, a[1] + c[1]}; - float c2[2] = {a[0] + c[0], 0}; + const float a2[2] = {0, a[1] + c[1]}; + const float c2[2] = {a[0] + c[0], 0}; return BLI_tridiagonal_solve(a2, b, c2, d, r_x, count); } diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 94efb0dd9e7..0cbf62cce03 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -363,6 +363,10 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w, int BLI_wcwidth(char32_t ucs) { + /* Treat private use areas (icon fonts), symbols, and emoticons as double-width. */ + if (ucs >= 0xf0000 || (ucs >= 0xe000 && ucs < 0xf8ff) || (ucs >= 0x1f300 && ucs < 0x1fbff)) { + return 2; + } return mk_wcwidth(ucs); } diff --git a/source/blender/blenlib/tests/BLI_bounds_test.cc b/source/blender/blenlib/tests/BLI_bounds_test.cc index 9c123d4705c..5aa4e710e90 100644 --- a/source/blender/blenlib/tests/BLI_bounds_test.cc +++ b/source/blender/blenlib/tests/BLI_bounds_test.cc @@ -33,6 +33,13 @@ TEST(bounds, MinMaxFloat) EXPECT_EQ(result->max, 3.0f); } +TEST(bounds, MinGreaterThanZero) +{ + Array<float> data = {1.5f, 3.0f, 1.1f, 100.0f}; + auto result = bounds::min_max(data.as_span()); + EXPECT_GT(result->min, 1.0f); +} + TEST(bounds, MinMaxRadii) { Array<int2> data = {int2(0, 1), int2(3, -1), int2(0, -2), int2(-1, 1)}; diff --git a/source/blender/blenlib/tests/BLI_kdtree_test.cc b/source/blender/blenlib/tests/BLI_kdtree_test.cc new file mode 100644 index 00000000000..d040ea15172 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_kdtree_test.cc @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "BLI_kdtree.h" + +#include <cmath> + +/* -------------------------------------------------------------------- */ +/* Tests */ + +static void standard_test() +{ + for (int tree_size = 30; tree_size < 500; tree_size++) { + int tree_index = 0; + KDTree_1d *tree = BLI_kdtree_1d_new(tree_size); + int mask = tree_size & 31; + bool occupied[32] = {false}; + + for (int i = 0; i < tree_size; i++) { + int index = i & mask; + occupied[index] = true; + float value = fmodf(index * 7.121f, 0.6037f); /* Co-prime. */ + float key[1] = {value}; + BLI_kdtree_1d_insert(tree, tree_index++, key); + } + int expected = 0; + for (int j = 0; j < 32; j++) { + if (occupied[j]) { + expected++; + } + } + + int dedup_count = BLI_kdtree_1d_deduplicate(tree); + EXPECT_EQ(dedup_count, expected); + BLI_kdtree_1d_free(tree); + } +} + +static void deduplicate_test() +{ + for (int tree_size = 1; tree_size < 40; tree_size++) { + int tree_index = 0; + KDTree_1d *tree = BLI_kdtree_1d_new(tree_size); + for (int i = 0; i < tree_size; i++) { + float key[1] = {1.0f}; + BLI_kdtree_1d_insert(tree, tree_index++, key); + } + int dedup_count = BLI_kdtree_1d_deduplicate(tree); + EXPECT_EQ(dedup_count, 1); + BLI_kdtree_1d_free(tree); + } +} + +TEST(kdtree, Standard) +{ + standard_test(); +} + +TEST(kdtree, Deduplicate) +{ + deduplicate_test(); +} diff --git a/source/blender/blenlib/tests/BLI_math_color_test.cc b/source/blender/blenlib/tests/BLI_math_color_test.cc index 7f2c0a3f1ca..4d928477870 100644 --- a/source/blender/blenlib/tests/BLI_math_color_test.cc +++ b/source/blender/blenlib/tests/BLI_math_color_test.cc @@ -74,3 +74,71 @@ TEST(math_color, LinearRGBTosRGBRoundtrip) EXPECT_NEAR(orig_linear_color, linear_color, 1e-5); } } + +TEST(math_color, linearrgb_to_srgb_v3_v3) +{ + float srgb_color[3]; + { + const float kTolerance = 1.0e-8f; + const float linear_color[3] = {0.0023f, 0.0024f, 0.0025f}; + linearrgb_to_srgb_v3_v3(srgb_color, linear_color); + EXPECT_NEAR(0.029716f, srgb_color[0], kTolerance); + EXPECT_NEAR(0.031008f, srgb_color[1], kTolerance); + EXPECT_NEAR(0.032300f, srgb_color[2], kTolerance); + } + + { + /* SIMD implementation of linear->srgb for larger inputs + * is less accurate; use larger tolerance. */ + const float kTolerance = 3.6e-5f; + const float linear_color[3] = {0.71f, 0.75f, 0.78f}; + linearrgb_to_srgb_v3_v3(srgb_color, linear_color); + EXPECT_NEAR(0.859696f, srgb_color[0], kTolerance); + EXPECT_NEAR(0.880825f, srgb_color[1], kTolerance); + EXPECT_NEAR(0.896244f, srgb_color[2], kTolerance); + } + + { + /* Not a common, but possible case: values beyond 1.0 range. */ + const float kTolerance = 2.3e-4f; + const float linear_color[3] = {1.5f, 2.8f, 5.6f}; + linearrgb_to_srgb_v3_v3(srgb_color, linear_color); + EXPECT_NEAR(1.19418f, srgb_color[0], kTolerance); + EXPECT_NEAR(1.56520f, srgb_color[1], kTolerance); + EXPECT_NEAR(2.10771f, srgb_color[2], kTolerance); + } +} + +TEST(math_color, srgb_to_linearrgb_v3_v3) +{ + float linear_color[3]; + { + const float kTolerance = 1.0e-8f; + const float srgb_color[3] = {0.0023f, 0.0024f, 0.0025f}; + srgb_to_linearrgb_v3_v3(linear_color, srgb_color); + EXPECT_NEAR(0.000178019f, linear_color[0], kTolerance); + EXPECT_NEAR(0.000185759f, linear_color[1], kTolerance); + EXPECT_NEAR(0.000193498f, linear_color[2], kTolerance); + } + + { + /* SIMD implementation of linear->srgb for larger inputs + * is less accurate; use larger tolerance. */ + const float kTolerance = 1.5e-7f; + const float srgb_color[3] = {0.71f, 0.72f, 0.73f}; + srgb_to_linearrgb_v3_v3(linear_color, srgb_color); + EXPECT_NEAR(0.4623615f, linear_color[0], kTolerance); + EXPECT_NEAR(0.4770000f, linear_color[1], kTolerance); + EXPECT_NEAR(0.4919052f, linear_color[2], kTolerance); + } + + { + /* Not a common, but possible case: values beyond 1.0 range. */ + const float kTolerance = 7.7e-6f; + const float srgb_color[3] = {1.1f, 2.5f, 5.6f}; + srgb_to_linearrgb_v3_v3(linear_color, srgb_color); + EXPECT_NEAR(1.24277f, linear_color[0], kTolerance); + EXPECT_NEAR(8.35473f, linear_color[1], kTolerance); + EXPECT_NEAR(56.23833f, linear_color[2], kTolerance); + } +} diff --git a/source/blender/blenlib/tests/BLI_math_vector_test.cc b/source/blender/blenlib/tests/BLI_math_vector_test.cc index 282be5f1963..5686be975b5 100644 --- a/source/blender/blenlib/tests/BLI_math_vector_test.cc +++ b/source/blender/blenlib/tests/BLI_math_vector_test.cc @@ -105,4 +105,24 @@ TEST(math_vector, InterpolateFloat) EXPECT_FLOAT_EQ(result.z, 75.0f); } +TEST(math_vector, CeilToMultiple) +{ + const int3 a(21, 16, 0); + const int3 b(8, 16, 15); + const int3 result = math::ceil_to_multiple(a, b); + EXPECT_FLOAT_EQ(result.x, 24); + EXPECT_FLOAT_EQ(result.y, 16); + EXPECT_FLOAT_EQ(result.z, 0); +} + +TEST(math_vector, DivideCeil) +{ + const int3 a(21, 16, 0); + const int3 b(8, 16, 15); + const int3 result = math::divide_ceil(a, b); + EXPECT_FLOAT_EQ(result.x, 3); + EXPECT_FLOAT_EQ(result.y, 1); + EXPECT_FLOAT_EQ(result.z, 0); +} + } // namespace blender::tests diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index eeec55a7b06..e542bc46a28 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1569,8 +1569,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) { /* Replace Multiply and Additive blend mode by Alpha Blend - * now that we use dualsource blending. */ - /* We take care of doing only nodetrees that are always part of materials + * now that we use dual-source blending. */ + /* We take care of doing only node-trees that are always part of materials * with old blending modes. */ for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) { bNodeTree *ntree = ma->nodetree; @@ -4102,7 +4102,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) LISTBASE_FOREACH (Object *, ob, &bmain->objects) { LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { if (md->type == eModifierType_DataTransfer) { - /* Now datatransfer's mix factor is multiplied with weights when any, + /* Now data-transfer's mix factor is multiplied with weights when any, * instead of being ignored, * we need to take care of that to keep 'old' files compatible. */ DataTransferModifierData *dtmd = (DataTransferModifierData *)md; diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 585ada3b2d8..a15ddc75aa2 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -347,8 +347,9 @@ static void seq_convert_transform_crop_lb_2(const Scene *scene, } } -static void seq_update_meta_disp_range(Editing *ed) +static void seq_update_meta_disp_range(Scene *scene) { + Editing *ed = SEQ_editing_get(scene); if (ed == NULL) { return; } @@ -356,21 +357,14 @@ static void seq_update_meta_disp_range(Editing *ed) LISTBASE_FOREACH_BACKWARD (MetaStack *, ms, &ed->metastack) { /* Update ms->disp_range from meta. */ if (ms->disp_range[0] == ms->disp_range[1]) { - copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp); + ms->disp_range[0] = SEQ_time_left_handle_frame_get(ms->parseq); + ms->disp_range[1] = SEQ_time_right_handle_frame_get(ms->parseq); } /* Update meta strip endpoints. */ - SEQ_time_left_handle_frame_set(ms->parseq, ms->disp_range[0]); - SEQ_time_right_handle_frame_set(ms->parseq, ms->disp_range[1]); - SEQ_transform_fix_single_image_seq_offsets(ms->parseq); - - /* Recalculate effects using meta strip. */ - LISTBASE_FOREACH (Sequence *, seq, ms->oldbasep) { - if (seq->seq2) { - seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp); - seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp); - } - } + SEQ_time_left_handle_frame_set(scene, ms->parseq, ms->disp_range[0]); + SEQ_time_right_handle_frame_set(scene, ms->parseq, ms->disp_range[1]); + SEQ_transform_fix_single_image_seq_offsets(scene, ms->parseq); /* Ensure that active seqbase points to active meta strip seqbase. */ MetaStack *active_ms = SEQ_meta_stack_active_get(ed); @@ -647,7 +641,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) if (!MAIN_VERSION_ATLEAST(bmain, 293, 16)) { LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - seq_update_meta_disp_range(SEQ_editing_get(scene)); + seq_update_meta_disp_range(scene); } /* Add a separate socket for Grid node X and Y size. */ @@ -1446,7 +1440,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) view_layer->eevee.render_passes &= ~EEVEE_RENDER_PASS_UNUSED_8; } - /* Rename Renderlayer Socket `VolumeScatterCol` to `VolumeDir` */ + /* Rename Render-layer Socket `VolumeScatterCol` to `VolumeDir`. */ if (scene->nodetree) { LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) { if (node->type == CMP_NODE_R_LAYERS) { diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index b0a8fa7e24a..80a8e9b7fd4 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -25,10 +25,12 @@ #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" +#include "DNA_curves_types.h" #include "DNA_genfile.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_lineart_types.h" #include "DNA_listBase.h" +#include "DNA_mask_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -45,6 +47,7 @@ #include "BKE_asset.h" #include "BKE_attribute.h" #include "BKE_collection.h" +#include "BKE_colortools.h" #include "BKE_curve.h" #include "BKE_data_transfer.h" #include "BKE_deform.h" @@ -406,7 +409,9 @@ static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const Lis v->speed_control_type = SEQ_SPEED_MULTIPLY; v->speed_fader = globalSpeed * ((float)seq->seq1->len / - max_ff((float)(seq->seq1->enddisp - seq->seq1->start), 1.0f)); + max_ff((float)(SEQ_time_right_handle_frame_get(seq->seq1) - + seq->seq1->start), + 1.0f)); } } else if (v->flags & SEQ_SPEED_INTEGRATE) { @@ -999,6 +1004,9 @@ static void do_version_subsurface_methods(bNode *node) static void version_geometry_nodes_add_attribute_input_settings(NodesModifierData *nmd) { + if (nmd->settings.properties == NULL) { + return; + } /* Before versioning the properties, make sure it hasn't been done already. */ LISTBASE_FOREACH (const IDProperty *, property, &nmd->settings.properties->data.group) { if (strstr(property->name, "_use_attribute") || strstr(property->name, "_attribute_name")) { @@ -1370,6 +1378,275 @@ static void version_liboverride_rnacollections_insertion_animdata(ID *id) } } +static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTree *ntree) +{ + /* In geometry nodes, replace shader combine/separate color nodes with function nodes */ + if (ntree->type == NTREE_GEOMETRY) { + version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red"); + version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green"); + version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue"); + version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color"); + + version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red"); + version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green"); + version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue"); + version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color"); + + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + switch (node->type) { + case SH_NODE_COMBRGB_LEGACY: { + node->type = FN_NODE_COMBINE_COLOR; + NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), + __func__); + storage->mode = NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "FunctionNodeCombineColor"); + node->storage = storage; + break; + } + case SH_NODE_SEPRGB_LEGACY: { + node->type = FN_NODE_SEPARATE_COLOR; + NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), + __func__); + storage->mode = NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "FunctionNodeSeparateColor"); + node->storage = storage; + break; + } + } + } + } + + /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with + * combine/separate color */ + if (ntree->type == NTREE_COMPOSIT) { + version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red"); + version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green"); + version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue"); + version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha"); + + version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red"); + version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green"); + version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue"); + version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha"); + + version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red"); + version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green"); + version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue"); + version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha"); + + version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red"); + version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green"); + version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue"); + version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha"); + + version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red"); + version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green"); + version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue"); + version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha"); + + version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red"); + version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green"); + version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue"); + version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha"); + + version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red"); + version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green"); + version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue"); + version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha"); + + version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red"); + version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green"); + version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue"); + version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha"); + + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + switch (node->type) { + case CMP_NODE_COMBRGBA_LEGACY: { + node->type = CMP_NODE_COMBINE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "CompositorNodeCombineColor"); + node->storage = storage; + break; + } + case CMP_NODE_COMBHSVA_LEGACY: { + node->type = CMP_NODE_COMBINE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_HSV; + strcpy(node->idname, "CompositorNodeCombineColor"); + node->storage = storage; + break; + } + case CMP_NODE_COMBYCCA_LEGACY: { + node->type = CMP_NODE_COMBINE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_YCC; + storage->ycc_mode = node->custom1; + strcpy(node->idname, "CompositorNodeCombineColor"); + node->storage = storage; + break; + } + case CMP_NODE_COMBYUVA_LEGACY: { + node->type = CMP_NODE_COMBINE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_YUV; + strcpy(node->idname, "CompositorNodeCombineColor"); + node->storage = storage; + break; + } + case CMP_NODE_SEPRGBA_LEGACY: { + node->type = CMP_NODE_SEPARATE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "CompositorNodeSeparateColor"); + node->storage = storage; + break; + } + case CMP_NODE_SEPHSVA_LEGACY: { + node->type = CMP_NODE_SEPARATE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_HSV; + strcpy(node->idname, "CompositorNodeSeparateColor"); + node->storage = storage; + break; + } + case CMP_NODE_SEPYCCA_LEGACY: { + node->type = CMP_NODE_SEPARATE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_YCC; + storage->ycc_mode = node->custom1; + strcpy(node->idname, "CompositorNodeSeparateColor"); + node->storage = storage; + break; + } + case CMP_NODE_SEPYUVA_LEGACY: { + node->type = CMP_NODE_SEPARATE_COLOR; + NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( + sizeof(NodeCMPCombSepColor), __func__); + storage->mode = CMP_NODE_COMBSEP_COLOR_YUV; + strcpy(node->idname, "CompositorNodeSeparateColor"); + node->storage = storage; + break; + } + } + } + } + + /* In texture nodes, replace combine/separate RGBA with combine/separate color */ + if (ntree->type == NTREE_TEXTURE) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + switch (node->type) { + case TEX_NODE_COMPOSE_LEGACY: { + node->type = TEX_NODE_COMBINE_COLOR; + node->custom1 = NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "TextureNodeCombineColor"); + break; + } + case TEX_NODE_DECOMPOSE_LEGACY: { + node->type = TEX_NODE_SEPARATE_COLOR; + node->custom1 = NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "TextureNodeSeparateColor"); + break; + } + } + } + } + + /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */ + if (ntree->type == NTREE_SHADER) { + version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red"); + version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green"); + version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue"); + version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color"); + + version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red"); + version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green"); + version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue"); + + version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red"); + version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green"); + version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue"); + version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color"); + + version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red"); + version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green"); + version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue"); + + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + switch (node->type) { + case SH_NODE_COMBRGB_LEGACY: { + node->type = SH_NODE_COMBINE_COLOR; + NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), + __func__); + storage->mode = NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "ShaderNodeCombineColor"); + node->storage = storage; + break; + } + case SH_NODE_COMBHSV_LEGACY: { + node->type = SH_NODE_COMBINE_COLOR; + NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), + __func__); + storage->mode = NODE_COMBSEP_COLOR_HSV; + strcpy(node->idname, "ShaderNodeCombineColor"); + node->storage = storage; + break; + } + case SH_NODE_SEPRGB_LEGACY: { + node->type = SH_NODE_SEPARATE_COLOR; + NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), + __func__); + storage->mode = NODE_COMBSEP_COLOR_RGB; + strcpy(node->idname, "ShaderNodeSeparateColor"); + node->storage = storage; + break; + } + case SH_NODE_SEPHSV_LEGACY: { + node->type = SH_NODE_SEPARATE_COLOR; + NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), + __func__); + storage->mode = NODE_COMBSEP_COLOR_HSV; + strcpy(node->idname, "ShaderNodeSeparateColor"); + node->storage = storage; + break; + } + } + } + } +} + +static void version_fix_image_format_copy(Main *bmain, ImageFormatData *format) +{ + /* Fix bug where curves in image format were not properly copied to file output + * node, incorrectly sharing a pointer with the scene settings. Copy the data + * structure now as it should have been done in the first place. */ + if (format->view_settings.curve_mapping) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (format != &scene->r.im_format && ELEM(format->view_settings.curve_mapping, + scene->view_settings.curve_mapping, + scene->r.im_format.view_settings.curve_mapping)) { + format->view_settings.curve_mapping = BKE_curvemapping_copy( + format->view_settings.curve_mapping); + break; + } + } + + /* Remove any invalid curves with missing data. */ + if (format->view_settings.curve_mapping->cm[0].curve == NULL) { + BKE_curvemapping_free(format->view_settings.curve_mapping); + format->view_settings.curve_mapping = NULL; + format->view_settings.flag &= ~COLORMANAGE_VIEW_USE_CURVES; + } + } +} + /* NOLINTNEXTLINE: readability-function-size */ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) { @@ -2488,8 +2765,8 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) /* Rebuild active/render color attribute references. */ if (!MAIN_VERSION_ATLEAST(bmain, 302, 6)) { LISTBASE_FOREACH (Brush *, br, &bmain->brushes) { - /* buggy code in wm_toolsystem broke smear in old files, - reset to defaults */ + /* Buggy code in wm_toolsystem broke smear in old files, + * reset to defaults. */ if (br->sculpt_tool == SCULPT_TOOL_SMEAR) { br->alpha = 1.0f; br->spacing = 5; @@ -2777,275 +3054,106 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } if (!MAIN_VERSION_ATLEAST(bmain, 303, 1)) { - /* Move mesh bevel weights from structs to dedicated custom data layers, like edit mode. */ - LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) { - if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) { - float *weights = (float *)CustomData_add_layer( - &mesh->edata, CD_BWEIGHT, CD_DEFAULT, NULL, mesh->totedge); - for (int i = 0; i < mesh->totedge; i++) { - weights[i] = mesh->medge[i].bweight / 255.0f; - } + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + versioning_replace_legacy_combined_and_separate_color_nodes(ntree); + } + FOREACH_NODETREE_END; + + /* Initialize brush curves sculpt settings. */ + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + if (brush->ob_mode != OB_MODE_SCULPT_CURVES) { + continue; } - if (mesh->cd_flag & ME_CDFLAG_VERT_BWEIGHT) { - float *weights = (float *)CustomData_add_layer( - &mesh->vdata, CD_BWEIGHT, CD_DEFAULT, NULL, mesh->totvert); - for (int i = 0; i < mesh->totvert; i++) { - weights[i] = mesh->mvert[i].bweight / 255.0f; + if (brush->curves_sculpt_settings->points_per_curve == 0) { + brush->curves_sculpt_settings->points_per_curve = 8; + } + } + + /* UDIM Packing. */ + if (!DNA_struct_elem_find(fd->filesdna, "ImagePackedFile", "int", "tile_number")) { + for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { + int view; + LISTBASE_FOREACH_INDEX (ImagePackedFile *, imapf, &ima->packedfiles, view) { + imapf->view = view; + imapf->tile_number = 1001; } } } - } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #blo_do_versions_userdef - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ + /* Merge still offsets into start/end offsets. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + Editing *ed = SEQ_editing_get(scene); + if (ed != NULL) { + SEQ_for_each_callback(&ed->seqbase, version_merge_still_offsets, NULL); + } + } - /* Replace legacy combine/separate color nodes */ + /* Use the curves type enum for the set spline type node, instead of a special one. */ FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - /* In geometry nodes, replace shader combine/separate color nodes with function nodes */ if (ntree->type == NTREE_GEOMETRY) { - version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red"); - version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green"); - version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue"); - version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color"); - - version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red"); - version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green"); - version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue"); - version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color"); - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - switch (node->type) { - case SH_NODE_COMBRGB_LEGACY: { - node->type = FN_NODE_COMBINE_COLOR; - NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), - __func__); - storage->mode = NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "FunctionNodeCombineColor"); - node->storage = storage; - break; - } - case SH_NODE_SEPRGB_LEGACY: { - node->type = FN_NODE_SEPARATE_COLOR; - NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), - __func__); - storage->mode = NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "FunctionNodeSeparateColor"); - node->storage = storage; - break; + if (node->type == GEO_NODE_CURVE_SPLINE_TYPE) { + NodeGeometryCurveSplineType *storage = (NodeGeometryCurveSplineType *)node->storage; + switch (storage->spline_type) { + case 0: /* GEO_NODE_SPLINE_TYPE_BEZIER */ + storage->spline_type = CURVE_TYPE_BEZIER; + break; + case 1: /* GEO_NODE_SPLINE_TYPE_NURBS */ + storage->spline_type = CURVE_TYPE_NURBS; + break; + case 2: /* GEO_NODE_SPLINE_TYPE_POLY */ + storage->spline_type = CURVE_TYPE_POLY; + break; } } } } + } + FOREACH_NODETREE_END; + } - /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with - * combine/separate color */ - if (ntree->type == NTREE_COMPOSIT) { - version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red"); - version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green"); - version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue"); - version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha"); - - version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red"); - version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green"); - version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue"); - version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha"); - - version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red"); - version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green"); - version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue"); - version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha"); - - version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red"); - version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green"); - version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue"); - version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha"); - - version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red"); - version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green"); - version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue"); - version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha"); - - version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red"); - version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green"); - version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue"); - version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha"); - - version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red"); - version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green"); - version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue"); - version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha"); - - version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red"); - version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green"); - version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue"); - version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha"); - - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - switch (node->type) { - case CMP_NODE_COMBRGBA_LEGACY: { - node->type = CMP_NODE_COMBINE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "CompositorNodeCombineColor"); - node->storage = storage; - break; - } - case CMP_NODE_COMBHSVA_LEGACY: { - node->type = CMP_NODE_COMBINE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_HSV; - strcpy(node->idname, "CompositorNodeCombineColor"); - node->storage = storage; - break; - } - case CMP_NODE_COMBYCCA_LEGACY: { - node->type = CMP_NODE_COMBINE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_YCC; - storage->ycc_mode = node->custom1; - strcpy(node->idname, "CompositorNodeCombineColor"); - node->storage = storage; - break; - } - case CMP_NODE_COMBYUVA_LEGACY: { - node->type = CMP_NODE_COMBINE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_YUV; - strcpy(node->idname, "CompositorNodeCombineColor"); - node->storage = storage; - break; - } - case CMP_NODE_SEPRGBA_LEGACY: { - node->type = CMP_NODE_SEPARATE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "CompositorNodeSeparateColor"); - node->storage = storage; - break; - } - case CMP_NODE_SEPHSVA_LEGACY: { - node->type = CMP_NODE_SEPARATE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_HSV; - strcpy(node->idname, "CompositorNodeSeparateColor"); - node->storage = storage; - break; - } - case CMP_NODE_SEPYCCA_LEGACY: { - node->type = CMP_NODE_SEPARATE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_YCC; - storage->ycc_mode = node->custom1; - strcpy(node->idname, "CompositorNodeSeparateColor"); - node->storage = storage; - break; - } - case CMP_NODE_SEPYUVA_LEGACY: { - node->type = CMP_NODE_SEPARATE_COLOR; - NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN( - sizeof(NodeCMPCombSepColor), __func__); - storage->mode = CMP_NODE_COMBSEP_COLOR_YUV; - strcpy(node->idname, "CompositorNodeSeparateColor"); - node->storage = storage; - break; - } + if (!MAIN_VERSION_ATLEAST(bmain, 303, 2)) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_CLIP) { + ((SpaceClip *)sl)->mask_info.blend_factor = 1.0; } } } + } + } - /* In texture nodes, replace combine/separate RGBA with combine/separate color */ - if (ntree->type == NTREE_TEXTURE) { - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - switch (node->type) { - case TEX_NODE_COMPOSE_LEGACY: { - node->type = TEX_NODE_COMBINE_COLOR; - node->custom1 = NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "TextureNodeCombineColor"); - break; - } - case TEX_NODE_DECOMPOSE_LEGACY: { - node->type = TEX_NODE_SEPARATE_COLOR; - node->custom1 = NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "TextureNodeSeparateColor"); - break; - } + if (!MAIN_VERSION_ATLEAST(bmain, 303, 3)) { + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_CLIP) { + ((SpaceClip *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE; + } + else if (sl->spacetype == SPACE_IMAGE) { + ((SpaceImage *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE; } } } + } + } - /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */ - if (ntree->type == NTREE_SHADER) { - version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red"); - version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green"); - version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue"); - version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color"); - - version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red"); - version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green"); - version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue"); - - version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red"); - version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green"); - version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue"); - version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color"); - - version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red"); - version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green"); - version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue"); - + if (!MAIN_VERSION_ATLEAST(bmain, 303, 4)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - switch (node->type) { - case SH_NODE_COMBRGB_LEGACY: { - node->type = SH_NODE_COMBINE_COLOR; - NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), - __func__); - storage->mode = NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "ShaderNodeCombineColor"); - node->storage = storage; - break; - } - case SH_NODE_COMBHSV_LEGACY: { - node->type = SH_NODE_COMBINE_COLOR; - NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), - __func__); - storage->mode = NODE_COMBSEP_COLOR_HSV; - strcpy(node->idname, "ShaderNodeCombineColor"); - node->storage = storage; - break; - } - case SH_NODE_SEPRGB_LEGACY: { - node->type = SH_NODE_SEPARATE_COLOR; - NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), - __func__); - storage->mode = NODE_COMBSEP_COLOR_RGB; - strcpy(node->idname, "ShaderNodeSeparateColor"); - node->storage = storage; - break; + if (node->type == CMP_NODE_OUTPUT_FILE) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + if (sock->storage) { + NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; + version_fix_image_format_copy(bmain, &sockdata->format); + } } - case SH_NODE_SEPHSV_LEGACY: { - node->type = SH_NODE_SEPARATE_COLOR; - NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor), - __func__); - storage->mode = NODE_COMBSEP_COLOR_HSV; - strcpy(node->idname, "ShaderNodeSeparateColor"); - node->storage = storage; - break; + + if (node->storage) { + NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; + version_fix_image_format_copy(bmain, &nimf->format); } } } @@ -3053,33 +3161,41 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } FOREACH_NODETREE_END; - /* Initialize brush curves sculpt settings. */ - LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { - if (brush->ob_mode != OB_MODE_SCULPT_CURVES) { - continue; - } - if (brush->curves_sculpt_settings->points_per_curve == 0) { - brush->curves_sculpt_settings->points_per_curve = 8; - } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + version_fix_image_format_copy(bmain, &scene->r.im_format); } + } - /* UDIM Packing. */ - if (!DNA_struct_elem_find(fd->filesdna, "ImagePackedFile", "int", "tile_number")) { - for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { - int view; - LISTBASE_FOREACH_INDEX (ImagePackedFile *, imapf, &ima->packedfiles, view) { - imapf->view = view; - imapf->tile_number = 1001; + if (!MAIN_VERSION_ATLEAST(bmain, 303, 1)) { + /* Move mesh bevel weights from structs to dedicated custom data layers, like edit mode. */ + LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) { + if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) { + float *weights = (float *)CustomData_add_layer( + &mesh->edata, CD_BWEIGHT, CD_DEFAULT, NULL, mesh->totedge); + for (int i = 0; i < mesh->totedge; i++) { + weights[i] = mesh->medge[i].bweight / 255.0f; } } - } - - /* Merge still offsets into start/end offsets. */ - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - Editing *ed = SEQ_editing_get(scene); - if (ed != NULL) { - SEQ_for_each_callback(&ed->seqbase, version_merge_still_offsets, NULL); + if (mesh->cd_flag & ME_CDFLAG_VERT_BWEIGHT) { + float *weights = (float *)CustomData_add_layer( + &mesh->vdata, CD_BWEIGHT, CD_DEFAULT, NULL, mesh->totvert); + for (int i = 0; i < mesh->totvert; i++) { + weights[i] = mesh->mvert[i].bweight / 255.0f; + } } } } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #blo_do_versions_userdef + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index f65976ee55f..6ce53e4a648 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -23,6 +23,7 @@ #include "DNA_curveprofile_types.h" #include "DNA_gpencil_types.h" #include "DNA_light_types.h" +#include "DNA_mask_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -184,6 +185,8 @@ static void blo_update_defaults_screen(bScreen *screen, else if (area->spacetype == SPACE_CLIP) { SpaceClip *sclip = area->spacedata.first; sclip->around = V3D_AROUND_CENTER_MEDIAN; + sclip->mask_info.blend_factor = 0.7f; + sclip->mask_info.draw_flag = MASK_DRAWFLAG_SPLINE; } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index b3f3b9cbf7d..40359500d3c 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -347,6 +347,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) */ { /* Keep this block, even when empty. */ + btheme->tui.wcol_view_item = U_theme_default.tui.wcol_view_item; } #undef FROM_DEFAULT_V4_UCHAR diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 35698c94c4f..e34abbd32ec 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -979,7 +979,7 @@ static void write_libraries(WriteData *wd, Main *main) if (main->curlib->packedfile) { BKE_packedfile_blend_write(&writer, main->curlib->packedfile); if (wd->use_memfile == false) { - CLOG_INFO(&LOG, 2, "Write packed .blend: %s\n", main->curlib->filepath); + CLOG_INFO(&LOG, 2, "Write packed .blend: %s", main->curlib->filepath); } } @@ -992,7 +992,7 @@ static void write_libraries(WriteData *wd, Main *main) if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { CLOG_ERROR(&LOG, "Data-block '%s' from lib '%s' is not linkable, but is flagged as " - "directly linked\n", + "directly linked", id->name, main->curlib->filepath_abs); } @@ -1503,7 +1503,7 @@ void BLO_write_struct_array_by_name(BlendWriter *writer, { int struct_id = BLO_get_struct_id_by_name(writer, struct_name); if (UNLIKELY(struct_id == -1)) { - CLOG_ERROR(&LOG, "Can't find SDNA code <%s>\n", struct_name); + CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name); return; } BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr); @@ -1551,7 +1551,7 @@ void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name, { int struct_id = BLO_get_struct_id_by_name(writer, struct_name); if (UNLIKELY(struct_id == -1)) { - CLOG_ERROR(&LOG, "Can't find SDNA code <%s>\n", struct_name); + CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name); return; } BLO_write_struct_list_by_id(writer, struct_id, list); diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index ebb0f604df7..129eba3de2f 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -28,13 +28,6 @@ const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid); const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid); const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid); -/** - * Note that "lang" here is the _output_ display language. We used to restrict - * IME for keyboard _input_ language because our multilingual font was only used - * when some output languages were selected. That font is used all the time now. - */ -bool BLT_lang_is_ime_supported(void); - /* The "translation-marker" macro. */ #define N_(msgid) msgid #define CTX_N_(context, msgid) msgid diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c index b015057ad2d..cb04b3ac0dc 100644 --- a/source/blender/blentranslation/intern/blt_lang.c +++ b/source/blender/blentranslation/intern/blt_lang.c @@ -345,12 +345,3 @@ void BLT_lang_locale_explode(const char *locale, MEM_freeN(_t); } } - -bool BLT_lang_is_ime_supported(void) -{ -#ifdef WITH_INPUT_IME - return true; -#else - return false; -#endif -} diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index ff8506f1868..a7637d2712c 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -60,8 +60,11 @@ void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, } /* prototypes */ -static void bm_loop_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude); +static void bm_loop_attrs_copy(BMesh *bm_src, + BMesh *bm_dst, + const BMLoop *l_src, + BMLoop *l_dst, + eCustomDataMask mask_exclude); BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, @@ -321,7 +324,7 @@ void BM_verts_sort_radial_plane(BMVert **vert_arr, int len) /*************************************************************/ static void bm_vert_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, CustomDataMask mask_exclude) + BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, eCustomDataMask mask_exclude) { if ((bm_src == bm_dst) && (v_src == v_dst)) { BLI_assert_msg(0, "BMVert: source and target match"); @@ -336,7 +339,7 @@ static void bm_vert_attrs_copy( } static void bm_edge_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, CustomDataMask mask_exclude) + BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, eCustomDataMask mask_exclude) { if ((bm_src == bm_dst) && (e_src == e_dst)) { BLI_assert_msg(0, "BMEdge: source and target match"); @@ -348,7 +351,7 @@ static void bm_edge_attrs_copy( } static void bm_loop_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude) + BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, eCustomDataMask mask_exclude) { if ((bm_src == bm_dst) && (l_src == l_dst)) { BLI_assert_msg(0, "BMLoop: source and target match"); @@ -360,7 +363,7 @@ static void bm_loop_attrs_copy( } static void bm_face_attrs_copy( - BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, CustomDataMask mask_exclude) + BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, eCustomDataMask mask_exclude) { if ((bm_src == bm_dst) && (f_src == f_dst)) { BLI_assert_msg(0, "BMFace: source and target match"); diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index ee8c22df630..4391a6a92d7 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -460,7 +460,7 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo for (el_store = eloops->first; el_store; el_store = el_store->next) { float len_sq; if (use_normals) { - /* scale the length by how close the loops are to pointing at eachother */ + /* Scale the length by how close the loops are to pointing at each other. */ float dir[3]; sub_v3_v3v3(dir, co, el_store->co); len_sq = normalize_v3(dir); diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 2f5827bdc4c..0c3db31dd1f 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -894,6 +894,27 @@ void BM_data_layer_free(BMesh *bm, CustomData *data, int type) } } +bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name) +{ + CustomData olddata = *data; + olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL; + + /* the pool is now owned by olddata and must not be shared */ + data->pool = NULL; + + const bool has_layer = CustomData_free_layer_named(data, name, 0); + + if (has_layer) { + update_data_blocks(bm, &olddata, data); + } + + if (olddata.layers) { + MEM_freeN(olddata.layers); + } + + return has_layer; +} + void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n) { CustomData olddata; diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h index a2f1dfc706d..2cf9dffceec 100644 --- a/source/blender/bmesh/intern/bmesh_interp.h +++ b/source/blender/bmesh/intern/bmesh_interp.h @@ -59,6 +59,10 @@ void BM_data_interp_face_vert_edge( void BM_data_layer_add(BMesh *bm, CustomData *data, int type); void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name); void BM_data_layer_free(BMesh *bm, CustomData *data, int type); +/** + * Remove a named custom data layer, if it existed. Return true if the layer was removed. + */ +bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name); void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n); void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 890456f9024..739e474c59a 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -888,7 +888,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh me->totloop = bm->totloop; me->totpoly = bm->totface; /* Will be overwritten with a valid value if 'dotess' is set, otherwise we - * end up with 'me->totface' and me->mface == nullptr which can crash T28625. */ + * end up with 'me->totface' and `me->mface == nullptr` which can crash T28625. */ me->totface = 0; me->act_face = -1; diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index aa7f0f511ec..1339efb3057 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -145,7 +145,7 @@ static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e, } static bool bm_edge_delimit_cdata(CustomData *ldata, - CustomDataType type, + eCustomDataType type, struct DelimitData_CD *r_delim_cd) { const int layer_len = CustomData_number_of_layers(ldata, type); diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h index 84ee9c563fd..7868aa140dc 100644 --- a/source/blender/compositor/operations/COM_TonemapOperation.h +++ b/source/blender/compositor/operations/COM_TonemapOperation.h @@ -81,8 +81,8 @@ class TonemapOperation : public MultiThreadedOperation { }; /** - * \brief class of tonemap, implementing the photoreceptor tonemap - * most parts have already been done in TonemapOperation + * \brief class of tone-map, implementing the photo-receptor tone-map + * most parts have already been done in #TonemapOperation. * \ingroup operation */ diff --git a/source/blender/datatoc/datatoc_icon.py b/source/blender/datatoc/datatoc_icon.py index cce464dbc41..7373df71318 100755 --- a/source/blender/datatoc/datatoc_icon.py +++ b/source/blender/datatoc/datatoc_icon.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0-or-later - -# <pep8 compliant> _IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little') diff --git a/source/blender/datatoc/datatoc_icon_split.py b/source/blender/datatoc/datatoc_icon_split.py index fcfd63f8707..8edafeda328 100755 --- a/source/blender/datatoc/datatoc_icon_split.py +++ b/source/blender/datatoc/datatoc_icon_split.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# <pep8 compliant> - """ This script dices up PNG into small files to store in version control. diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 56117a00b73..a3cd821e82f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -54,9 +54,9 @@ bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base) return id_node->has_base; } -/******************************************************************************* - * Base class for builders. - */ +/* -------------------------------------------------------------------- */ +/** \name Base Class for Builders + * \{ */ DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache) : bmain_(bmain), graph_(graph), cache_(cache) @@ -120,9 +120,11 @@ bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const char return check_pchan_has_bbone_segments(object, pchan); } -/******************************************************************************* - * Builder finalizer. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Builder Finalizer. + * \{ */ namespace { @@ -137,7 +139,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph) for (ComponentNode *comp_node : id_node->components.values()) { comp_node->affects_directly_visible |= id_node->is_directly_visible; - /* Enforce "visibility" of the syncronization component. + /* Enforce "visibility" of the synchronization component. * * This component is never connected to other ID nodes, and hence can not be handled in the * same way as other components needed for evaluation. It is only needed for proper @@ -213,7 +215,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph) void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) { - /* Make sure dependencies of visible ID datablocks are visible. */ + /* Make sure dependencies of visible ID data-blocks are visible. */ deg_graph_build_flush_visibility(graph); deg_graph_remove_unused_noops(graph); @@ -248,4 +250,6 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) } } +/** \} */ + } // namespace blender::deg diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index d632c4e2f7e..8ba6c840a59 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -42,9 +42,7 @@ struct StackEntry { struct CyclesSolverState { CyclesSolverState(Depsgraph *graph) - : graph(graph), - traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")), - num_cycles(0) + : graph(graph), traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")) { /* pass */ } @@ -57,7 +55,7 @@ struct CyclesSolverState { } Depsgraph *graph; BLI_Stack *traversal_stack; - int num_cycles; + int num_cycles = 0; }; inline void set_node_visited_state(Node *node, eCyclicCheckVisitedState state) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index ae159373efd..c13c6d2f870 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1137,6 +1137,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, /* Add dependencies for each constraint in turn. */ for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {nullptr, nullptr}; /* Invalid constraint type. */ if (cti == nullptr) { continue; @@ -1188,9 +1189,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, add_relation(cache_key, constraint_op_key, cti->name); } } - else if (cti->get_constraint_targets) { - ListBase targets = {nullptr, nullptr}; - cti->get_constraint_targets(con, &targets); + else if (BKE_constraint_targets_get(con, &targets)) { LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { if (ct->tar == nullptr) { continue; @@ -1300,9 +1299,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, add_relation(target_transform_key, constraint_op_key, cti->name); } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, true); - } + BKE_constraint_targets_flush(con, &targets, true); } } } @@ -1714,6 +1711,37 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) } add_relation(variable_exit_key, driver_key, "RNA Target -> Driver"); + /* It is possible that RNA path points to a property of a different ID than the target_id: + * for example, paths like "data" on Object, "camera" on Scene. + * + * For the demonstration purposes lets consider a driver variable uses Scene ID as target + * and "camera.location.x" as its RNA path. If the scene has 2 different cameras at + * 2 different locations changing the active scene camera is expected to immediately be + * reflected in the variable value. In order to achieve this behavior we create a relation + * from the target ID to the driver so that if the ID property of the target ID changes the + * driver is re-evaluated. + * + * The most straightforward (at the moment of writing this comment) way of figuring out + * such relation is to use copy-on-write operation of the target ID. There are two down + * sides of this approach which are considered a design limitation as there is a belief + * that they are not common in practice or are not reliable due to other issues: + * + * - IDs which are not covered with the copy-on-write mechanism. + * + * Such IDs are either do not have ID properties, or are not part of the dependency + * graph. + * + * - Modifications of evaluated IDs from a Python handler. + * Such modifications are not fully integrated in the dependency graph evaluation as it + * has issues with copy-on-write tagging and the fact that relations are defined by the + * original main database status. */ + if (target_id != variable_exit_key.ptr.owner_id) { + if (deg_copy_on_write_is_needed(GS(target_id->name))) { + ComponentKey target_id_key(target_id, NodeType::COPY_ON_WRITE); + add_relation(target_id_key, driver_key, "Target ID -> Driver"); + } + } + /* The RNA getter for `object.data` can write to the mesh datablock due * to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation * ensures it is safe to call when the driver is evaluated. diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 3381dbadbab..9cb3743dd02 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -39,8 +39,8 @@ set(INC set(SRC intern/draw_cache.c intern/draw_cache_extract_mesh.cc - intern/draw_cache_extract_mesh_render_data.c - intern/mesh_extractors/extract_mesh.c + intern/draw_cache_extract_mesh_render_data.cc + intern/mesh_extractors/extract_mesh.cc intern/mesh_extractors/extract_mesh_ibo_edituv.cc intern/mesh_extractors/extract_mesh_ibo_fdots.cc intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -75,7 +75,7 @@ set(SRC intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c intern/draw_cache_impl_lattice.c - intern/draw_cache_impl_mesh.c + intern/draw_cache_impl_mesh.cc intern/draw_cache_impl_metaball.c intern/draw_cache_impl_particles.c intern/draw_cache_impl_pointcloud.c @@ -141,8 +141,8 @@ set(SRC engines/eevee_next/eevee_pipeline.cc engines/eevee_next/eevee_shader.cc engines/eevee_next/eevee_sync.cc - engines/eevee_next/eevee_view.cc engines/eevee_next/eevee_velocity.cc + engines/eevee_next/eevee_view.cc engines/eevee_next/eevee_world.cc engines/workbench/workbench_data.c engines/workbench/workbench_effect_antialiasing.c @@ -201,7 +201,7 @@ set(SRC intern/DRW_render.h intern/draw_attributes.h intern/draw_cache.h - intern/draw_cache_extract.h + intern/draw_cache_extract.hh intern/draw_cache_impl.h intern/draw_cache_inline.h intern/draw_color_management.h @@ -221,7 +221,7 @@ set(SRC intern/draw_texture_pool.h intern/draw_view.h intern/draw_view_data.h - intern/mesh_extractors/extract_mesh.h + intern/mesh_extractors/extract_mesh.hh intern/smaa_textures.h engines/basic/basic_engine.h engines/basic/basic_private.h @@ -452,108 +452,113 @@ set(GLSL_SRC engines/select/shaders/select_id_vert.glsl engines/select/shaders/select_id_frag.glsl - engines/basic/shaders/conservative_depth_geom.glsl - engines/basic/shaders/depth_vert.glsl - engines/basic/shaders/depth_pointcloud_vert.glsl - engines/basic/shaders/depth_frag.glsl - - engines/overlay/shaders/common_overlay_lib.glsl - engines/overlay/shaders/antialiasing_frag.glsl - engines/overlay/shaders/armature_dof_vert.glsl - engines/overlay/shaders/armature_dof_solid_frag.glsl - engines/overlay/shaders/armature_envelope_outline_vert.glsl - engines/overlay/shaders/armature_envelope_solid_frag.glsl - engines/overlay/shaders/armature_envelope_solid_vert.glsl - engines/overlay/shaders/armature_shape_outline_geom.glsl - engines/overlay/shaders/armature_shape_outline_vert.glsl - engines/overlay/shaders/armature_shape_solid_frag.glsl - engines/overlay/shaders/armature_shape_solid_vert.glsl - engines/overlay/shaders/armature_shape_wire_vert.glsl - engines/overlay/shaders/armature_sphere_outline_vert.glsl - engines/overlay/shaders/armature_sphere_solid_frag.glsl - engines/overlay/shaders/armature_sphere_solid_vert.glsl - engines/overlay/shaders/armature_stick_frag.glsl - engines/overlay/shaders/armature_stick_vert.glsl - engines/overlay/shaders/armature_wire_frag.glsl - engines/overlay/shaders/armature_wire_vert.glsl - engines/overlay/shaders/background_frag.glsl - engines/overlay/shaders/clipbound_vert.glsl - engines/overlay/shaders/depth_only_vert.glsl - engines/overlay/shaders/edit_curve_handle_geom.glsl - engines/overlay/shaders/edit_curve_handle_vert.glsl - engines/overlay/shaders/edit_curve_point_vert.glsl - engines/overlay/shaders/edit_curve_wire_vert.glsl - engines/overlay/shaders/edit_gpencil_canvas_vert.glsl - engines/overlay/shaders/edit_gpencil_guide_vert.glsl - engines/overlay/shaders/edit_gpencil_vert.glsl - engines/overlay/shaders/edit_lattice_point_vert.glsl - engines/overlay/shaders/edit_lattice_wire_vert.glsl - engines/overlay/shaders/edit_mesh_common_lib.glsl - engines/overlay/shaders/edit_mesh_frag.glsl - engines/overlay/shaders/edit_mesh_geom.glsl - engines/overlay/shaders/edit_mesh_normal_vert.glsl - engines/overlay/shaders/edit_mesh_analysis_frag.glsl - engines/overlay/shaders/edit_mesh_analysis_vert.glsl - engines/overlay/shaders/edit_mesh_skin_root_vert.glsl - engines/overlay/shaders/edit_mesh_vert.glsl - engines/overlay/shaders/edit_particle_strand_vert.glsl - engines/overlay/shaders/edit_particle_point_vert.glsl - engines/overlay/shaders/edit_uv_edges_vert.glsl - engines/overlay/shaders/edit_uv_edges_geom.glsl - engines/overlay/shaders/edit_uv_edges_frag.glsl - engines/overlay/shaders/edit_uv_verts_vert.glsl - engines/overlay/shaders/edit_uv_verts_frag.glsl - engines/overlay/shaders/edit_uv_faces_vert.glsl - engines/overlay/shaders/edit_uv_face_dots_vert.glsl - engines/overlay/shaders/edit_uv_image_vert.glsl - engines/overlay/shaders/edit_uv_image_mask_frag.glsl - engines/overlay/shaders/edit_uv_stretching_vert.glsl - engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl - engines/overlay/shaders/extra_frag.glsl - engines/overlay/shaders/extra_vert.glsl - engines/overlay/shaders/extra_groundline_vert.glsl - engines/overlay/shaders/extra_lightprobe_grid_vert.glsl - engines/overlay/shaders/extra_loose_point_frag.glsl - engines/overlay/shaders/extra_loose_point_vert.glsl - engines/overlay/shaders/extra_point_vert.glsl - engines/overlay/shaders/extra_wire_frag.glsl - engines/overlay/shaders/extra_wire_vert.glsl - engines/overlay/shaders/facing_frag.glsl - engines/overlay/shaders/facing_vert.glsl - engines/overlay/shaders/grid_background_frag.glsl - engines/overlay/shaders/grid_frag.glsl - engines/overlay/shaders/grid_vert.glsl - engines/overlay/shaders/image_vert.glsl - engines/overlay/shaders/image_frag.glsl - engines/overlay/shaders/motion_path_line_frag.glsl - engines/overlay/shaders/motion_path_line_geom.glsl - engines/overlay/shaders/motion_path_line_vert.glsl - engines/overlay/shaders/motion_path_point_vert.glsl - engines/overlay/shaders/outline_detect_frag.glsl - engines/overlay/shaders/outline_prepass_frag.glsl - engines/overlay/shaders/outline_prepass_gpencil_frag.glsl - engines/overlay/shaders/outline_prepass_geom.glsl - engines/overlay/shaders/outline_prepass_gpencil_vert.glsl - engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl - engines/overlay/shaders/outline_prepass_vert.glsl - engines/overlay/shaders/paint_face_vert.glsl - engines/overlay/shaders/paint_point_vert.glsl - engines/overlay/shaders/paint_texture_frag.glsl - engines/overlay/shaders/paint_texture_vert.glsl - engines/overlay/shaders/paint_vertcol_frag.glsl - engines/overlay/shaders/paint_vertcol_vert.glsl - engines/overlay/shaders/paint_weight_frag.glsl - engines/overlay/shaders/paint_weight_vert.glsl - engines/overlay/shaders/paint_wire_vert.glsl - engines/overlay/shaders/particle_vert.glsl - engines/overlay/shaders/particle_frag.glsl - engines/overlay/shaders/sculpt_mask_vert.glsl - engines/overlay/shaders/sculpt_mask_frag.glsl - engines/overlay/shaders/volume_velocity_vert.glsl - engines/overlay/shaders/volume_gridlines_vert.glsl - engines/overlay/shaders/wireframe_vert.glsl - engines/overlay/shaders/wireframe_frag.glsl - engines/overlay/shaders/xray_fade_frag.glsl + engines/basic/shaders/basic_conservative_depth_geom.glsl + engines/basic/shaders/basic_depth_vert.glsl + engines/basic/shaders/basic_depth_pointcloud_vert.glsl + engines/basic/shaders/basic_depth_frag.glsl + + engines/overlay/shaders/overlay_antialiasing_frag.glsl + engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl + engines/overlay/shaders/overlay_armature_dof_vert.glsl + engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl + engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl + engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl + engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl + engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl + engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl + engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl + engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl + engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl + engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl + engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl + engines/overlay/shaders/overlay_armature_stick_frag.glsl + engines/overlay/shaders/overlay_armature_stick_vert.glsl + engines/overlay/shaders/overlay_armature_wire_frag.glsl + engines/overlay/shaders/overlay_armature_wire_vert.glsl + engines/overlay/shaders/overlay_background_frag.glsl + engines/overlay/shaders/overlay_clipbound_vert.glsl + engines/overlay/shaders/overlay_common_lib.glsl + engines/overlay/shaders/overlay_depth_only_frag.glsl + engines/overlay/shaders/overlay_depth_only_vert.glsl + engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl + engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl + engines/overlay/shaders/overlay_edit_curve_point_vert.glsl + engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl + engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl + engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl + engines/overlay/shaders/overlay_edit_gpencil_vert.glsl + engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl + engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl + engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl + engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl + engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl + engines/overlay/shaders/overlay_edit_mesh_frag.glsl + engines/overlay/shaders/overlay_edit_mesh_geom.glsl + engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl + engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl + engines/overlay/shaders/overlay_edit_mesh_vert.glsl + engines/overlay/shaders/overlay_edit_particle_point_vert.glsl + engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl + engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl + engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl + engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl + engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl + engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl + engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl + engines/overlay/shaders/overlay_edit_uv_image_vert.glsl + engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl + engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl + engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl + engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl + engines/overlay/shaders/overlay_extra_frag.glsl + engines/overlay/shaders/overlay_extra_groundline_vert.glsl + engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl + engines/overlay/shaders/overlay_extra_loose_point_frag.glsl + engines/overlay/shaders/overlay_extra_loose_point_vert.glsl + engines/overlay/shaders/overlay_extra_point_vert.glsl + engines/overlay/shaders/overlay_extra_vert.glsl + engines/overlay/shaders/overlay_extra_wire_frag.glsl + engines/overlay/shaders/overlay_extra_wire_vert.glsl + engines/overlay/shaders/overlay_facing_frag.glsl + engines/overlay/shaders/overlay_facing_vert.glsl + engines/overlay/shaders/overlay_grid_background_frag.glsl + engines/overlay/shaders/overlay_grid_frag.glsl + engines/overlay/shaders/overlay_grid_vert.glsl + engines/overlay/shaders/overlay_image_frag.glsl + engines/overlay/shaders/overlay_image_vert.glsl + engines/overlay/shaders/overlay_motion_path_line_frag.glsl + engines/overlay/shaders/overlay_motion_path_line_geom.glsl + engines/overlay/shaders/overlay_motion_path_line_vert.glsl + engines/overlay/shaders/overlay_motion_path_point_vert.glsl + engines/overlay/shaders/overlay_outline_detect_frag.glsl + engines/overlay/shaders/overlay_outline_prepass_frag.glsl + engines/overlay/shaders/overlay_outline_prepass_geom.glsl + engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl + engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl + engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl + engines/overlay/shaders/overlay_outline_prepass_vert.glsl + engines/overlay/shaders/overlay_paint_face_vert.glsl + engines/overlay/shaders/overlay_paint_point_vert.glsl + engines/overlay/shaders/overlay_paint_texture_frag.glsl + engines/overlay/shaders/overlay_paint_texture_vert.glsl + engines/overlay/shaders/overlay_paint_vertcol_frag.glsl + engines/overlay/shaders/overlay_paint_vertcol_vert.glsl + engines/overlay/shaders/overlay_paint_weight_frag.glsl + engines/overlay/shaders/overlay_paint_weight_vert.glsl + engines/overlay/shaders/overlay_paint_wire_vert.glsl + engines/overlay/shaders/overlay_particle_frag.glsl + engines/overlay/shaders/overlay_particle_vert.glsl + engines/overlay/shaders/overlay_point_varying_color_frag.glsl + engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl + engines/overlay/shaders/overlay_sculpt_mask_frag.glsl + engines/overlay/shaders/overlay_sculpt_mask_vert.glsl + engines/overlay/shaders/overlay_uniform_color_frag.glsl + engines/overlay/shaders/overlay_varying_color.glsl + engines/overlay/shaders/overlay_volume_gridlines_vert.glsl + engines/overlay/shaders/overlay_volume_velocity_vert.glsl + engines/overlay/shaders/overlay_wireframe_frag.glsl + engines/overlay/shaders/overlay_wireframe_vert.glsl + engines/overlay/shaders/overlay_xray_fade_frag.glsl engines/overlay/overlay_shader_shared.h diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 00822946fe5..dec7a22aadb 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -23,6 +23,9 @@ struct DrawEngineType; struct GHash; struct GPUMaterial; struct GPUOffScreen; +struct GPUVertFormat; +struct CustomDataLayer; +struct CustomData; struct GPUViewport; struct ID; struct Main; @@ -218,6 +221,12 @@ void DRW_opengl_context_activate(bool drw_state); */ void DRW_draw_cursor_2d_ex(const struct ARegion *region, const float cursor[2]); +void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat *format, + const char *base_name, + const struct CustomData *data, + const struct CustomDataLayer *cl, + bool is_active_render, + bool is_active_layer); #ifdef __cplusplus } #endif diff --git a/source/blender/draw/engines/basic/basic_shader.c b/source/blender/draw/engines/basic/basic_shader.c index d7a8f23e3b3..3d40c627fff 100644 --- a/source/blender/draw/engines/basic/basic_shader.c +++ b/source/blender/draw/engines/basic/basic_shader.c @@ -11,9 +11,9 @@ #include "basic_private.h" -extern char datatoc_depth_frag_glsl[]; -extern char datatoc_depth_vert_glsl[]; -extern char datatoc_conservative_depth_geom_glsl[]; +extern char datatoc_basic_depth_frag_glsl[]; +extern char datatoc_basic_depth_vert_glsl[]; +extern char datatoc_basic_conservative_depth_geom_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_common_pointcloud_lib_glsl[]; diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl index d478f37691e..d478f37691e 100644 --- a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl +++ b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl diff --git a/source/blender/draw/engines/basic/shaders/depth_frag.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl index ff4a015c335..ff4a015c335 100644 --- a/source/blender/draw/engines/basic/shaders/depth_frag.glsl +++ b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl diff --git a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl index b82edc61cee..b82edc61cee 100644 --- a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl +++ b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl diff --git a/source/blender/draw/engines/basic/shaders/depth_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl index 7046979cf97..7046979cf97 100644 --- a/source/blender/draw/engines/basic/shaders/depth_vert.glsl +++ b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl diff --git a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh index 9914d264c63..bae50eb48fa 100644 --- a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh +++ b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh @@ -10,7 +10,7 @@ GPU_SHADER_CREATE_INFO(basic_conservative) .geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3) - .geometry_source("conservative_depth_geom.glsl"); + .geometry_source("basic_conservative_depth_geom.glsl"); /** \} */ @@ -20,11 +20,11 @@ GPU_SHADER_CREATE_INFO(basic_conservative) GPU_SHADER_CREATE_INFO(basic_mesh) .vertex_in(0, Type::VEC3, "pos") - .vertex_source("depth_vert.glsl") + .vertex_source("basic_depth_vert.glsl") .additional_info("draw_mesh"); GPU_SHADER_CREATE_INFO(basic_pointcloud) - .vertex_source("depth_pointcloud_vert.glsl") + .vertex_source("basic_depth_pointcloud_vert.glsl") .additional_info("draw_pointcloud"); /** \} */ @@ -54,7 +54,7 @@ GPU_SHADER_CREATE_INFO(basic_pointcloud) /** \name Depth shader types. * \{ */ -GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("depth_frag.glsl"); +GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("basic_depth_frag.glsl"); BASIC_OBTYPE_VARIATIONS(basic_depth, "basic_depth"); diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c index d12ce7213f9..4528027a9ea 100644 --- a/source/blender/draw/engines/eevee/eevee_bloom.c +++ b/source/blender/draw/engines/eevee/eevee_bloom.c @@ -125,7 +125,8 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name, struct GPUShader *sh, DRWPass **pass, bool upsample, - bool resolve) + bool resolve, + bool resolve_add_base) { struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); @@ -141,7 +142,7 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name, } if (resolve) { DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 1); - DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", true); + DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", resolve_add_base); } return grp; @@ -193,18 +194,21 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved EEVEE_shaders_bloom_downsample_get(use_antiflicker), &psl->bloom_downsample_first, false, + false, false); eevee_create_bloom_pass("Bloom Downsample", effects, EEVEE_shaders_bloom_downsample_get(false), &psl->bloom_downsample, false, + false, false); eevee_create_bloom_pass("Bloom Upsample", effects, EEVEE_shaders_bloom_upsample_get(use_highres), &psl->bloom_upsample, true, + false, false); grp = eevee_create_bloom_pass("Bloom Blit", @@ -212,6 +216,7 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved EEVEE_shaders_bloom_blit_get(use_antiflicker), &psl->bloom_blit, false, + false, false); DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1); DRW_shgroup_uniform_float(grp, "clampIntensity", &effects->bloom_clamp, 1); @@ -221,6 +226,7 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved EEVEE_shaders_bloom_resolve_get(use_highres), &psl->bloom_resolve, true, + true, true); } } @@ -304,13 +310,13 @@ void EEVEE_bloom_output_init(EEVEE_ViewLayerData *UNUSED(sldata), {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->bloom_accum)}); /* Create Pass and shgroup. */ - DRWShadingGroup *grp = eevee_create_bloom_pass("Bloom Accumulate", - effects, - EEVEE_shaders_bloom_resolve_get(use_highres), - &psl->bloom_accum_ps, - true, - true); - DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", false); + eevee_create_bloom_pass("Bloom Accumulate", + effects, + EEVEE_shaders_bloom_resolve_get(use_highres), + &psl->bloom_accum_ps, + true, + true, + false); } void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 0a7c8e185c4..ad218d80cdf 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -671,7 +671,7 @@ typedef struct EEVEE_HairMotionData { /** Allocator will alloc enough slot for all particle systems. Or 1 if it's a curves object. */ int psys_len; struct { - /* The vbos and textures are not owned. */ + /* The VBO's and textures are not owned. */ EEVEE_HairMotionStepData step_data[2]; /* Data for time = t +/- step. */ } psys[0]; } EEVEE_HairMotionData; @@ -682,7 +682,7 @@ typedef struct EEVEE_GeometryMotionData { /** To disable deform mb if vertcount mismatch. */ int use_deform; - /* The batch and vbos are not owned. */ + /* The batch and VBOs are not owned. */ struct GPUBatch *batch; /* Batch for time = t. */ struct GPUVertBuf *vbo[2]; /* VBO for time = t +/- step. */ } EEVEE_GeometryMotionData; diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 6fd5d97089d..5709621fc05 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -718,7 +718,7 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair) if (e_data.cryptomatte_sh[index] == NULL) { DynStr *ds = BLI_dynstr_new(); BLI_dynstr_append(ds, SHADER_DEFINES); - BLI_dynstr_append(ds, "#define attrib_load(a) \n"); + BLI_dynstr_append(ds, "#define attrib_load() \n"); if (is_hair) { BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); } diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl index 0f5290a7c07..ffca97b6b8f 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl @@ -181,6 +181,8 @@ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection) /* Glue with the old system. */ CLOSURE_VARS_DECLARE_2(Diffuse, Glossy); + /* WORKAROUND: This is to avoid regression in 3.2 and avoid messing with EEVEE-Next. */ + in_common.occlusion = (diffuse.sss_radius.g == -1.0) ? diffuse.sss_radius.r : 1.0; in_Diffuse_0.N = diffuse.N; in_Diffuse_0.albedo = diffuse.color; in_Glossy_1.N = reflection.N; @@ -207,6 +209,8 @@ Closure closure_eval(ClosureDiffuse diffuse, /* Glue with the old system. */ CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy); + /* WORKAROUND: This is to avoid regression in 3.2 and avoid messing with EEVEE-Next. */ + in_common.occlusion = (diffuse.sss_radius.g == -1.0) ? diffuse.sss_radius.r : 1.0; in_Diffuse_0.N = diffuse.N; in_Diffuse_0.albedo = diffuse.color; in_Glossy_1.N = reflection.N; diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl index 186f438b03b..b3b9c7af19c 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl @@ -77,3 +77,13 @@ vec3 coordinate_incoming(vec3 P) { return vec3(0.0); } + +float attr_load_temperature_post(float attr) +{ + return attr; +} + +vec4 attr_load_color_post(vec4 attr) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index 7141928a20d..f75ebd2bd13 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -12,7 +12,7 @@ #pragma once /** - Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536. + * 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. */ 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 1261c855a82..eb409f076f3 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -126,7 +126,7 @@ BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16) * \{ */ enum eClosureBits : uint32_t { - /** NOTE: Theses are used as stencil bits. So we are limited to 8bits. */ + /** NOTE: These are used as stencil bits. So we are limited to 8bits. */ CLOSURE_DIFFUSE = (1u << 0u), CLOSURE_SSS = (1u << 1u), CLOSURE_REFLECTION = (1u << 2u), diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc index 9f8dce43910..ceae9df44d0 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc @@ -185,7 +185,7 @@ void VelocityModule::step_swap() dst_ofs += src_len; } /* TODO(@fclem): Fail gracefully (disable motion blur + warning print) if - `tot_len * sizeof(float4)` is greater than max SSBO size. */ + * `tot_len * sizeof(float4)` is greater than max SSBO size. */ geometry_steps[step_]->resize(max_ii(16, dst_ofs)); for (VelocityGeometryData &geom : geometry_map.values()) { diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh index 1bfd9f8c18f..e2606c061e1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.hh +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh @@ -111,7 +111,7 @@ class VelocityModule { void step_sync(eVelocityStep step, float time); /* Gather motion data. Returns true if the object **can** have motion. */ - bool step_object_sync(Object *ob, ObjectKey &ob_key, int recalc = 0); + bool step_object_sync(Object *ob, ObjectKey &object_key, int recalc = 0); /* Moves next frame data to previous frame data. Nullify next frame data. */ void step_swap(); diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh index 95ec1760c63..fb74412f557 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.hh +++ b/source/blender/draw/engines/eevee_next/eevee_view.hh @@ -41,7 +41,7 @@ class ShadingView { /** Matrix to apply to the viewmat. */ const float (*face_matrix_)[4]; - /** Post-fx modules. */ + /** Post-FX modules. */ // DepthOfField dof_; // MotionBlur mb_; VelocityView velocity_; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl index 1b113e529b6..a65bb7decb6 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl @@ -132,7 +132,9 @@ int curves_attribute_element_id() { int id = interp.curves_strand_id; if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) { +# ifdef COMMON_HAIR_LIB id = hair_get_base_id(); +# endif } g_curves_attr_id += 1; @@ -285,7 +287,7 @@ vec3 attr_load_uv(vec3 attr) /** \name Volume Attribute post * * TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on - * the engine side. But as of now, the engines are reponsible for loading the attributes. + * the engine side. But as of now, the engines are responsible for loading the attributes. * * \{ */ 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 277b2e35d8b..0ccf06a9e14 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 @@ -29,7 +29,7 @@ bool closure_select(float weight, inout float total_weight, inout float r) float x = weight / total_weight; bool chosen = (r < x); /* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within - * that interval, so you remaping to [0,1] again to explore this space of probability. */ + * that interval, so you remapping to [0,1] again to explore this space of probability. */ r = (chosen) ? (r / x) : ((r - x) / (1.0 - x)); return chosen; } @@ -333,7 +333,7 @@ vec3 coordinate_screen(vec3 P) window.xy = vec2(0.5); } else { - /* TODO(fclem): Actual camera tranform. */ + /* TODO(fclem): Actual camera transform. */ window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5; window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw; } 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 49250b5741e..a944bea402e 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 @@ -39,7 +39,10 @@ GPU_SHADER_CREATE_INFO(eevee_geom_curves) .additional_info("eevee_shared") .define("MAT_GEOM_CURVES") .vertex_source("eevee_geom_curves_vert.glsl") - .additional_info("draw_hair", "draw_resource_id_varying", "draw_resource_handle"); + .additional_info("draw_hair", + "draw_curves_infos", + "draw_resource_id_varying", + "draw_resource_handle"); GPU_SHADER_CREATE_INFO(eevee_geom_world) .additional_info("eevee_shared") @@ -166,7 +169,7 @@ GPU_SHADER_CREATE_INFO(eevee_material_stub).define("EEVEE_MATERIAL_STUBS"); # define EEVEE_MAT_GEOM_VARIATIONS(prefix, ...) \ EEVEE_MAT_FINAL_VARIATION(prefix##_world, "eevee_geom_world", __VA_ARGS__) \ EEVEE_MAT_FINAL_VARIATION(prefix##_gpencil, "eevee_geom_gpencil", __VA_ARGS__) \ - EEVEE_MAT_FINAL_VARIATION(prefix##_hair, "eevee_geom_curves", __VA_ARGS__) \ + EEVEE_MAT_FINAL_VARIATION(prefix##_curves, "eevee_geom_curves", __VA_ARGS__) \ EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__) # define EEVEE_MAT_PIPE_VARIATIONS(name, ...) \ diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 9f2f2b4b23d..b9c09e2bc4f 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -36,8 +36,8 @@ #define EXTERNAL_ENGINE "BLENDER_EXTERNAL" -extern char datatoc_depth_frag_glsl[]; -extern char datatoc_depth_vert_glsl[]; +extern char datatoc_basic_depth_frag_glsl[]; +extern char datatoc_basic_depth_vert_glsl[]; extern char datatoc_common_view_lib_glsl[]; diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 5d8ba06e181..f875254a685 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -1310,13 +1310,11 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, } else { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); + ListBase targets = {NULL, NULL}; - if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag & (1 << 0))) { - ListBase targets = {NULL, NULL}; + if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) { bConstraintTarget *ct; - cti->get_constraint_targets(curcon, &targets); - for (ct = targets.first; ct; ct = ct->next) { /* calculate target's matrix */ if (cti->get_target_matrix) { @@ -1328,9 +1326,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color); } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(curcon, &targets, 1); - } + BKE_constraint_targets_flush(curcon, &targets, 1); } } } diff --git a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh index fe67dd473b7..0dba8b54e35 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh @@ -9,7 +9,7 @@ GPU_SHADER_CREATE_INFO(overlay_antialiasing) .sampler(2, ImageType::FLOAT_2D, "lineTex") .push_constant(Type::BOOL, "doSmoothLines") .fragment_out(0, Type::VEC4, "fragColor") - .fragment_source("antialiasing_frag.glsl") + .fragment_source("overlay_antialiasing_frag.glsl") .additional_info("draw_fullscreen", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_xray_fade) @@ -18,5 +18,5 @@ GPU_SHADER_CREATE_INFO(overlay_xray_fade) .sampler(1, ImageType::DEPTH_2D, "xrayDepthTex") .push_constant(Type::FLOAT, "opacity") .fragment_out(0, Type::VEC4, "fragColor") - .fragment_source("xray_fade_frag.glsl") + .fragment_source("overlay_xray_fade_frag.glsl") .additional_info("draw_fullscreen"); diff --git a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh index d89272a50cf..9f2acceed97 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh @@ -25,8 +25,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline) /* Per instance. */ .vertex_in(1, Type::MAT4, "inst_obmat") .vertex_out(overlay_armature_wire_iface) - .vertex_source("armature_sphere_outline_vert.glsl") - .fragment_source("armature_wire_frag.glsl") + .vertex_source("overlay_armature_sphere_outline_vert.glsl") + .fragment_source("overlay_armature_wire_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline_clipped) @@ -47,8 +47,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid) .vertex_in(2, Type::MAT4, "inst_obmat") // .depth_layout(DepthLayout::GREATER) /* TODO */ .vertex_out(overlay_armature_sphere_solid_iface) - .vertex_source("armature_sphere_solid_vert.glsl") - .fragment_source("armature_sphere_solid_frag.glsl") + .vertex_source("overlay_armature_sphere_solid_vert.glsl") + .fragment_source("overlay_armature_sphere_solid_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid_clipped) @@ -79,9 +79,9 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline) .vertex_out(overlay_armature_shape_outline_iface) .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2) .geometry_out(overlay_armature_wire_iface) - .vertex_source("armature_shape_outline_vert.glsl") - .geometry_source("armature_shape_outline_geom.glsl") - .fragment_source("armature_wire_frag.glsl") + .vertex_source("overlay_armature_shape_outline_vert.glsl") + .geometry_source("overlay_armature_shape_outline_geom.glsl") + .fragment_source("overlay_armature_wire_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline_clipped) @@ -100,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid) .vertex_in(2, Type::MAT4, "inst_obmat") .depth_write(DepthWrite::GREATER) .vertex_out(overlay_armature_shape_solid_iface) - .vertex_source("armature_shape_solid_vert.glsl") - .fragment_source("armature_shape_solid_frag.glsl") + .vertex_source("overlay_armature_shape_solid_vert.glsl") + .fragment_source("overlay_armature_shape_solid_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid_clipped) @@ -115,8 +115,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire) /* Per instance. */ .vertex_in(2, Type::MAT4, "inst_obmat") .vertex_out(overlay_armature_wire_iface) - .vertex_source("armature_shape_wire_vert.glsl") - .fragment_source("armature_wire_frag.glsl") + .vertex_source("overlay_armature_shape_wire_vert.glsl") + .fragment_source("overlay_armature_wire_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire_clipped) @@ -140,8 +140,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline) .vertex_in(5, Type::VEC4, "outlineColorSize") .vertex_in(6, Type::VEC3, "xAxis") .vertex_out(overlay_armature_wire_iface) - .vertex_source("armature_envelope_outline_vert.glsl") - .fragment_source("armature_wire_frag.glsl") + .vertex_source("overlay_armature_envelope_outline_vert.glsl") + .fragment_source("overlay_armature_wire_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline_clipped) @@ -164,8 +164,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid) .vertex_in(5, Type::VEC3, "boneColor") .vertex_out(overlay_armature_envelope_solid_iface) .push_constant(Type::BOOL, "isDistance") - .vertex_source("armature_envelope_solid_vert.glsl") - .fragment_source("armature_envelope_solid_frag.glsl") + .vertex_source("overlay_armature_envelope_solid_vert.glsl") + .fragment_source("overlay_armature_envelope_solid_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common"); GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid_clipped) @@ -198,8 +198,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_stick) .vertex_in(7, Type::VEC4, "tailColor") .define("do_wire", "(wireColor.a > 0.0)") .vertex_out(overlay_armature_stick_iface) - .vertex_source("armature_stick_vert.glsl") - .fragment_source("armature_stick_frag.glsl") + .vertex_source("overlay_armature_stick_vert.glsl") + .fragment_source("overlay_armature_stick_frag.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_stick_clipped) @@ -218,12 +218,12 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof) .vertex_in(1, Type::VEC4, "color") .vertex_in(2, Type::MAT4, "inst_obmat") .vertex_out(overlay_armature_wire_iface) - .vertex_source("armature_dof_vert.glsl") + .vertex_source("overlay_armature_dof_vert.glsl") .additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire) .do_static_compilation(true) - .fragment_source("armature_dof_solid_frag.glsl") + .fragment_source("overlay_armature_dof_solid_frag.glsl") .additional_info("overlay_armature_dof"); GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped) @@ -232,7 +232,7 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped) GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid) .do_static_compilation(true) - .fragment_source("armature_dof_solid_frag.glsl") + .fragment_source("overlay_armature_dof_solid_frag.glsl") .additional_info("overlay_armature_dof"); GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid_clipped) @@ -251,8 +251,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_wire) .vertex_in(1, Type::VEC4, "color") .push_constant(Type::FLOAT, "alpha") .vertex_out(overlay_armature_wire_iface) - .vertex_source("armature_wire_vert.glsl") - .fragment_source("armature_wire_frag.glsl") + .vertex_source("overlay_armature_wire_vert.glsl") + .fragment_source("overlay_armature_wire_frag.glsl") .additional_info("overlay_frag_output", "draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_armature_wire_clipped) diff --git a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh index c96d302d861..88a012c35c9 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh @@ -9,17 +9,15 @@ GPU_SHADER_CREATE_INFO(overlay_background) .sampler(1, ImageType::DEPTH_2D, "depthBuffer") .push_constant(Type::INT, "bgType") .push_constant(Type::VEC4, "colorOverride") - .fragment_source("background_frag.glsl") + .fragment_source("overlay_background_frag.glsl") .fragment_out(0, Type::VEC4, "fragColor") .additional_info("draw_fullscreen", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_clipbound) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .push_constant(Type::VEC4, "color") .push_constant(Type::VEC3, "boundbox", 8) - .vertex_source("clipbound_vert.glsl") + .vertex_source("overlay_clipbound_vert.glsl") .fragment_out(0, Type::VEC4, "fragColor") - .fragment_source("gpu_shader_uniform_color_frag.glsl") + .fragment_source("overlay_uniform_color_frag.glsl") .additional_info("draw_view"); diff --git a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh index e6f15046838..58f96110887 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh @@ -19,7 +19,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_common) .push_constant(Type::BOOL, "selectEdges") .push_constant(Type::FLOAT, "alpha") .push_constant(Type::IVEC4, "dataMask") - .vertex_source("edit_mesh_vert.glsl") + .vertex_source("overlay_edit_mesh_vert.glsl") .additional_info("draw_modelmat", "draw_globals"); GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "") @@ -29,13 +29,12 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "") GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert) .do_static_compilation(true) .builtins(BuiltinBits::POINT_SIZE) - .define("srgbTarget", "false") /* Colors are already in linear space. */ .define("VERT") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::IVEC4, "data") .vertex_in(2, Type::VEC3, "vnor") .vertex_out(overlay_edit_mesh_vert_iface) - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("overlay_edit_mesh_common"); GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_edge_iface, "geometry_in") @@ -58,8 +57,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge) .vertex_out(overlay_edit_mesh_edge_iface) .geometry_out(overlay_edit_mesh_edge_geom_iface) .geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4) - .geometry_source("edit_mesh_geom.glsl") - .fragment_source("edit_mesh_frag.glsl") + .geometry_source("overlay_edit_mesh_geom.glsl") + .fragment_source("overlay_edit_mesh_frag.glsl") .additional_info("overlay_edit_mesh_common"); GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat) @@ -69,13 +68,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat) GPU_SHADER_CREATE_INFO(overlay_edit_mesh_face) .do_static_compilation(true) - .define("srgbTarget", "false") /* Colors are already in linear space. */ .define("FACE") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::IVEC4, "data") .vertex_in(2, Type::VEC3, "vnor") .vertex_out(overlay_edit_flat_color_iface) - .fragment_source("gpu_shader_3D_smooth_color_frag.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("overlay_edit_mesh_common"); GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot) @@ -86,12 +84,11 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot) .vertex_in(2, Type::VEC4, "norAndFlag") .define("vnor", "norAndFlag.xyz") .vertex_out(overlay_edit_flat_color_iface) - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("overlay_edit_mesh_common"); GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal) .do_static_compilation(true) - .define("srgbTarget", "false") /* Colors are already in linear space. */ .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::VEC4, "lnor") .vertex_in(2, Type::VEC4, "vnor") @@ -103,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal) .push_constant(Type::BOOL, "isConstantScreenSizeNormals") .vertex_out(overlay_edit_flat_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_mesh_normal_vert.glsl") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .vertex_source("overlay_edit_mesh_normal_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_modelmat_instanced_attr", "draw_globals"); GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_analysis_iface, "").smooth(Type::VEC4, "weightColor"); @@ -116,20 +113,19 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_analysis) .sampler(0, ImageType::FLOAT_1D, "weightTex") .fragment_out(0, Type::VEC4, "fragColor") .vertex_out(overlay_edit_mesh_analysis_iface) - .vertex_source("edit_mesh_analysis_vert.glsl") - .fragment_source("edit_mesh_analysis_frag.glsl") + .vertex_source("overlay_edit_mesh_analysis_vert.glsl") + .fragment_source("overlay_edit_mesh_analysis_frag.glsl") .additional_info("draw_modelmat"); GPU_SHADER_CREATE_INFO(overlay_edit_mesh_skin_root) .do_static_compilation(true) - .define("srgbTarget", "false") /* Colors are already in linear space. */ .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::FLOAT, "size") .vertex_in(2, Type::VEC3, "local_pos") .vertex_out(overlay_edit_flat_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_mesh_skin_root_vert.glsl") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .vertex_source("overlay_edit_mesh_skin_root_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_modelmat_instanced_attr", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert_clipped) @@ -193,9 +189,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges) .push_constant(Type::FLOAT, "alpha") .push_constant(Type::FLOAT, "dashLength") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_edges_vert.glsl") - .geometry_source("edit_uv_edges_geom.glsl") - .fragment_source("edit_uv_edges_frag.glsl") + .vertex_source("overlay_edit_uv_edges_vert.glsl") + .geometry_source("overlay_edit_uv_edges_geom.glsl") + .fragment_source("overlay_edit_uv_edges_frag.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select) @@ -205,28 +201,24 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select) GPU_SHADER_CREATE_INFO(overlay_edit_uv_faces) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC2, "au") .vertex_in(1, Type::INT, "flag") .push_constant(Type::FLOAT, "uvOpacity") .vertex_out(overlay_edit_flat_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_faces_vert.glsl") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .vertex_source("overlay_edit_uv_faces_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_uv_face_dots) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC2, "au") .vertex_in(1, Type::INT, "flag") .push_constant(Type::FLOAT, "pointSize") .vertex_out(overlay_edit_flat_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_face_dots_vert.glsl") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .vertex_source("overlay_edit_uv_face_dots_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "") @@ -236,8 +228,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "") GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC2, "au") .vertex_in(1, Type::INT, "flag") .push_constant(Type::FLOAT, "pointSize") @@ -245,19 +235,17 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts) .push_constant(Type::VEC4, "color") .vertex_out(overlay_edit_uv_vert_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_verts_vert.glsl") - .fragment_source("edit_uv_verts_frag.glsl") + .vertex_source("overlay_edit_uv_verts_vert.glsl") + .fragment_source("overlay_edit_uv_verts_frag.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_uv_tiled_image_borders) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .push_constant(Type::VEC4, "color") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_tiled_image_borders_vert.glsl") - .fragment_source("gpu_shader_uniform_color_frag.glsl") + .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl") + .fragment_source("overlay_uniform_color_frag.glsl") .additional_info("draw_mesh"); GPU_SHADER_INTERFACE_INFO(edit_uv_image_iface, "").smooth(Type::VEC2, "uvs"); @@ -266,13 +254,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_stencil_image) .do_static_compilation(true) .vertex_in(0, Type::VEC3, "pos") .vertex_out(edit_uv_image_iface) - .vertex_source("edit_uv_image_vert.glsl") + .vertex_source("overlay_edit_uv_image_vert.glsl") .sampler(0, ImageType::FLOAT_2D, "imgTexture") .push_constant(Type::BOOL, "imgPremultiplied") .push_constant(Type::BOOL, "imgAlphaBlend") .push_constant(Type::VEC4, "color") .fragment_out(0, Type::VEC4, "fragColor") - .fragment_source("image_frag.glsl") + .fragment_source("overlay_image_frag.glsl") .additional_info("draw_mesh"); GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image) @@ -282,8 +270,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image) .sampler(0, ImageType::FLOAT_2D, "imgTexture") .push_constant(Type::VEC4, "color") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_image_vert.glsl") - .fragment_source("edit_uv_image_mask_frag.glsl") + .vertex_source("overlay_edit_uv_image_vert.glsl") + .fragment_source("overlay_edit_uv_image_mask_frag.glsl") .additional_info("draw_mesh"); /** \} */ @@ -293,14 +281,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image) * \{ */ GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC2, "pos") .push_constant(Type::VEC2, "aspect") .vertex_out(overlay_edit_nopersp_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_stretching_vert.glsl") - .fragment_source("gpu_shader_2D_smooth_color_frag.glsl") + .vertex_source("overlay_edit_uv_stretching_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_area) @@ -328,8 +314,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type::IN GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle) .do_static_compilation(true) .typedef_source("overlay_shader_shared.h") - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::INT, "data") .vertex_out(overlay_edit_curve_handle_iface) @@ -338,9 +322,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle) .push_constant(Type::BOOL, "showCurveHandles") .push_constant(Type::INT, "curveHandleDisplay") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_curve_handle_vert.glsl") - .geometry_source("edit_curve_handle_geom.glsl") - .fragment_source("gpu_shader_3D_smooth_color_frag.glsl") + .vertex_source("overlay_edit_curve_handle_vert.glsl") + .geometry_source("overlay_edit_curve_handle_geom.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped) @@ -350,16 +334,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped) GPU_SHADER_CREATE_INFO(overlay_edit_curve_point) .do_static_compilation(true) .typedef_source("overlay_shader_shared.h") - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::INT, "data") .vertex_out(overlay_edit_flat_color_iface) .push_constant(Type::BOOL, "showCurveHandles") .push_constant(Type::INT, "curveHandleDisplay") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_curve_point_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .vertex_source("overlay_edit_curve_point_vert.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped) @@ -368,8 +350,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped) GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::VEC3, "nor") .vertex_in(2, Type::VEC3, "tan") @@ -377,8 +357,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire) .push_constant(Type::FLOAT, "normalSize") .vertex_out(overlay_edit_flat_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_curve_wire_vert.glsl") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .vertex_source("overlay_edit_curve_wire_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped) @@ -393,14 +373,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped) GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::INT, "data") .vertex_out(overlay_edit_flat_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_lattice_point_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .vertex_source("overlay_edit_lattice_point_vert.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped) @@ -409,15 +387,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped) GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::FLOAT, "weight") .sampler(0, ImageType::FLOAT_1D, "weightTex") .vertex_out(overlay_edit_smooth_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_lattice_wire_vert.glsl") - .fragment_source("gpu_shader_3D_smooth_color_frag.glsl") + .vertex_source("overlay_edit_lattice_wire_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped) @@ -432,16 +408,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped) GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::FLOAT, "color") .sampler(0, ImageType::FLOAT_1D, "weightTex") .push_constant(Type::BOOL, "useWeight") .vertex_out(overlay_edit_smooth_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_particle_strand_vert.glsl") - .fragment_source("gpu_shader_3D_smooth_color_frag.glsl") + .vertex_source("overlay_edit_particle_strand_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped) @@ -450,14 +424,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped) GPU_SHADER_CREATE_INFO(overlay_edit_particle_point) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::FLOAT, "color") .vertex_out(overlay_edit_flat_color_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_particle_point_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .vertex_source("overlay_edit_particle_point_vert.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped) @@ -472,8 +444,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped) GPU_SHADER_CREATE_INFO(overlay_edit_gpencil) .typedef_source("overlay_shader_shared.h") - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::INT, "ma") .vertex_in(2, Type::UINT, "vflag") @@ -487,13 +457,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil) .push_constant(Type::VEC4, "gpEditColor") .sampler(0, ImageType::FLOAT_1D, "weightTex") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_gpencil_vert.glsl") + .vertex_source("overlay_edit_gpencil_vert.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire) .do_static_compilation(true) .vertex_out(overlay_edit_smooth_color_iface) - .fragment_source("gpu_shader_3D_smooth_color_frag.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("overlay_edit_gpencil"); GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire_clipped) @@ -504,7 +474,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point) .do_static_compilation(true) .define("USE_POINTS") .vertex_out(overlay_edit_flat_color_iface) - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("overlay_edit_gpencil"); GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped) @@ -514,8 +484,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped) /* TODO(fclem): Refactor this to take list of point instead of drawing 1 point per drawcall. */ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::INT, "data") .vertex_out(overlay_edit_flat_color_iface) @@ -523,8 +491,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point) .push_constant(Type::FLOAT, "pSize") .push_constant(Type::VEC4, "pColor") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_gpencil_guide_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .vertex_source("overlay_edit_gpencil_guide_vert.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped) @@ -542,8 +510,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped) GPU_SHADER_CREATE_INFO(overlay_depth_only) .do_static_compilation(true) .vertex_in(0, Type::VEC3, "pos") - .vertex_source("depth_only_vert.glsl") - .fragment_source("gpu_shader_depth_only_frag.glsl") + .vertex_source("overlay_depth_only_vert.glsl") + .fragment_source("overlay_depth_only_frag.glsl") .additional_info("draw_mesh"); GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped) @@ -558,13 +526,11 @@ GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped) GPU_SHADER_CREATE_INFO(overlay_uniform_color) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .push_constant(Type::VEC4, "color") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("depth_only_vert.glsl") - .fragment_source("gpu_shader_uniform_color_frag.glsl") + .vertex_source("overlay_depth_only_vert.glsl") + .fragment_source("overlay_uniform_color_frag.glsl") .additional_info("draw_mesh"); GPU_SHADER_CREATE_INFO(overlay_uniform_color_clipped) diff --git a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh index b9b1b73dbd4..5b50bbcaa55 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh @@ -21,8 +21,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra) .vertex_out(overlay_extra_iface) .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") - .vertex_source("extra_vert.glsl") - .fragment_source("extra_frag.glsl") + .vertex_source("overlay_extra_vert.glsl") + .fragment_source("overlay_extra_frag.glsl") .additional_info("draw_view", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_extra_select) @@ -53,8 +53,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_grid) .push_constant(Type::BOOL, "isTransform") .vertex_out(overlay_extra_grid_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("extra_lightprobe_grid_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .vertex_source("overlay_extra_lightprobe_grid_vert.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("draw_view", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_extra_grid_clipped) @@ -75,8 +75,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_groundline) .vertex_out(overlay_extra_iface) .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") - .vertex_source("extra_groundline_vert.glsl") - .fragment_source("extra_frag.glsl") + .vertex_source("overlay_extra_groundline_vert.glsl") + .fragment_source("overlay_extra_frag.glsl") .additional_info("draw_view", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_extra_groundline_clipped) @@ -103,8 +103,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_wire) .vertex_out(overlay_extra_wire_iface) .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") - .vertex_source("extra_wire_vert.glsl") - .fragment_source("extra_wire_frag.glsl") + .vertex_source("overlay_extra_wire_vert.glsl") + .fragment_source("overlay_extra_wire_frag.glsl") .additional_info("draw_modelmat", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_extra_wire_select) @@ -148,8 +148,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_point) .push_constant(Type::VEC4, "color") .vertex_out(overlay_extra_point_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("extra_point_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_varying_outline_aa_frag.glsl") + .vertex_source("overlay_extra_point_vert.glsl") + .fragment_source("overlay_point_varying_color_varying_outline_aa_frag.glsl") .additional_info("draw_modelmat", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_extra_point_clipped) @@ -165,8 +165,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_loose_point) .vertex_out(overlay_extra_loose_point_iface) .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") - .vertex_source("extra_loose_point_vert.glsl") - .fragment_source("extra_loose_point_frag.glsl") + .vertex_source("overlay_extra_loose_point_vert.glsl") + .fragment_source("overlay_extra_loose_point_frag.glsl") .additional_info("draw_modelmat", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_extra_loose_point_clipped) @@ -194,9 +194,9 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_line) .geometry_out(overlay_motion_path_line_iface) .geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("motion_path_line_vert.glsl") - .geometry_source("motion_path_line_geom.glsl") - .fragment_source("motion_path_line_frag.glsl") + .vertex_source("overlay_motion_path_line_vert.glsl") + .geometry_source("overlay_motion_path_line_geom.glsl") + .fragment_source("overlay_motion_path_line_frag.glsl") .additional_info("draw_view", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_motion_path_line_clipped) @@ -215,8 +215,8 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_point) .push_constant(Type::VEC3, "customColor") .vertex_out(overlay_motion_path_point_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("motion_path_point_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .vertex_source("overlay_motion_path_point_vert.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("draw_view", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_motion_path_point_clipped) @@ -242,8 +242,8 @@ GPU_SHADER_CREATE_INFO(overlay_image) .vertex_out(overlay_image_iface) .sampler(0, ImageType::FLOAT_2D, "imgTexture") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("image_vert.glsl") - .fragment_source("image_frag.glsl") + .vertex_source("overlay_image_vert.glsl") + .fragment_source("overlay_image_frag.glsl") .additional_info("draw_mesh"); GPU_SHADER_CREATE_INFO(overlay_image_clipped) @@ -266,8 +266,8 @@ GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas) .push_constant(Type::INT, "halfLineCount") .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") - .vertex_source("edit_gpencil_canvas_vert.glsl") - .fragment_source("extra_frag.glsl") + .vertex_source("overlay_edit_gpencil_canvas_vert.glsl") + .fragment_source("overlay_extra_frag.glsl") .additional_info("draw_mesh", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas_clipped) @@ -289,7 +289,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle) .vertex_in(1, Type::VEC4, "part_rot") .vertex_in(2, Type::FLOAT, "part_val") .vertex_out(overlay_particle_iface) - .vertex_source("particle_vert.glsl") + .vertex_source("overlay_particle_vert.glsl") .additional_info("draw_globals"); GPU_SHADER_CREATE_INFO(overlay_particle_dot) @@ -299,7 +299,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot) .define("pos", "vec3(0.0)") .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") - .fragment_source("particle_frag.glsl") + .fragment_source("overlay_particle_frag.glsl") .additional_info("overlay_particle", "draw_mesh"); GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped) @@ -308,13 +308,11 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped) GPU_SHADER_CREATE_INFO(overlay_particle_shape) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") /* Instantiated Attrs. */ .vertex_in(3, Type::VEC3, "pos") .vertex_in(4, Type::INT, "vclass") .fragment_out(0, Type::VEC4, "fragColor") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("overlay_particle", "draw_modelmat", "draw_resource_id_uniform"); GPU_SHADER_CREATE_INFO(overlay_particle_shape_clipped) diff --git a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh index 6d6806eaa80..6d528bbba62 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh @@ -5,8 +5,8 @@ GPU_SHADER_CREATE_INFO(overlay_facing) .do_static_compilation(true) .vertex_in(0, Type::VEC3, "pos") - .vertex_source("facing_vert.glsl") - .fragment_source("facing_frag.glsl") + .vertex_source("overlay_facing_vert.glsl") + .fragment_source("overlay_facing_frag.glsl") .fragment_out(0, Type::VEC4, "fragColor") .additional_info("draw_mesh", "draw_globals"); diff --git a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh index d02014c98a0..a8f1281d53a 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh @@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_grid) .uniform_buf(3, "OVERLAY_GridData", "grid_buf") .push_constant(Type::VEC3, "plane_axes") .push_constant(Type::INT, "grid_flag") - .vertex_source("grid_vert.glsl") - .fragment_source("grid_frag.glsl") + .vertex_source("overlay_grid_vert.glsl") + .fragment_source("overlay_grid_frag.glsl") .additional_info("draw_view", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_grid_background) @@ -25,17 +25,15 @@ GPU_SHADER_CREATE_INFO(overlay_grid_background) .sampler(0, ImageType::DEPTH_2D, "depthBuffer") .push_constant(Type::VEC4, "color") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_tiled_image_borders_vert.glsl") - .fragment_source("grid_background_frag.glsl") + .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl") + .fragment_source("overlay_grid_background_frag.glsl") .additional_info("draw_modelmat"); GPU_SHADER_CREATE_INFO(overlay_grid_image) .do_static_compilation(true) - /* NOTE: Color already in Linear space. Which is what we want. */ - .define("srgbTarget", "false") .vertex_in(0, Type::VEC3, "pos") .push_constant(Type::VEC4, "color") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("edit_uv_tiled_image_borders_vert.glsl") - .fragment_source("gpu_shader_uniform_color_frag.glsl") + .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl") + .fragment_source("overlay_uniform_color_frag.glsl") .additional_info("draw_modelmat"); diff --git a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh index 21575747efa..6f6a9c1622d 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh @@ -13,13 +13,13 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass) .vertex_out(overlay_outline_prepass_iface) /* Using uint because 16bit uint can contain more ids than int. */ .fragment_out(0, Type::UINT, "out_object_id") - .fragment_source("outline_prepass_frag.glsl") + .fragment_source("overlay_outline_prepass_frag.glsl") .additional_info("draw_resource_handle"); GPU_SHADER_CREATE_INFO(overlay_outline_prepass_mesh) .do_static_compilation(true) .vertex_in(0, Type::VEC3, "pos") - .vertex_source("outline_prepass_vert.glsl") + .vertex_source("overlay_outline_prepass_vert.glsl") .additional_info("draw_mesh", "overlay_outline_prepass") .additional_info("draw_object_infos"); @@ -36,8 +36,8 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire) .vertex_out(overlay_outline_prepass_wire_iface) .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2) .geometry_out(overlay_outline_prepass_iface) - .vertex_source("outline_prepass_vert.glsl") - .geometry_source("outline_prepass_geom.glsl") + .vertex_source("overlay_outline_prepass_vert.glsl") + .geometry_source("overlay_outline_prepass_geom.glsl") .additional_info("draw_mesh", "overlay_outline_prepass") .additional_info("draw_object_infos"); @@ -56,12 +56,12 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil) .push_constant(Type::BOOL, "isTransform") .vertex_out(overlay_outline_prepass_iface) .vertex_out(overlay_outline_prepass_gpencil_iface) - .vertex_source("outline_prepass_gpencil_vert.glsl") + .vertex_source("overlay_outline_prepass_gpencil_vert.glsl") .push_constant(Type::BOOL, "gpStrokeOrder3d") /* TODO(fclem): Move to a GPencil object UBO. */ .push_constant(Type::VEC4, "gpDepthPlane") /* TODO(fclem): Move to a GPencil object UBO. */ /* Using uint because 16bit uint can contain more ids than int. */ .fragment_out(0, Type::UINT, "out_object_id") - .fragment_source("outline_prepass_gpencil_frag.glsl") + .fragment_source("overlay_outline_prepass_gpencil_frag.glsl") .additional_info("draw_gpencil", "draw_resource_handle"); GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped) @@ -70,7 +70,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped) GPU_SHADER_CREATE_INFO(overlay_outline_prepass_pointcloud) .do_static_compilation(true) - .vertex_source("outline_prepass_pointcloud_vert.glsl") + .vertex_source("overlay_outline_prepass_pointcloud_vert.glsl") .additional_info("draw_pointcloud", "overlay_outline_prepass") .additional_info("draw_object_infos"); @@ -95,7 +95,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_detect) .sampler(2, ImageType::DEPTH_2D, "sceneDepth") .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") - .fragment_source("outline_detect_frag.glsl") + .fragment_source("overlay_outline_detect_frag.glsl") .additional_info("draw_fullscreen", "draw_view", "draw_globals"); /** \} */ diff --git a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh index bbec79d515f..3083d5a463b 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh @@ -10,13 +10,12 @@ GPU_SHADER_CREATE_INFO(overlay_paint_face) .do_static_compilation(true) - .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */ .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */ .push_constant(Type::VEC4, "color") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("paint_face_vert.glsl") - .fragment_source("gpu_shader_uniform_color_frag.glsl") + .vertex_source("overlay_paint_face_vert.glsl") + .fragment_source("overlay_uniform_color_frag.glsl") .additional_info("draw_modelmat"); GPU_SHADER_CREATE_INFO(overlay_paint_face_clipped) @@ -40,8 +39,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_point) .vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */ .vertex_out(overlay_overlay_paint_point_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("paint_point_vert.glsl") - .fragment_source("gpu_shader_point_varying_color_frag.glsl") + .vertex_source("overlay_paint_point_vert.glsl") + .fragment_source("overlay_point_varying_color_frag.glsl") .additional_info("draw_modelmat", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_paint_point_clipped) @@ -70,8 +69,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_texture) .push_constant(Type::BOOL, "maskInvertStencil") .push_constant(Type::BOOL, "maskImagePremultiplied") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("paint_texture_vert.glsl") - .fragment_source("paint_texture_frag.glsl") + .vertex_source("overlay_paint_texture_vert.glsl") + .fragment_source("overlay_paint_texture_frag.glsl") .additional_info("draw_modelmat"); GPU_SHADER_CREATE_INFO(overlay_paint_texture_clipped) @@ -97,8 +96,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_vertcol) .push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */ .push_constant(Type::BOOL, "useAlphaBlend") /* `false` by default. */ .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("paint_vertcol_vert.glsl") - .fragment_source("paint_vertcol_frag.glsl") + .vertex_source("overlay_paint_vertcol_vert.glsl") + .fragment_source("overlay_paint_vertcol_frag.glsl") .additional_info("draw_modelmat"); GPU_SHADER_CREATE_INFO(overlay_paint_vertcol_clipped) @@ -129,8 +128,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_weight) .push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */ .push_constant(Type::BOOL, "drawContours") /* `false` by default. */ .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("paint_weight_vert.glsl") - .fragment_source("paint_weight_frag.glsl") + .vertex_source("overlay_paint_weight_vert.glsl") + .fragment_source("overlay_paint_weight_frag.glsl") .additional_info("draw_modelmat", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_paint_weight_fake_shading) @@ -162,14 +161,13 @@ GPU_SHADER_INTERFACE_INFO(overlay_paint_wire_iface, "").flat(Type::VEC4, "finalC GPU_SHADER_CREATE_INFO(overlay_paint_wire) .do_static_compilation(true) - .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */ .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::VEC4, "nor") /* flag stored in w */ .vertex_out(overlay_paint_wire_iface) .push_constant(Type::BOOL, "useSelect") .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("paint_wire_vert.glsl") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .vertex_source("overlay_paint_wire_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_modelmat", "draw_globals"); GPU_SHADER_CREATE_INFO(overlay_paint_wire_clipped) diff --git a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh index d4f1ca44362..3a53bd388a6 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh @@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_sculpt_mask) .vertex_in(1, Type::VEC3, "fset") .vertex_in(2, Type::FLOAT, "msk") .vertex_out(overlay_sculpt_mask_iface) - .vertex_source("sculpt_mask_vert.glsl") - .fragment_source("sculpt_mask_frag.glsl") + .vertex_source("overlay_sculpt_mask_vert.glsl") + .fragment_source("overlay_sculpt_mask_frag.glsl") .fragment_out(0, Type::VEC4, "fragColor") .additional_info("draw_mesh", "draw_object_infos", "draw_globals"); diff --git a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh index 5853e974eeb..3740b42ba26 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh @@ -10,8 +10,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_velocity_iface, "").smooth(Type::VEC4, GPU_SHADER_CREATE_INFO(overlay_volume_velocity) .do_static_compilation(true) - /* Colors are already in linear space. */ - .define("srgbTarget", "false") .sampler(0, ImageType::FLOAT_3D, "velocityX") .sampler(1, ImageType::FLOAT_3D, "velocityY") .sampler(2, ImageType::FLOAT_3D, "velocityZ") @@ -28,8 +26,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_velocity) .push_constant(Type::IVEC3, "adaptiveCellOffset") .vertex_out(overlay_volume_velocity_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("volume_velocity_vert.glsl") - .fragment_source("gpu_shader_3D_smooth_color_frag.glsl") + .vertex_source("overlay_volume_velocity_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_volume"); GPU_SHADER_CREATE_INFO(overlay_volume_velocity_mac) @@ -55,8 +53,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_gridlines_iface, "").flat(Type::VEC4, " GPU_SHADER_CREATE_INFO(overlay_volume_gridlines) .do_static_compilation(true) - /* Colors are already in linear space. */ - .define("srgbTarget", "false") .push_constant(Type::FLOAT, "slicePosition") .push_constant(Type::INT, "sliceAxis") /* FluidDomainSettings.res */ @@ -69,8 +65,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_gridlines) .push_constant(Type::IVEC3, "adaptiveCellOffset") .vertex_out(overlay_volume_gridlines_iface) .fragment_out(0, Type::VEC4, "fragColor") - .vertex_source("volume_gridlines_vert.glsl") - .fragment_source("gpu_shader_flat_color_frag.glsl") + .vertex_source("overlay_volume_gridlines_vert.glsl") + .fragment_source("overlay_varying_color.glsl") .additional_info("draw_volume"); GPU_SHADER_CREATE_INFO(overlay_volume_gridlines_flags) diff --git a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh index 16b59f6bb7d..1899b191741 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh @@ -23,8 +23,8 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe) .vertex_in(1, Type::VEC3, "nor") .vertex_in(2, Type::FLOAT, "wd") /* wire-data. */ .vertex_out(overlay_wireframe_iface) - .vertex_source("wireframe_vert.glsl") - .fragment_source("wireframe_frag.glsl") + .vertex_source("overlay_wireframe_vert.glsl") + .fragment_source("overlay_wireframe_frag.glsl") .fragment_out(0, Type::VEC4, "fragColor") .fragment_out(1, Type::VEC4, "lineOutput") .additional_info("draw_mesh", "draw_object_infos", "draw_globals"); diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl index f28a809fdab..f28a809fdab 100644 --- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl index d46abbf79ee..d46abbf79ee 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl index b3c9ce5dfd2..b3c9ce5dfd2 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl index 0a8e279e9b0..0a8e279e9b0 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl index a90d2e3e406..a90d2e3e406 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl index 2dd86a57dfd..2dd86a57dfd 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl index 47c5dada708..47c5dada708 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl index 29319b3f7ac..29319b3f7ac 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl index 8e1768846dc..8e1768846dc 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl index cdbe8c3d7df..cdbe8c3d7df 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl index cee86956c43..cee86956c43 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl index 31369e0c3df..31369e0c3df 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl index e60b6e94492..e60b6e94492 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl index abbaad8cd10..abbaad8cd10 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl index 2e42cdf0517..2e42cdf0517 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl index b5edcd2858b..b5edcd2858b 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl index 2c454a8becd..2c454a8becd 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl index c89d0249e4f..c89d0249e4f 100644 --- a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl index b25dcae9fca..b25dcae9fca 100644 --- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl index c065a66414f..c065a66414f 100644 --- a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl index 65aeb81a4ef..65aeb81a4ef 100644 --- a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl new file mode 100644 index 00000000000..59efdd8d538 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl @@ -0,0 +1,6 @@ + +void main() +{ + /* No color output, only depth (line below is implicit). */ + // gl_FragDepth = gl_FragCoord.z; +} diff --git a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl index d403890f44e..d403890f44e 100644 --- a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl index 7d92baea595..7d92baea595 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl index 186cc010f45..186cc010f45 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl index a30496177c3..a30496177c3 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl index 183df7e5450..183df7e5450 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl index 47d9439ed80..47d9439ed80 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl index a5091345539..a5091345539 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl index f5d6e89d016..f5d6e89d016 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl index 38ba80a981a..38ba80a981a 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl index 440dfdc1482..440dfdc1482 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl index 430ace8726a..430ace8726a 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl index 1e163dc9a9a..1e163dc9a9a 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl index 72b0a43cdb4..72b0a43cdb4 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl index 2fd155f715c..2fd155f715c 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl index 82f957b2071..82f957b2071 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl index 6ff8d0665d1..6ff8d0665d1 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl index f1fbdac7847..f1fbdac7847 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl index 166ac1a37b0..374fb50af75 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl @@ -1,7 +1,7 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) -#pragma BLENDER_REQUIRE(edit_mesh_common_lib.glsl) +#pragma BLENDER_REQUIRE(overlay_edit_mesh_common_lib.glsl) #ifdef EDGE /* Ugly but needed to keep the same vertex shader code for other passes. */ diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl index 956b27e948d..956b27e948d 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl index 6a92206d524..6a92206d524 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl index 9c0ce4ecc8a..a849cb5160a 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(common_overlay_lib.glsl) +#pragma BLENDER_REQUIRE(overlay_common_lib.glsl) /** * We want to know how much a pixel is covered by a line. diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl index ac8d33cd727..8b19f671139 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(common_overlay_lib.glsl) +#pragma BLENDER_REQUIRE(overlay_common_lib.glsl) void do_vertex( vec4 pos, float selection_fac, vec2 stipple_start, vec2 stipple_pos, float coord, vec2 offset) diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl index 23f1a44c321..23f1a44c321 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl index 280b31ea463..c0d4393f2da 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl @@ -5,6 +5,6 @@ void main() vec3 world_pos = point_object_to_world(vec3(au, 0.0)); gl_Position = point_world_to_ndc(world_pos); - finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorVertexSelect : vec4(colorWire.rgb, 1.0); + finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorFaceDot : vec4(colorWire.rgb, 1.0); gl_PointSize = pointSize; } diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl index 80ea6228675..80ea6228675 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl index a1392abbb92..a1392abbb92 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl index 7ecbb513265..7ecbb513265 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl index bb086e8d9f5..bb086e8d9f5 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl index bc5235b9cab..bc5235b9cab 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl index c0ea6aebe10..c0ea6aebe10 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl index 9f9b02ce19d..9f9b02ce19d 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl index bf29b2b057e..bf29b2b057e 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl index ff7aae523e7..ff7aae523e7 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl index 1eee7ab251b..1eee7ab251b 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl index d92b947ef89..d92b947ef89 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl index f283934816c..f283934816c 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl index de999c241c0..de999c241c0 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl index b2578970c9b..b2578970c9b 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl index f32e3a8564e..f32e3a8564e 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl index cd217021e8f..cd217021e8f 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl index 8208689d113..8208689d113 100644 --- a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl index d98caee6a25..d98caee6a25 100644 --- a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl index 37958319b44..37958319b44 100644 --- a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl index 25f4984f119..25f4984f119 100644 --- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl index b81f1a24358..b81f1a24358 100644 --- a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/image_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl index e0339507e0f..e0339507e0f 100644 --- a/source/blender/draw/engines/overlay/shaders/image_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl index 45cddb3610d..45cddb3610d 100644 --- a/source/blender/draw/engines/overlay/shaders/image_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl index 324d22501f9..324d22501f9 100644 --- a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl index 29346a44863..29346a44863 100644 --- a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl index bc74a436f5e..bc74a436f5e 100644 --- a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl index 5027525b9b3..5027525b9b3 100644 --- a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl index 472a589f441..472a589f441 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl index d1abd74a7b3..d1abd74a7b3 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl index 8a196620af9..8a196620af9 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl index b6d5cd96c12..b6d5cd96c12 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl index 4b1470e5723..4b1470e5723 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl index 371ff628c59..371ff628c59 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl index 1d0b08f51b2..1d0b08f51b2 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl index 22906bf1526..22906bf1526 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl index 8736b2a87db..8736b2a87db 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl index e5af0e7bd88..e5af0e7bd88 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl index f93d0050950..f93d0050950 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl index 193fabc65cb..193fabc65cb 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl index 650070dcfd5..650070dcfd5 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl index 1befe7506c4..1befe7506c4 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl index cff79d606d6..cff79d606d6 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl index 749cc92f082..749cc92f082 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl index a2bcca7b820..a2bcca7b820 100644 --- a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl index fb981a8167a..fb981a8167a 100644 --- a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl new file mode 100644 index 00000000000..b0da035ef09 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl @@ -0,0 +1,23 @@ + +void main() +{ + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + /* Round point with jaggy edges. */ + if (dist_squared > rad_squared) { + discard; + } + +#if defined(VERT) + fragColor = finalColor; + + float midStroke = 0.5 * rad_squared; + if (vertexCrease > 0.0 && dist_squared > midStroke) { + fragColor.rgb = mix(finalColor.rgb, colorEdgeCrease.rgb, vertexCrease); + } +#else + fragColor = finalColor; +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl new file mode 100644 index 00000000000..c0ea6aebe10 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl @@ -0,0 +1,27 @@ + +void main() +{ + float dist = length(gl_PointCoord - vec2(0.5)); + + /* transparent outside of point + * --- 0 --- + * smooth transition + * --- 1 --- + * pure outline color + * --- 2 --- + * smooth transition + * --- 3 --- + * pure fill color + * ... + * dist = 0 at center of point */ + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else { + fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist)); + } +} diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl index 9650af755c5..9650af755c5 100644 --- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl index 36c0e6a0acf..36c0e6a0acf 100644 --- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl new file mode 100644 index 00000000000..0a498471b46 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl @@ -0,0 +1,4 @@ +void main() +{ + fragColor = color; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl new file mode 100644 index 00000000000..a27e2849bb3 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl @@ -0,0 +1,4 @@ +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl index 11a04dddd2a..11a04dddd2a 100644 --- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl index a33d27676c3..a33d27676c3 100644 --- a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl index bc28d7a8a36..bc28d7a8a36 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl index 41bd7791dd7..41bd7791dd7 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl diff --git a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl index 9aa2fdc3796..9aa2fdc3796 100644 --- a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index fb20bde2f65..9eb35c25bf4 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -97,7 +97,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd, { const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR); if (use_single_drawcall) { - DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL); + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, ob->actcol, color_type, NULL); DRW_shgroup_call_sculpt(grp, ob, false, false); } else { @@ -323,7 +323,8 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, } } - if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR) { + if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR && + BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) { /* Force use of material color for sculpt. */ color_type = V3D_SHADING_MATERIAL_COLOR; } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 07105757b2c..fa4a1d93d3e 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -837,7 +837,7 @@ void DRW_render_viewport_size_set(const int size[2]); /** * Assume a valid GL context is bound (and that the gl_context_mutex has been acquired). * This function only setup DST and execute the given function. - * \warning similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl). + * \warning similar to DRW_render_to_image you cannot use default lists (`dfbl` & `dtxl`). */ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, struct Depsgraph *depsgraph, @@ -850,6 +850,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, void DRW_cache_restart(void); /* ViewLayers */ + void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); void **DRW_view_layer_engine_data_ensure_ex(struct ViewLayer *view_layer, DrawEngineType *engine_type, @@ -858,6 +859,7 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage)); /* DrawData */ + DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type); DrawData *DRW_drawdata_ensure(ID *id, DrawEngineType *engine_type, diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc index 714f1dbb3d1..3f187aef8e6 100644 --- a/source/blender/draw/intern/draw_attributes.cc +++ b/source/blender/draw/intern/draw_attributes.cc @@ -65,9 +65,10 @@ bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b) } DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs, - CustomDataType type, - int layer, - AttributeDomain domain) + const char *name, + const eCustomDataType type, + const int layer_index, + const eAttrDomain domain) { if (attrs->num_requests >= GPU_MAX_ATTR) { return nullptr; @@ -75,7 +76,8 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs, DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests]; req->cd_type = type; - req->layer_index = layer; + BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name)); + req->layer_index = layer_index; req->domain = domain; attrs->num_requests += 1; return req; @@ -84,9 +86,9 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs, bool drw_custom_data_match_attribute(const CustomData *custom_data, const char *name, int *r_layer_index, - int *r_type) + eCustomDataType *r_type) { - const int possible_attribute_types[7] = { + const eCustomDataType possible_attribute_types[7] = { CD_PROP_BOOL, CD_PROP_INT8, CD_PROP_INT32, @@ -97,7 +99,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data, }; for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) { - const int attr_type = possible_attribute_types[i]; + const eCustomDataType attr_type = possible_attribute_types[i]; int layer_index = CustomData_get_named_layer(custom_data, attr_type, name); if (layer_index == -1) { continue; diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h index 192ffa43337..b577c6c4162 100644 --- a/source/blender/draw/intern/draw_attributes.h +++ b/source/blender/draw/intern/draw_attributes.h @@ -25,9 +25,9 @@ extern "C" { #endif typedef struct DRW_AttributeRequest { - CustomDataType cd_type; + eCustomDataType cd_type; int layer_index; - AttributeDomain domain; + eAttrDomain domain; char attribute_name[64]; } DRW_AttributeRequest; @@ -46,14 +46,15 @@ void drw_attributes_merge(DRW_Attributes *dst, bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b); DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs, - CustomDataType type, - int layer, - AttributeDomain domain); + const char *name, + eCustomDataType data_type, + int layer_index, + eAttrDomain domain); bool drw_custom_data_match_attribute(const CustomData *custom_data, const char *name, int *r_layer_index, - int *r_type); + eCustomDataType *r_type); #ifdef __cplusplus } diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index fb074cc728e..f846251c66b 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -3410,3 +3410,35 @@ void DRW_batch_cache_free_old(Object *ob, int ctime) } /** \} */ + +void DRW_cdlayer_attr_aliases_add(GPUVertFormat *format, + const char *base_name, + const CustomData *UNUSED(data), + const CustomDataLayer *cl, + bool is_active_render, + bool is_active_layer) +{ + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = cl->name; + + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + + /* Attribute layer name. */ + BLI_snprintf(attr_name, sizeof(attr_name), "%s%s", base_name, attr_safe_name); + GPU_vertformat_alias_add(format, attr_name); + + /* Auto layer name. */ + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + GPU_vertformat_alias_add(format, attr_name); + + /* Active render layer name. */ + if (is_active_render) { + GPU_vertformat_alias_add(format, base_name); + } + + /* Active display layer name. */ + if (is_active_layer) { + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", base_name); + GPU_vertformat_alias_add(format, attr_name); + } +} diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.hh index ce3ad9923da..c7127d169e1 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.hh @@ -7,11 +7,13 @@ #pragma once -struct DRWSubdivCache; -struct MeshRenderData; -struct TaskGraph; +#include <algorithm> + +#include "BLI_utildefines.h" #include "DNA_customdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_view3d_enums.h" #include "BKE_attribute.h" #include "BKE_object.h" @@ -22,8 +24,12 @@ struct TaskGraph; #include "draw_attributes.h" +struct DRWSubdivCache; +struct MeshRenderData; +struct TaskGraph; + /* Vertex Group Selection and display options */ -typedef struct DRW_MeshWeightState { +struct DRW_MeshWeightState { int defgroup_active; int defgroup_len; @@ -31,13 +37,13 @@ typedef struct DRW_MeshWeightState { char alert_mode; /* Set of all selected bones for Multi-paint. */ - bool *defgroup_sel; /* [defgroup_len] */ + bool *defgroup_sel; /* #defgroup_len */ int defgroup_sel_count; /* Set of all locked and unlocked deform bones for Lock Relative mode. */ - bool *defgroup_locked; /* [defgroup_len] */ - bool *defgroup_unlocked; /* [defgroup_len] */ -} DRW_MeshWeightState; + bool *defgroup_locked; /* #defgroup_len */ + bool *defgroup_unlocked; /* #defgroup_len */ +}; /* DRW_MeshWeightState.flags */ enum { @@ -46,30 +52,32 @@ enum { DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE = (1 << 2), }; -typedef struct DRW_MeshCDMask { +struct DRW_MeshCDMask { uint32_t uv : 8; uint32_t tan : 8; uint32_t vcol : 8; uint32_t orco : 1; uint32_t tan_orco : 1; uint32_t sculpt_overlays : 1; - /** Edit uv layer is from the base edit mesh as - * modifiers could remove it. (see T68857) */ + /** + * Edit uv layer is from the base edit mesh as modifiers could remove it. (see T68857) + */ uint32_t edit_uv : 1; -} DRW_MeshCDMask; -/* Keep `DRW_MeshCDMask` struct within an `uint32_t`. +}; +/* Keep `DRW_MeshCDMask` struct within a `uint32_t`. * bit-wise and atomic operations are used to compare and update the struct. * See `mesh_cd_layers_type_*` functions. */ BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits") -typedef enum eMRIterType { + +enum eMRIterType { MR_ITER_LOOPTRI = 1 << 0, MR_ITER_POLY = 1 << 1, MR_ITER_LEDGE = 1 << 2, MR_ITER_LVERT = 1 << 3, -} eMRIterType; +}; ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT) -typedef enum eMRDataType { +enum eMRDataType { MR_DATA_NONE = 0, MR_DATA_POLY_NOR = 1 << 1, MR_DATA_LOOP_NOR = 1 << 2, @@ -78,29 +86,24 @@ typedef enum eMRDataType { /** Force loop normals calculation. */ MR_DATA_TAN_LOOP_NOR = 1 << 5, MR_DATA_POLYS_SORTED = 1 << 6, -} eMRDataType; +}; ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED) -#ifdef __cplusplus -extern "C" { -#endif - BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me) { if (me->edit_mesh != NULL) { const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); if (editmesh_eval_final != NULL) { - return MAX2(1, editmesh_eval_final->totcol); + return std::max<int>(1, editmesh_eval_final->totcol); } } - return MAX2(1, me->totcol); + return std::max<int>(1, me->totcol); } -typedef struct MeshBufferList { - /* Every VBO below contains at least enough - * data for every loops in the mesh (except fdots and skin roots). - * For some VBOs, it extends to (in this exact order) : - * loops + loose_edges*2 + loose_verts */ +struct MeshBufferList { + /* Every VBO below contains at least enough data for every loop in the mesh + * (except fdots and skin roots). For some VBOs, it extends to (in this exact order) : + * loops + loose_edges * 2 + loose_verts */ struct { GPUVertBuf *pos_nor; /* extend */ GPUVertBuf *lnor; /* extend */ @@ -133,14 +136,17 @@ typedef struct MeshBufferList { /* Index Buffers: * Only need to be updated when topology changes. */ struct { - /* Indices to vloops. */ - GPUIndexBuf *tris; /* Ordered per material. */ - GPUIndexBuf *lines; /* Loose edges last. */ - GPUIndexBuf *lines_loose; /* sub buffer of `lines` only containing the loose edges. */ + /* Indices to vloops. Ordered per material. */ + GPUIndexBuf *tris; + /* Loose edges last. */ + GPUIndexBuf *lines; + /* Sub buffer of `lines` only containing the loose edges. */ + GPUIndexBuf *lines_loose; GPUIndexBuf *points; GPUIndexBuf *fdots; /* 3D overlays. */ - GPUIndexBuf *lines_paint_mask; /* no loose edges. */ + /* no loose edges. */ + GPUIndexBuf *lines_paint_mask; GPUIndexBuf *lines_adjacency; /* Uv overlays. (visibility can differ from 3D view) */ GPUIndexBuf *edituv_tris; @@ -148,9 +154,9 @@ typedef struct MeshBufferList { GPUIndexBuf *edituv_points; GPUIndexBuf *edituv_fdots; } ibo; -} MeshBufferList; +}; -typedef struct MeshBatchList { +struct MeshBatchList { /* Surfaces / Render */ GPUBatch *surface; GPUBatch *surface_weights; @@ -180,19 +186,22 @@ typedef struct MeshBatchList { GPUBatch *all_edges; GPUBatch *loose_edges; GPUBatch *edge_detection; - GPUBatch *wire_edges; /* Individual edges with face normals. */ - GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */ - GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */ + /* Individual edges with face normals. */ + GPUBatch *wire_edges; + /* Loops around faces. no edges between selected faces */ + GPUBatch *wire_loops; + /* Same as wire_loops but only has uvs. */ + GPUBatch *wire_loops_uvs; GPUBatch *sculpt_overlays; -} MeshBatchList; +}; #define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *)) -#define MBC_VBO_LEN (sizeof(((MeshBufferList){0}).vbo) / sizeof(void *)) -#define MBC_IBO_LEN (sizeof(((MeshBufferList){0}).ibo) / sizeof(void *)) +#define MBC_VBO_LEN (sizeof(MeshBufferList::vbo) / sizeof(void *)) +#define MBC_IBO_LEN (sizeof(MeshBufferList::ibo) / sizeof(void *)) #define MBC_BATCH_INDEX(batch) (offsetof(MeshBatchList, batch) / sizeof(void *)) -typedef enum DRWBatchFlag { +enum DRWBatchFlag { MBC_SURFACE = (1u << MBC_BATCH_INDEX(surface)), MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(surface_weights)), MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(edit_triangles)), @@ -221,23 +230,25 @@ typedef enum DRWBatchFlag { MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)), MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)), MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)), -} DRWBatchFlag; + MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN), +}; +ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT); BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields"); -typedef struct MeshExtractLooseGeom { +struct MeshExtractLooseGeom { int edge_len; int vert_len; int *verts; int *edges; -} MeshExtractLooseGeom; +}; /** * Data that are kept around between extractions to reduce rebuilding time. * * - Loose geometry. */ -typedef struct MeshBufferCache { +struct MeshBufferCache { MeshBufferList buff; MeshExtractLooseGeom loose_geom; @@ -247,7 +258,7 @@ typedef struct MeshBufferCache { int *mat_tri_len; int visible_tri_len; } poly_sorted; -} MeshBufferCache; +}; #define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \ for (MeshBufferCache *mbc = &batch_cache->final; \ @@ -256,7 +267,7 @@ typedef struct MeshBufferCache { &batch_cache->cage : \ ((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL)) -typedef struct MeshBatchCache { +struct MeshBatchCache { MeshBufferCache final, cage, uv_cage; MeshBatchList batch; @@ -266,22 +277,23 @@ typedef struct MeshBatchCache { GPUBatch **surface_per_mat; - struct DRWSubdivCache *subdiv_cache; + DRWSubdivCache *subdiv_cache; - DRWBatchFlag batch_requested; /* DRWBatchFlag */ - DRWBatchFlag batch_ready; /* DRWBatchFlag */ + DRWBatchFlag batch_requested; + DRWBatchFlag batch_ready; - /* settings to determine if cache is invalid */ + /* Settings to determine if cache is invalid. */ int edge_len; int tri_len; int poly_len; int vert_len; int mat_len; - bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ + /* Instantly invalidates cache, skipping mesh check */ + bool is_dirty; bool is_editmode; bool is_uvsyncsel; - struct DRW_MeshWeightState weight_state; + DRW_MeshWeightState weight_state; DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time; @@ -302,13 +314,15 @@ typedef struct MeshBatchCache { eV3DShadingColorType color_type; bool pbvh_is_drawing; -} MeshBatchCache; +}; #define MBC_EDITUV \ (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \ MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS) -void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, +namespace blender::draw { + +void mesh_buffer_cache_create_requested(TaskGraph *task_graph, MeshBatchCache *cache, MeshBufferCache *mbc, Object *object, @@ -320,14 +334,12 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, bool do_final, bool do_uvedit, const Scene *scene, - const struct ToolSettings *ts, + const ToolSettings *ts, bool use_hide); void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, MeshBufferCache *mbc, - struct DRWSubdivCache *subdiv_cache, - struct MeshRenderData *mr); + DRWSubdivCache *subdiv_cache, + MeshRenderData *mr); -#ifdef __cplusplus -} -#endif +} // namespace blender::draw diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 3d44d3d1b3f..380736ef656 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -24,11 +24,11 @@ #include "GPU_capabilities.h" -#include "draw_cache_extract.h" +#include "draw_cache_extract.hh" #include "draw_cache_inline.h" #include "draw_subdivision.h" -#include "mesh_extractors/extract_mesh.h" +#include "mesh_extractors/extract_mesh.hh" // #define DEBUG_TIME @@ -155,7 +155,7 @@ struct ExtractTaskData { bool use_threading = false; ExtractTaskData(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, ExtractorRunDatas *extractors, MeshBufferList *mbuflist, const bool use_threading) @@ -193,7 +193,7 @@ static void extract_task_data_free(void *data) * \{ */ BLI_INLINE void extract_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, ExtractorRunDatas &extractors, MeshBufferList *mbuflist, void *data_stack) @@ -209,7 +209,7 @@ BLI_INLINE void extract_init(const MeshRenderData *mr, } BLI_INLINE void extract_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, const ExtractorRunDatas &extractors, void *data_stack) { @@ -551,21 +551,21 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t /** \name Extract Loop * \{ */ -static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache *mbc, - Object *object, - Mesh *me, - - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const Scene *scene, - const ToolSettings *ts, - const bool use_hide) +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, + MeshBufferCache *mbc, + Object *object, + Mesh *me, + + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const Scene *scene, + const ToolSettings *ts, + const bool use_hide) { /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. * This sub-graph starts with an extract_render_data_node. This fills/converts the required @@ -772,10 +772,10 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, /** \name Subdivision Extract Loop * \{ */ -static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, - MeshBufferCache *mbc, - DRWSubdivCache *subdiv_cache, - MeshRenderData *mr) +void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, + MeshBufferCache *mbc, + DRWSubdivCache *subdiv_cache, + MeshRenderData *mr) { /* Create an array containing all the extractors that needs to be executed. */ ExtractorRunDatas extractors; @@ -908,46 +908,3 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, /** \} */ } // namespace blender::draw - -extern "C" { -void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache *mbc, - Object *object, - Mesh *me, - - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const Scene *scene, - const ToolSettings *ts, - const bool use_hide) -{ - blender::draw::mesh_buffer_cache_create_requested(task_graph, - cache, - mbc, - object, - me, - is_editmode, - is_paint_mode, - is_mode_active, - obmat, - do_final, - do_uvedit, - scene, - ts, - use_hide); -} - -void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, - MeshBufferCache *mbc, - DRWSubdivCache *subdiv_cache, - MeshRenderData *mr) -{ - blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, mr); -} - -} // extern "C" diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index 0a93f346b37..77cbb5efa12 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_task.h" @@ -22,7 +22,7 @@ #include "ED_mesh.h" -#include "mesh_extractors/extract_mesh.h" +#include "mesh_extractors/extract_mesh.hh" /* ---------------------------------------------------------------------- */ /** \name Update Loose Geometry @@ -78,7 +78,8 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe { BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); - cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__); + cache->loose_geom.edges = static_cast<int *>( + MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__)); const MEdge *med = mr->medge; for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { if (med->flag & ME_LOOSEEDGE) { @@ -89,19 +90,20 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe BLI_BITMAP_ENABLE(lvert_map, med->v2); } if (cache->loose_geom.edge_len < mr->edge_len) { - cache->loose_geom.edges = MEM_reallocN( - cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)); + cache->loose_geom.edges = static_cast<int *>(MEM_reallocN( + cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges))); } - cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__); + cache->loose_geom.verts = static_cast<int *>( + MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__)); for (int v = 0; v < mr->vert_len; v++) { if (!BLI_BITMAP_TEST(lvert_map, v)) { cache->loose_geom.verts[cache->loose_geom.vert_len++] = v; } } if (cache->loose_geom.vert_len < mr->vert_len) { - cache->loose_geom.verts = MEM_reallocN( - cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)); + cache->loose_geom.verts = static_cast<int *>(MEM_reallocN( + cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts))); } MEM_freeN(lvert_map); @@ -112,15 +114,16 @@ static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache int elem_id; BMIter iter; BMVert *eve; - cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__); + cache->loose_geom.verts = static_cast<int *>( + MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__)); BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) { - if (eve->e == NULL) { + if (eve->e == nullptr) { cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id; } } if (cache->loose_geom.vert_len < mr->vert_len) { - cache->loose_geom.verts = MEM_reallocN( - cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)); + cache->loose_geom.verts = static_cast<int *>(MEM_reallocN( + cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts))); } } @@ -129,15 +132,16 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache int elem_id; BMIter iter; BMEdge *ede; - cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__); + cache->loose_geom.edges = static_cast<int *>( + MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__)); BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) { - if (ede->l == NULL) { + if (ede->l == nullptr) { cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id; } } if (cache->loose_geom.edge_len < mr->edge_len) { - cache->loose_geom.edges = MEM_reallocN( - cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)); + cache->loose_geom.edges = static_cast<int *>(MEM_reallocN( + cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges))); } } @@ -192,12 +196,13 @@ static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferC static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache) { - int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__); + int *tri_first_index = static_cast<int *>( + MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__)); int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr); /* Apply offset. */ int visible_tri_len = 0; - int *mat_tri_offs = BLI_array_alloca(mat_tri_offs, mr->mat_len); + blender::Array<int, 32> mat_tri_offs(mr->mat_len); { for (int i = 0; i < mr->mat_len; i++) { mat_tri_offs[i] = visible_tri_len; @@ -245,8 +250,8 @@ static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls) { - MeshRenderData *mr = userdata; - int *mat_tri_len = tls->userdata_chunk; + MeshRenderData *mr = static_cast<MeshRenderData *>(userdata); + int *mat_tri_len = static_cast<int *>(tls->userdata_chunk); BMesh *bm = mr->bm; BMFace *efa = BM_face_at_index(bm, iter); @@ -260,8 +265,8 @@ static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata const int iter, const TaskParallelTLS *__restrict tls) { - MeshRenderData *mr = userdata; - int *mat_tri_len = tls->userdata_chunk; + MeshRenderData *mr = static_cast<MeshRenderData *>(userdata); + int *mat_tri_len = static_cast<int *>(tls->userdata_chunk); const MPoly *mp = &mr->mpoly[iter]; if (!(mr->use_hide && (mp->flag & ME_HIDE))) { @@ -274,9 +279,9 @@ static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userda void *__restrict chunk_join, void *__restrict chunk) { - const MeshRenderData *mr = userdata; - int *dst_mat_len = chunk_join; - int *src_mat_len = chunk; + const MeshRenderData *mr = static_cast<const MeshRenderData *>(userdata); + int *dst_mat_len = static_cast<int *>(chunk_join); + int *src_mat_len = static_cast<int *>(chunk); for (int i = 0; i < mr->mat_len; i++) { dst_mat_len[i] += src_mat_len[i]; } @@ -288,7 +293,7 @@ static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr, { /* Extending the #MatOffsetUserData with an int per material slot. */ size_t mat_tri_len_size = sizeof(int) * mr->mat_len; - int *mat_tri_len = MEM_callocN(mat_tri_len_size, __func__); + int *mat_tri_len = static_cast<int *>(MEM_callocN(mat_tri_len_size, __func__)); TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); @@ -330,8 +335,9 @@ void mesh_render_data_update_looptris(MeshRenderData *mr, /* NOTE(campbell): It's possible to skip allocating tessellation, * the tessellation can be calculated as part of the iterator, see: P2188. * The overall advantage is small (around 1%), so keep this as-is. */ - mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"); - if (mr->poly_normals != NULL) { + mr->mlooptri = static_cast<MLoopTri *>( + MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI")); + if (mr->poly_normals != nullptr) { BKE_mesh_recalc_looptri_with_normals(me->mloop, me->mpoly, me->mvert, @@ -350,7 +356,7 @@ void mesh_render_data_update_looptris(MeshRenderData *mr, /* #BMesh */ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { /* Edit mode ensures this is valid, no need to calculate. */ - BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); + BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != nullptr)); } } } @@ -368,8 +374,10 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ mr->poly_normals = BKE_mesh_poly_normals_ensure(mr->me); } if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); - short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL); + mr->loop_normals = static_cast<float(*)[3]>( + MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__)); + short(*clnors)[2] = static_cast<short(*)[2]>( + CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL)); BKE_mesh_normals_loop_split(mr->me->mvert, mr->vert_normals, mr->vert_len, @@ -383,9 +391,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ mr->poly_len, is_auto_smooth, split_angle, - NULL, + nullptr, clnors, - NULL); + nullptr); } } else { @@ -395,9 +403,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ } if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - const float(*vert_coords)[3] = NULL; - const float(*vert_normals)[3] = NULL; - const float(*poly_normals)[3] = NULL; + const float(*vert_coords)[3] = nullptr; + const float(*vert_normals)[3] = nullptr; + const float(*poly_normals)[3] = nullptr; if (mr->edit_data && mr->edit_data->vertexCos) { vert_coords = mr->bm_vert_coords; @@ -405,7 +413,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ poly_normals = mr->bm_poly_normals; } - mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); + mr->loop_normals = static_cast<float(*)[3]>( + MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__)); const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(mr->bm, vert_coords, @@ -414,8 +423,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ is_auto_smooth, split_angle, mr->loop_normals, - NULL, - NULL, + nullptr, + nullptr, clnors_offset, false); } @@ -432,7 +441,7 @@ MeshRenderData *mesh_render_data_create(Object *object, const bool do_uvedit, const ToolSettings *ts) { - MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__); + MeshRenderData *mr = static_cast<MeshRenderData *>(MEM_callocN(sizeof(*mr), __func__)); mr->toolsettings = ts; mr->mat_len = mesh_render_mat_len_get(object, me); @@ -446,7 +455,7 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->bm = me->edit_mesh->bm; mr->edit_bmesh = me->edit_mesh; mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage; - mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL; + mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : nullptr; if (mr->edit_data) { EditMeshData *emd = mr->edit_data; @@ -491,9 +500,12 @@ MeshRenderData *mesh_render_data_create(Object *object, #endif if (use_mapped) { - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + 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); } @@ -502,20 +514,23 @@ MeshRenderData *mesh_render_data_create(Object *object, /* 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; + if (use_mapped && do_final && editmesh_eval_final != editmesh_eval_cage) { + // mr->edit_bmesh = nullptr; mr->extract_type = MR_EXTRACT_MESH; } } else { mr->me = me; - mr->edit_bmesh = NULL; + mr->edit_bmesh = nullptr; bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original; if (use_mapped) { - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + 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); } @@ -531,14 +546,14 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->poly_len = mr->me->totpoly; mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); - mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT); - mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE); - mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP); - mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY); + mr->mvert = static_cast<MVert *>(CustomData_get_layer(&mr->me->vdata, CD_MVERT)); + mr->medge = static_cast<MEdge *>(CustomData_get_layer(&mr->me->edata, CD_MEDGE)); + mr->mloop = static_cast<MLoop *>(CustomData_get_layer(&mr->me->ldata, CD_MLOOP)); + mr->mpoly = static_cast<MPoly *>(CustomData_get_layer(&mr->me->pdata, CD_MPOLY)); - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + 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 { /* #BMesh */ @@ -560,8 +575,8 @@ void mesh_render_data_free(MeshRenderData *mr) MEM_SAFE_FREE(mr->loop_normals); /* Loose geometry are owned by #MeshBufferCache. */ - mr->ledges = NULL; - mr->lverts = NULL; + mr->ledges = nullptr; + mr->lverts = nullptr; MEM_freeN(mr); } diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 0755d5967d5..4fa5813d476 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -156,11 +156,15 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt); /** \} */ /* -------------------------------------------------------------------- */ -/** \name Hair +/** \name Curves * \{ */ int DRW_curves_material_count_get(struct Curves *curves); +struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves); + +void DRW_curves_batch_cache_create_requested(struct Object *ob); + /** \} */ /* -------------------------------------------------------------------- */ @@ -352,16 +356,6 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *ob /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Curves - * \{ */ - -struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves); - -void DRW_curves_batch_cache_create_requested(const struct Object *ob); - -/** \} */ - #ifdef __cplusplus } #endif diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index f9cf0021fcd..6e098e0310d 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -52,11 +52,14 @@ struct CurvesBatchCache { GPUBatch *edit_points; - /* To determine if cache is invalid. */ + /* Whether the cache is invalid. */ bool is_dirty; - /** Needed when updating material data (e.g. attributes) as the same curves might be used for - * multiple objects with different materials. */ + /** + * The draw cache extraction is currently not multi-threaded for multiple objects, but if it was, + * some locking would be necessary because multiple objects can use the same curves data with + * different materials, etc. This is a placeholder to make multi-threading easier in the future. + */ ThreadMutex render_mutex; }; @@ -84,13 +87,13 @@ static void curves_batch_cache_init(Curves &curves) static void curves_discard_attributes(CurvesEvalCache &curves_cache) { - for (int i = 0; i < GPU_MAX_ATTR; i++) { + for (const int i : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]); DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]); } - for (int i = 0; i < MAX_HAIR_SUBDIV; i++) { - for (int j = 0; j < GPU_MAX_ATTR; j++) { + for (const int i : IndexRange(MAX_HAIR_SUBDIV)) { + for (const int j : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]); DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]); } @@ -112,10 +115,10 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache) DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex); DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex); - for (int i = 0; i < MAX_HAIR_SUBDIV; i++) { + for (const int i : IndexRange(MAX_HAIR_SUBDIV)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf); DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex); - for (int j = 0; j < MAX_THICKRES; j++) { + for (const int j : IndexRange(MAX_THICKRES)) { GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]); } } @@ -160,7 +163,7 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode) cache->is_dirty = true; break; default: - BLI_assert(0); + BLI_assert_unreachable(); } } @@ -181,7 +184,7 @@ void DRW_curves_batch_cache_free_old(Curves *curves, int ctime) bool do_discard = false; - for (int i = 0; i < MAX_HAIR_SUBDIV; i++) { + for (const int i : IndexRange(MAX_HAIR_SUBDIV)) { CurvesEvalFinalCache &final_cache = cache->curves_cache.final[i]; if (drw_attributes_overlap(&final_cache.attr_used_over_time, &final_cache.attr_used)) { @@ -255,7 +258,7 @@ static void curves_batch_cache_fill_segments_proc_pos( } } -static void curves_batch_cache_ensure_procedural_pos(Curves &curves, +static void curves_batch_cache_ensure_procedural_pos(const Curves &curves, CurvesEvalCache &cache, GPUMaterial *gpu_material) { @@ -308,8 +311,11 @@ void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sample BLI_snprintf(r_sampler_name, 32, "a%s", attr_safe_name); } -static void curves_batch_cache_ensure_procedural_final_attr( - CurvesEvalCache &cache, GPUVertFormat *format, int subdiv, int index, const char *name) +static void curves_batch_cache_ensure_procedural_final_attr(CurvesEvalCache &cache, + const GPUVertFormat *format, + const int subdiv, + const int index, + const char *name) { CurvesEvalFinalCache &final_cache = cache.final[subdiv]; final_cache.attributes_buf[index] = GPU_vertbuf_create_with_format_ex(format, @@ -330,8 +336,8 @@ static void curves_batch_cache_ensure_procedural_final_attr( static void curves_batch_ensure_attribute(const Curves &curves, CurvesEvalCache &cache, const DRW_AttributeRequest &request, - int subdiv, - int index) + const int subdiv, + const int index) { GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]); DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]); @@ -512,48 +518,28 @@ static bool curves_ensure_attributes(const Curves &curves, ListBase gpu_attrs = GPU_material_attributes(gpu_material); LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { const char *name = gpu_attr->name; - int type = gpu_attr->type; - int layer = -1; - AttributeDomain domain; - if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) { + int layer_index; + eCustomDataType type; + eAttrDomain domain; + if (drw_custom_data_match_attribute(cd_curve, name, &layer_index, &type)) { domain = ATTR_DOMAIN_CURVE; } - else if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) { + else if (drw_custom_data_match_attribute(cd_point, name, &layer_index, &type)) { domain = ATTR_DOMAIN_POINT; } else { continue; } - switch (type) { - default: - break; - case CD_PROP_BOOL: - case CD_PROP_INT8: - case CD_PROP_INT32: - case CD_PROP_FLOAT: - case CD_PROP_FLOAT2: - case CD_PROP_FLOAT3: - case CD_PROP_COLOR: { - if (layer != -1) { - DRW_AttributeRequest *req = drw_attributes_add_request( - &attrs_needed, (CustomDataType)type, layer, domain); - if (req) { - BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name)); - } - } - break; - } - } + drw_attributes_add_request(&attrs_needed, name, type, layer_index, domain); } CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv]; - const bool attr_overlap = drw_attributes_overlap(&final_cache.attr_used, &attrs_needed); - if (attr_overlap == false) { + if (!drw_attributes_overlap(&final_cache.attr_used, &attrs_needed)) { /* Some new attributes have been added, free all and start over. */ - for (int i = 0; i < GPU_MAX_ATTR; i++) { + for (const int i : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]); DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]); } @@ -563,7 +549,7 @@ static bool curves_ensure_attributes(const Curves &curves, bool need_tf_update = false; - for (int i = 0; i < final_cache.attr_used.num_requests; i++) { + for (const int i : IndexRange(final_cache.attr_used.num_requests)) { const DRW_AttributeRequest &request = final_cache.attr_used.requests[i]; if (cache.curves_cache.proc_attributes_buf[i] != nullptr) { @@ -580,16 +566,15 @@ static bool curves_ensure_attributes(const Curves &curves, return need_tf_update; } -bool curves_ensure_procedural_data(Object *object, +bool curves_ensure_procedural_data(Curves *curves, CurvesEvalCache **r_hair_cache, GPUMaterial *gpu_material, const int subdiv, const int thickness_res) { bool need_ft_update = false; - Curves &curves = *static_cast<Curves *>(object->data); - CurvesBatchCache &cache = curves_batch_cache_get(curves); + CurvesBatchCache &cache = curves_batch_cache_get(*curves); *r_hair_cache = &cache.curves_cache; const int steps = 3; /* TODO: don't hard-code? */ @@ -597,14 +582,14 @@ bool curves_ensure_procedural_data(Object *object, /* Refreshed on combing and simulation. */ if ((*r_hair_cache)->proc_point_buf == nullptr) { - ensure_seg_pt_count(curves, cache.curves_cache); - curves_batch_cache_ensure_procedural_pos(curves, cache.curves_cache, gpu_material); + ensure_seg_pt_count(*curves, cache.curves_cache); + curves_batch_cache_ensure_procedural_pos(*curves, cache.curves_cache, gpu_material); need_ft_update = true; } /* Refreshed if active layer or custom data changes. */ if ((*r_hair_cache)->strand_tex == nullptr) { - curves_batch_cache_ensure_procedural_strand_data(curves, cache.curves_cache); + curves_batch_cache_ensure_procedural_strand_data(*curves, cache.curves_cache); } /* Refreshed only on subdiv count change. */ @@ -614,11 +599,11 @@ bool curves_ensure_procedural_data(Object *object, } if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) { curves_batch_cache_ensure_procedural_indices( - curves, cache.curves_cache, thickness_res, subdiv); + *curves, cache.curves_cache, thickness_res, subdiv); } if (gpu_material) { - need_ft_update |= curves_ensure_attributes(curves, cache, gpu_material, subdiv); + need_ft_update |= curves_ensure_attributes(*curves, cache, gpu_material, subdiv); } return need_ft_update; @@ -635,7 +620,7 @@ GPUBatch *DRW_curves_batch_cache_get_edit_points(Curves *curves) return DRW_batch_request(&cache.edit_points); } -void DRW_curves_batch_cache_create_requested(const Object *ob) +void DRW_curves_batch_cache_create_requested(Object *ob) { Curves *curves = static_cast<Curves *>(ob->data); CurvesBatchCache &cache = curves_batch_cache_get(*curves); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.cc index a6ab2176d16..e93b1a66b66 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -7,15 +7,19 @@ * \brief Mesh API for render engines */ +#include <optional> + #include "MEM_guardedalloc.h" -#include "BLI_alloca.h" #include "BLI_bitmap.h" #include "BLI_buffer.h" #include "BLI_edgehash.h" +#include "BLI_index_range.hh" #include "BLI_listbase.h" +#include "BLI_map.hh" #include "BLI_math_bits.h" #include "BLI_math_vector.h" +#include "BLI_span.hh" #include "BLI_string.h" #include "BLI_task.h" #include "BLI_utildefines.h" @@ -52,13 +56,17 @@ #include "ED_mesh.h" #include "ED_uvedit.h" -#include "draw_cache_extract.h" +#include "draw_cache_extract.hh" #include "draw_cache_inline.h" #include "draw_subdivision.h" #include "draw_cache_impl.h" /* own include */ -#include "mesh_extractors/extract_mesh.h" +#include "mesh_extractors/extract_mesh.hh" + +using blender::IndexRange; +using blender::Map; +using blender::Span; /* ---------------------------------------------------------------------- */ /** \name Dependencies between buffer and batch @@ -69,21 +77,7 @@ #define BUFFER_INDEX(buff_name) ((offsetof(MeshBufferList, buff_name) - offsetof(MeshBufferList, vbo)) / sizeof(void *)) #define BUFFER_LEN (sizeof(MeshBufferList) / sizeof(void *)) -#define _BATCH_FLAG1(b) (1u << MBC_BATCH_INDEX(b)) -#define _BATCH_FLAG2(b1, b2) _BATCH_FLAG1(b1) | _BATCH_FLAG1(b2) -#define _BATCH_FLAG3(b1, b2, b3) _BATCH_FLAG2(b1, b2) | _BATCH_FLAG1(b3) -#define _BATCH_FLAG4(b1, b2, b3, b4) _BATCH_FLAG3(b1, b2, b3) | _BATCH_FLAG1(b4) -#define _BATCH_FLAG5(b1, b2, b3, b4, b5) _BATCH_FLAG4(b1, b2, b3, b4) | _BATCH_FLAG1(b5) -#define _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) _BATCH_FLAG5(b1, b2, b3, b4, b5) | _BATCH_FLAG1(b6) -#define _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) | _BATCH_FLAG1(b7) -#define _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) | _BATCH_FLAG1(b8) -#define _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) | _BATCH_FLAG1(b9) -#define _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _BATCH_FLAG1(b10) -#define _BATCH_FLAG18(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18) _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _BATCH_FLAG8(b11, b12, b13, b14, b15, b16, b17, b18) - -#define BATCH_FLAG(...) VA_NARGS_CALL_OVERLOAD(_BATCH_FLAG, __VA_ARGS__) - -#define _BATCH_MAP1(a) g_buffer_deps[BUFFER_INDEX(a)] +#define _BATCH_MAP1(a) batches_that_use_buffer(BUFFER_INDEX(a)) #define _BATCH_MAP2(a, b) _BATCH_MAP1(a) | _BATCH_MAP1(b) #define _BATCH_MAP3(a, b, c) _BATCH_MAP2(a, b) | _BATCH_MAP1(c) #define _BATCH_MAP4(a, b, c, d) _BATCH_MAP3(a, b, c) | _BATCH_MAP1(d) @@ -96,132 +90,110 @@ #define BATCH_MAP(...) VA_NARGS_CALL_OVERLOAD(_BATCH_MAP, __VA_ARGS__) -#ifndef NDEBUG -# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) \ - g_buffer_deps_d[buffer_index] |= batch_flag; \ - BLI_assert(g_buffer_deps[buffer_index] & batch_flag) - -# define _MDEPS_ASSERT2(b, n1) MDEPS_ASSERT_INDEX(BUFFER_INDEX(n1), b) -# define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2) -# define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3) -# define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4) -# define _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5) _MDEPS_ASSERT5(b, n1, n2, n3, n4); _MDEPS_ASSERT2(b, n5) -# define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6) -# define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7) -# define _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20) _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7); _MDEPS_ASSERT8(b, n8, n9, n10, n11, n12, n13, n14); _MDEPS_ASSERT7(b, n15, n16, n17, n18, n19, n20) -# define _MDEPS_ASSERT22(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21) _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20); _MDEPS_ASSERT2(b, n21); - -# define MDEPS_ASSERT_FLAG(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__) -# define MDEPS_ASSERT(batch_name, ...) MDEPS_ASSERT_FLAG(BATCH_FLAG(batch_name), __VA_ARGS__) -# define MDEPS_ASSERT_MAP_INDEX(buff_index) BLI_assert(g_buffer_deps_d[buff_index] == g_buffer_deps[buff_index]) -# define MDEPS_ASSERT_MAP(buff_name) MDEPS_ASSERT_MAP_INDEX(BUFFER_INDEX(buff_name)) -#else -# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) -# define MDEPS_ASSERT_FLAG(...) -# define MDEPS_ASSERT(batch_name, ...) -# define MDEPS_ASSERT_MAP_INDEX(buff_index) -# define MDEPS_ASSERT_MAP(buff_name) -#endif - /* clang-format on */ #define TRIS_PER_MAT_INDEX BUFFER_LEN -#define SURFACE_PER_MAT_FLAG (1u << MBC_BATCH_LEN) - -static const DRWBatchFlag g_buffer_deps[] = { - [BUFFER_INDEX(vbo.pos_nor)] = BATCH_FLAG(surface, - surface_weights, - edit_triangles, - edit_vertices, - edit_edges, - edit_vnor, - edit_lnor, - edit_mesh_analysis, - edit_selection_verts, - edit_selection_edges, - edit_selection_faces, - all_verts, - all_edges, - loose_edges, - edge_detection, - wire_edges, - wire_loops, - sculpt_overlays) | - SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.lnor)] = BATCH_FLAG(surface, edit_lnor, wire_loops) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.edge_fac)] = BATCH_FLAG(wire_edges), - [BUFFER_INDEX(vbo.weights)] = BATCH_FLAG(surface_weights), - [BUFFER_INDEX(vbo.uv)] = BATCH_FLAG(surface, - edituv_faces_stretch_area, - edituv_faces_stretch_angle, - edituv_faces, - edituv_edges, - edituv_verts, - wire_loops_uvs) | - SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.tan)] = SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.vcol)] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.sculpt_data)] = BATCH_FLAG(sculpt_overlays), - [BUFFER_INDEX(vbo.orco)] = SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.edit_data)] = BATCH_FLAG(edit_triangles, edit_edges, edit_vertices), - [BUFFER_INDEX(vbo.edituv_data)] = BATCH_FLAG(edituv_faces, - edituv_faces_stretch_area, - edituv_faces_stretch_angle, - edituv_edges, - edituv_verts), - [BUFFER_INDEX(vbo.edituv_stretch_area)] = BATCH_FLAG(edituv_faces_stretch_area), - [BUFFER_INDEX(vbo.edituv_stretch_angle)] = BATCH_FLAG(edituv_faces_stretch_angle), - [BUFFER_INDEX(vbo.mesh_analysis)] = BATCH_FLAG(edit_mesh_analysis), - [BUFFER_INDEX(vbo.fdots_pos)] = BATCH_FLAG(edit_fdots, edit_selection_fdots), - [BUFFER_INDEX(vbo.fdots_nor)] = BATCH_FLAG(edit_fdots), - [BUFFER_INDEX(vbo.fdots_uv)] = BATCH_FLAG(edituv_fdots), - [BUFFER_INDEX(vbo.fdots_edituv_data)] = BATCH_FLAG(edituv_fdots), - [BUFFER_INDEX(vbo.skin_roots)] = BATCH_FLAG(edit_skin_roots), - [BUFFER_INDEX(vbo.vert_idx)] = BATCH_FLAG(edit_selection_verts), - [BUFFER_INDEX(vbo.edge_idx)] = BATCH_FLAG(edit_selection_edges), - [BUFFER_INDEX(vbo.poly_idx)] = BATCH_FLAG(edit_selection_faces), - [BUFFER_INDEX(vbo.fdot_idx)] = BATCH_FLAG(edit_selection_fdots), - [BUFFER_INDEX(vbo.attr) + 0] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 1] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 2] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 3] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 4] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 5] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 6] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 7] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 8] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 9] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 10] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 11] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 12] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 13] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - [BUFFER_INDEX(vbo.attr) + 14] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, - - [BUFFER_INDEX(ibo.tris)] = BATCH_FLAG(surface, - surface_weights, - edit_triangles, - edit_lnor, - edit_mesh_analysis, - edit_selection_faces, - sculpt_overlays), - [BUFFER_INDEX(ibo.lines)] = BATCH_FLAG( - edit_edges, edit_selection_edges, all_edges, wire_edges), - [BUFFER_INDEX(ibo.lines_loose)] = BATCH_FLAG(loose_edges), - [BUFFER_INDEX(ibo.points)] = BATCH_FLAG(edit_vnor, edit_vertices, edit_selection_verts), - [BUFFER_INDEX(ibo.fdots)] = BATCH_FLAG(edit_fdots, edit_selection_fdots), - [BUFFER_INDEX(ibo.lines_paint_mask)] = BATCH_FLAG(wire_loops), - [BUFFER_INDEX(ibo.lines_adjacency)] = BATCH_FLAG(edge_detection), - [BUFFER_INDEX(ibo.edituv_tris)] = BATCH_FLAG( - edituv_faces, edituv_faces_stretch_area, edituv_faces_stretch_angle), - [BUFFER_INDEX(ibo.edituv_lines)] = BATCH_FLAG(edituv_edges, wire_loops_uvs), - [BUFFER_INDEX(ibo.edituv_points)] = BATCH_FLAG(edituv_verts), - [BUFFER_INDEX(ibo.edituv_fdots)] = BATCH_FLAG(edituv_fdots), - [TRIS_PER_MAT_INDEX] = SURFACE_PER_MAT_FLAG, -}; - -#ifndef NDEBUG -static DRWBatchFlag g_buffer_deps_d[ARRAY_SIZE(g_buffer_deps)] = {0}; -#endif + +static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index) +{ + switch (buffer_index) { + case BUFFER_INDEX(vbo.pos_nor): + return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES | + MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS | + MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES | + MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION | + MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.lnor): + return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.edge_fac): + return MBC_WIRE_EDGES; + case BUFFER_INDEX(vbo.weights): + return MBC_SURFACE_WEIGHTS; + case BUFFER_INDEX(vbo.uv): + return MBC_SURFACE | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | + MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_WIRE_LOOPS_UVS | + MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.tan): + return MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.vcol): + return MBC_SURFACE | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.sculpt_data): + return MBC_SCULPT_OVERLAYS; + case BUFFER_INDEX(vbo.orco): + return MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.edit_data): + return MBC_EDIT_TRIANGLES | MBC_EDIT_EDGES | MBC_EDIT_VERTICES; + case BUFFER_INDEX(vbo.edituv_data): + return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | + MBC_EDITUV_EDGES | MBC_EDITUV_VERTS; + case BUFFER_INDEX(vbo.edituv_stretch_area): + return MBC_EDITUV_FACES_STRETCH_AREA; + case BUFFER_INDEX(vbo.edituv_stretch_angle): + return MBC_EDITUV_FACES_STRETCH_ANGLE; + case BUFFER_INDEX(vbo.mesh_analysis): + return MBC_EDIT_MESH_ANALYSIS; + case BUFFER_INDEX(vbo.fdots_pos): + return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS; + case BUFFER_INDEX(vbo.fdots_nor): + return MBC_EDIT_FACEDOTS; + case BUFFER_INDEX(vbo.fdots_uv): + return MBC_EDITUV_FACEDOTS; + case BUFFER_INDEX(vbo.fdots_edituv_data): + return MBC_EDITUV_FACEDOTS; + case BUFFER_INDEX(vbo.skin_roots): + return MBC_SKIN_ROOTS; + case BUFFER_INDEX(vbo.vert_idx): + return MBC_EDIT_SELECTION_VERTS; + case BUFFER_INDEX(vbo.edge_idx): + return MBC_EDIT_SELECTION_EDGES; + case BUFFER_INDEX(vbo.poly_idx): + return MBC_EDIT_SELECTION_FACES; + case BUFFER_INDEX(vbo.fdot_idx): + return MBC_EDIT_SELECTION_FACEDOTS; + case BUFFER_INDEX(vbo.attr[0]): + case BUFFER_INDEX(vbo.attr[1]): + case BUFFER_INDEX(vbo.attr[2]): + case BUFFER_INDEX(vbo.attr[3]): + case BUFFER_INDEX(vbo.attr[4]): + case BUFFER_INDEX(vbo.attr[5]): + case BUFFER_INDEX(vbo.attr[6]): + case BUFFER_INDEX(vbo.attr[7]): + case BUFFER_INDEX(vbo.attr[8]): + case BUFFER_INDEX(vbo.attr[9]): + case BUFFER_INDEX(vbo.attr[10]): + case BUFFER_INDEX(vbo.attr[11]): + case BUFFER_INDEX(vbo.attr[12]): + case BUFFER_INDEX(vbo.attr[13]): + case BUFFER_INDEX(vbo.attr[14]): + return MBC_SURFACE | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(ibo.tris): + return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | + MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS; + case BUFFER_INDEX(ibo.lines): + return MBC_EDIT_EDGES | MBC_EDIT_SELECTION_EDGES | MBC_ALL_EDGES | MBC_WIRE_EDGES; + case BUFFER_INDEX(ibo.lines_loose): + return MBC_LOOSE_EDGES; + case BUFFER_INDEX(ibo.points): + return MBC_EDIT_VNOR | MBC_EDIT_VERTICES | MBC_EDIT_SELECTION_VERTS; + case BUFFER_INDEX(ibo.fdots): + return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS; + case BUFFER_INDEX(ibo.lines_paint_mask): + return MBC_WIRE_LOOPS; + case BUFFER_INDEX(ibo.lines_adjacency): + return MBC_EDGE_DETECTION; + case BUFFER_INDEX(ibo.edituv_tris): + return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE; + case BUFFER_INDEX(ibo.edituv_lines): + return MBC_EDITUV_EDGES | MBC_WIRE_LOOPS_UVS; + case BUFFER_INDEX(ibo.edituv_points): + return MBC_EDITUV_VERTS; + case BUFFER_INDEX(ibo.edituv_fdots): + return MBC_EDITUV_FACEDOTS; + case TRIS_PER_MAT_INDEX: + return MBC_SURFACE_PER_MAT; + } + return (DRWBatchFlag)0; +} static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache); static void mesh_batch_cache_clear(Mesh *me); @@ -229,14 +201,14 @@ static void mesh_batch_cache_clear(Mesh *me); static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatchFlag batch_map) { for (int i = 0; i < MBC_BATCH_LEN; i++) { - DRWBatchFlag batch_requested = (1u << i); + DRWBatchFlag batch_requested = (DRWBatchFlag)(1u << i); if (batch_map & batch_requested) { GPU_BATCH_DISCARD_SAFE(((GPUBatch **)&cache->batch)[i]); cache->batch_ready &= ~batch_requested; } } - if (batch_map & SURFACE_PER_MAT_FLAG) { + if (batch_map & MBC_SURFACE_PER_MAT) { mesh_batch_cache_discard_surface_batches(cache); } } @@ -266,9 +238,9 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a) BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me) { - if (me->edit_mesh != NULL) { + if (me->edit_mesh != nullptr) { Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); - if (editmesh_eval_final != NULL) { + if (editmesh_eval_final != nullptr) { return editmesh_eval_final; } } @@ -374,14 +346,15 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object, DRW_MeshCDMask *cd_used) { const Mesh *me_final = editmesh_final_or_this(object, me); - Mesh me_query = {0}; + Mesh me_query = blender::dna::shallow_zero_initialize(); const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); - BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id); + BKE_id_attribute_copy_domains_temp( + ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id); - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id); int layer_i = BKE_id_attribute_to_index( &me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); @@ -395,8 +368,8 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query, const CustomData *cd_ldata, const char name[]) { - CustomDataLayer *layer = NULL; - AttributeDomain domain; + const CustomDataLayer *layer = nullptr; + eAttrDomain domain; if (name[0]) { int layer_i = 0; @@ -451,10 +424,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, /* Create a mesh with final customdata domains * we can query with attribute API. */ - Mesh me_query = {0}; + Mesh me_query = blender::dna::shallow_zero_initialize(); BKE_id_attribute_copy_domains_temp( - ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, NULL, &me_query.id); + ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, nullptr, &me_query.id); /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -466,10 +439,9 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, ListBase gpu_attrs = GPU_material_attributes(gpumat); LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { const char *name = gpu_attr->name; - int type = gpu_attr->type; + eCustomDataType type = static_cast<eCustomDataType>(gpu_attr->type); int layer = -1; - /* ATTR_DOMAIN_NUM is standard for "invalid value". */ - AttributeDomain domain = ATTR_DOMAIN_NUM; + std::optional<eAttrDomain> domain; if (type == CD_AUTO_FROM_NAME) { /* We need to deduce what exact layer is used. @@ -535,7 +507,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, } else { layer = -1; - domain = ATTR_DOMAIN_NUM; } } @@ -602,8 +573,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, break; } - if (layer != -1 && domain != ATTR_DOMAIN_NUM) { - drw_attributes_add_request(attributes, type, layer, domain); + if (layer != -1 && domain.has_value()) { + drw_attributes_add_request(attributes, name, type, layer, *domain); } break; } @@ -613,11 +584,13 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, case CD_PROP_INT32: case CD_PROP_FLOAT: case CD_PROP_FLOAT2: { - if (layer != -1 && domain != ATTR_DOMAIN_NUM) { - drw_attributes_add_request(attributes, type, layer, domain); + if (layer != -1 && domain.has_value()) { + drw_attributes_add_request(attributes, name, type, layer, *domain); } break; } + default: + break; } } } @@ -654,13 +627,14 @@ static void drw_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, memcpy(wstate_dst, wstate_src, sizeof(*wstate_dst)); if (wstate_src->defgroup_sel) { - wstate_dst->defgroup_sel = MEM_dupallocN(wstate_src->defgroup_sel); + wstate_dst->defgroup_sel = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_sel)); } if (wstate_src->defgroup_locked) { - wstate_dst->defgroup_locked = MEM_dupallocN(wstate_src->defgroup_locked); + wstate_dst->defgroup_locked = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_locked)); } if (wstate_src->defgroup_unlocked) { - wstate_dst->defgroup_unlocked = MEM_dupallocN(wstate_src->defgroup_unlocked); + wstate_dst->defgroup_unlocked = static_cast<bool *>( + MEM_dupallocN(wstate_src->defgroup_unlocked)); } } @@ -764,14 +738,15 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag static bool mesh_batch_cache_valid(Object *object, Mesh *me) { - MeshBatchCache *cache = me->runtime.batch_cache; + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); - if (cache == NULL) { + if (cache == nullptr) { return false; } if (object->sculpt && object->sculpt->pbvh) { - if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) { + if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh) || + BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) { return false; } @@ -781,7 +756,7 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me) } } - if (cache->is_editmode != (me->edit_mesh != NULL)) { + if (cache->is_editmode != (me->edit_mesh != nullptr)) { return false; } @@ -798,16 +773,17 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me) static void mesh_batch_cache_init(Object *object, Mesh *me) { - MeshBatchCache *cache = me->runtime.batch_cache; + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); if (!cache) { - cache = me->runtime.batch_cache = MEM_callocN(sizeof(*cache), __func__); + me->runtime.batch_cache = MEM_cnew<MeshBatchCache>(__func__); + cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); } else { memset(cache, 0, sizeof(*cache)); } - cache->is_editmode = me->edit_mesh != NULL; + cache->is_editmode = me->edit_mesh != nullptr; if (object->sculpt && object->sculpt->pbvh) { cache->pbvh_is_drawing = BKE_pbvh_is_drawing(object->sculpt->pbvh); @@ -821,12 +797,14 @@ static void mesh_batch_cache_init(Object *object, Mesh *me) } cache->mat_len = mesh_render_mat_len_get(object, me); - cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__); - cache->tris_per_mat = MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__); + cache->surface_per_mat = static_cast<GPUBatch **>( + MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__)); + cache->tris_per_mat = static_cast<GPUIndexBuf **>( + MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__)); cache->is_dirty = false; - cache->batch_ready = 0; - cache->batch_requested = 0; + cache->batch_ready = (DRWBatchFlag)0; + cache->batch_requested = (DRWBatchFlag)0; drw_mesh_weight_state_clear(&cache->weight_state); } @@ -841,7 +819,7 @@ void DRW_mesh_batch_cache_validate(Object *object, Mesh *me) static MeshBatchCache *mesh_batch_cache_get(Mesh *me) { - return me->runtime.batch_cache; + return static_cast<MeshBatchCache *>(me->runtime.batch_cache); } static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, @@ -950,8 +928,8 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) { - MeshBatchCache *cache = me->runtime.batch_cache; - if (cache == NULL) { + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); + if (cache == nullptr) { return; } DRWBatchFlag batch_map; @@ -1032,13 +1010,13 @@ static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache) if (cache->subdiv_cache) { draw_subdiv_cache_free(cache->subdiv_cache); MEM_freeN(cache->subdiv_cache); - cache->subdiv_cache = NULL; + cache->subdiv_cache = nullptr; } } static void mesh_batch_cache_clear(Mesh *me) { - MeshBatchCache *cache = me->runtime.batch_cache; + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); if (!cache) { return; } @@ -1061,7 +1039,7 @@ static void mesh_batch_cache_clear(Mesh *me) MEM_SAFE_FREE(cache->surface_per_mat); cache->mat_len = 0; - cache->batch_ready = 0; + cache->batch_ready = (DRWBatchFlag)0; drw_mesh_weight_state_clear(&cache->weight_state); mesh_batch_cache_free_subdiv_cache(cache); @@ -1110,11 +1088,12 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final); const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); - Mesh me_query = {0}; - BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id); + Mesh me_query = blender::dna::shallow_zero_initialize(); + BKE_id_attribute_copy_domains_temp( + ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id); - CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id); - CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id); + const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id); + const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id); int active_i = BKE_id_attribute_to_index( &me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); @@ -1157,7 +1136,7 @@ GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me) MeshBatchCache *cache = mesh_batch_cache_get(me); mesh_batch_cache_add_request(cache, MBC_LOOSE_EDGES); if (cache->no_loose_wire) { - return NULL; + return nullptr; } return DRW_batch_request(&cache->batch.loose_edges); @@ -1276,7 +1255,7 @@ GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ mesh_batch_cache_request_surface_batches(cache); - DRW_vbo_request(NULL, &cache->final.buff.vbo.pos_nor); + DRW_vbo_request(nullptr, &cache->final.buff.vbo.pos_nor); return cache->final.buff.vbo.pos_nor; } @@ -1398,10 +1377,10 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object, edituv_request_active_uv(cache, object, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA); - if (tot_area != NULL) { + if (tot_area != nullptr) { *tot_area = &cache->tot_area; } - if (tot_uv_area != NULL) { + if (tot_uv_area != nullptr) { *tot_uv_area = &cache->tot_uv_area; } return DRW_batch_request(&cache->batch.edituv_faces_stretch_area); @@ -1471,9 +1450,9 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me) void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) { - MeshBatchCache *cache = me->runtime.batch_cache; + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); - if (cache == NULL) { + if (cache == nullptr) { return; } @@ -1513,7 +1492,7 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M * happening in release builds). */ BLI_task_graph_work_and_wait(task_graph); for (int i = 0; i < MBC_BATCH_LEN; i++) { - BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); + BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], (GPUPrimType)0)); } for (int i = 0; i < MBC_VBO_LEN; i++) { BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.buff.vbo)[i])); @@ -1544,7 +1523,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, const bool use_hide) { BLI_assert(task_graph); - const ToolSettings *ts = NULL; + const ToolSettings *ts = nullptr; if (scene) { ts = scene->toolsettings; } @@ -1559,24 +1538,43 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, return; } +#ifdef DEBUG + /* Map the index of a buffer to a flag containing all batches that use it. */ + Map<int, DRWBatchFlag> batches_that_use_buffer_local; + + auto assert_deps_valid = [&](DRWBatchFlag batch_flag, Span<int> used_buffer_indices) { + for (const int buffer_index : used_buffer_indices) { + batches_that_use_buffer_local.add_or_modify( + buffer_index, + [&](DRWBatchFlag *value) { *value = batch_flag; }, + [&](DRWBatchFlag *value) { *value |= batch_flag; }); + BLI_assert(batches_that_use_buffer(buffer_index) & batch_flag); + } + }; +#else + auto assert_deps_valid = [&](DRWBatchFlag UNUSED(batch_flag), + Span<int> UNUSED(used_buffer_indices)) {}; + +#endif + /* Sanity check. */ - if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) { - BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL); + if ((me->edit_mesh != nullptr) && (ob->mode & OB_MODE_EDIT)) { + BLI_assert(BKE_object_get_editmesh_eval_final(ob) != nullptr); } - const bool is_editmode = (me->edit_mesh != NULL) && - (BKE_object_get_editmesh_eval_final(ob) != NULL) && + const bool is_editmode = (me->edit_mesh != nullptr) && + (BKE_object_get_editmesh_eval_final(ob) != nullptr) && DRW_object_is_in_edit_mode(ob); /* This could be set for paint mode too, currently it's only used for edit-mode. */ const bool is_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob); DRWBatchFlag batch_requested = cache->batch_requested; - cache->batch_requested = 0; + cache->batch_requested = (DRWBatchFlag)0; if (batch_requested & MBC_SURFACE_WEIGHTS) { /* Check vertex weights. */ - if ((cache->batch.surface_weights != NULL) && (ts != NULL)) { + if ((cache->batch.surface_weights != nullptr) && (ts != nullptr)) { struct DRW_MeshWeightState wstate; BLI_assert(ob->type == OB_MESH); drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate); @@ -1593,7 +1591,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (cache->cd_needed.orco != 0) { /* Orco is always extracted from final mesh. */ Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me; - if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) { + if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == nullptr) { /* Skip orco calculation */ cache->cd_needed.orco = 0; } @@ -1692,7 +1690,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, * per redraw when smooth shading is enabled. */ const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh; if (do_update_sculpt_normals) { - Mesh *mesh = ob->data; + Mesh *mesh = static_cast<Mesh *>(ob->data); BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg); } @@ -1712,27 +1710,15 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, MeshBufferList *mbuflist = &cache->final.buff; /* Initialize batches and request VBO's & IBO's. */ - MDEPS_ASSERT(surface, - ibo.tris, - vbo.lnor, - vbo.pos_nor, - vbo.uv, - vbo.vcol, - vbo.attr[0], - vbo.attr[1], - vbo.attr[2], - vbo.attr[3], - vbo.attr[4], - vbo.attr[5], - vbo.attr[6], - vbo.attr[7], - vbo.attr[8], - vbo.attr[9], - vbo.attr[10], - vbo.attr[11], - vbo.attr[12], - vbo.attr[13], - vbo.attr[14]); + assert_deps_valid( + MBC_SURFACE, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), + BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.attr[0]), + BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]), + BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]), + BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), BUFFER_INDEX(vbo.attr[9]), + BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), BUFFER_INDEX(vbo.attr[12]), + BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])}); if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris); /* Order matters. First ones override latest VBO's attributes. */ @@ -1746,52 +1732,61 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, } drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used); } - MDEPS_ASSERT(all_verts, vbo.pos_nor); + assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos_nor)}); if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) { DRW_vbo_request(cache->batch.all_verts, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(sculpt_overlays, ibo.tris, vbo.pos_nor, vbo.sculpt_data); + assert_deps_valid( + MBC_SCULPT_OVERLAYS, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.sculpt_data)}); if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.sculpt_overlays, &mbuflist->ibo.tris); DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.sculpt_data); } - MDEPS_ASSERT(all_edges, ibo.lines, vbo.pos_nor); + assert_deps_valid(MBC_ALL_EDGES, {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor)}); if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.all_edges, &mbuflist->ibo.lines); DRW_vbo_request(cache->batch.all_edges, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(loose_edges, ibo.lines_loose, vbo.pos_nor); + assert_deps_valid(MBC_LOOSE_EDGES, {BUFFER_INDEX(ibo.lines_loose), BUFFER_INDEX(vbo.pos_nor)}); if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(NULL, &mbuflist->ibo.lines); + DRW_ibo_request(nullptr, &mbuflist->ibo.lines); DRW_ibo_request(cache->batch.loose_edges, &mbuflist->ibo.lines_loose); DRW_vbo_request(cache->batch.loose_edges, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(edge_detection, ibo.lines_adjacency, vbo.pos_nor); + assert_deps_valid(MBC_EDGE_DETECTION, + {BUFFER_INDEX(ibo.lines_adjacency), BUFFER_INDEX(vbo.pos_nor)}); if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) { DRW_ibo_request(cache->batch.edge_detection, &mbuflist->ibo.lines_adjacency); DRW_vbo_request(cache->batch.edge_detection, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(surface_weights, ibo.tris, vbo.pos_nor, vbo.weights); + assert_deps_valid( + MBC_SURFACE_WEIGHTS, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.weights)}); if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.surface_weights, &mbuflist->ibo.tris); DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.weights); } - MDEPS_ASSERT(wire_loops, ibo.lines_paint_mask, vbo.lnor, vbo.pos_nor); + assert_deps_valid( + MBC_WIRE_LOOPS, + {BUFFER_INDEX(ibo.lines_paint_mask), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor)}); if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.wire_loops, &mbuflist->ibo.lines_paint_mask); /* Order matters. First ones override latest VBO's attributes. */ DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.lnor); DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(wire_edges, ibo.lines, vbo.pos_nor, vbo.edge_fac); + assert_deps_valid( + MBC_WIRE_EDGES, + {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_fac)}); if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.wire_edges, &mbuflist->ibo.lines); DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.edge_fac); } - MDEPS_ASSERT(wire_loops_uvs, ibo.edituv_lines, vbo.uv); + assert_deps_valid(MBC_WIRE_LOOPS_UVS, {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv)}); if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.wire_loops_uvs, &mbuflist->ibo.edituv_lines); /* For paint overlay. Active layer should have been queried. */ @@ -1799,7 +1794,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, DRW_vbo_request(cache->batch.wire_loops_uvs, &mbuflist->vbo.uv); } } - MDEPS_ASSERT(edit_mesh_analysis, ibo.tris, vbo.pos_nor, vbo.mesh_analysis); + assert_deps_valid( + MBC_EDIT_MESH_ANALYSIS, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.mesh_analysis)}); if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbuflist->ibo.tris); DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor); @@ -1807,29 +1804,16 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, } /* Per Material */ - MDEPS_ASSERT_FLAG(SURFACE_PER_MAT_FLAG, - vbo.lnor, - vbo.pos_nor, - vbo.uv, - vbo.tan, - vbo.vcol, - vbo.orco, - vbo.attr[0], - vbo.attr[1], - vbo.attr[2], - vbo.attr[3], - vbo.attr[4], - vbo.attr[5], - vbo.attr[6], - vbo.attr[7], - vbo.attr[8], - vbo.attr[9], - vbo.attr[10], - vbo.attr[11], - vbo.attr[12], - vbo.attr[13], - vbo.attr[14]); - MDEPS_ASSERT_INDEX(TRIS_PER_MAT_INDEX, SURFACE_PER_MAT_FLAG); + assert_deps_valid( + MBC_SURFACE_PER_MAT, + {BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.uv), + BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.orco), + BUFFER_INDEX(vbo.attr[0]), BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), + BUFFER_INDEX(vbo.attr[3]), BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), + BUFFER_INDEX(vbo.attr[6]), BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), + BUFFER_INDEX(vbo.attr[9]), BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), + BUFFER_INDEX(vbo.attr[12]), BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])}); + assert_deps_valid(MBC_SURFACE_PER_MAT, {TRIS_PER_MAT_INDEX}); for (int i = 0; i < cache->mat_len; i++) { if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) { DRW_ibo_request(cache->surface_per_mat[i], &cache->tris_per_mat[i]); @@ -1855,66 +1839,83 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mbuflist = (do_cage) ? &cache->cage.buff : &cache->final.buff; /* Edit Mesh */ - MDEPS_ASSERT(edit_triangles, ibo.tris, vbo.pos_nor, vbo.edit_data); + assert_deps_valid( + MBC_EDIT_TRIANGLES, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)}); if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.edit_triangles, &mbuflist->ibo.tris); DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.edit_data); } - MDEPS_ASSERT(edit_vertices, ibo.points, vbo.pos_nor, vbo.edit_data); + assert_deps_valid( + MBC_EDIT_VERTICES, + {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)}); if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edit_vertices, &mbuflist->ibo.points); DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.edit_data); } - MDEPS_ASSERT(edit_edges, ibo.lines, vbo.pos_nor, vbo.edit_data); + assert_deps_valid( + MBC_EDIT_EDGES, + {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)}); if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.edit_edges, &mbuflist->ibo.lines); DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.edit_data); } - MDEPS_ASSERT(edit_vnor, ibo.points, vbo.pos_nor); + assert_deps_valid(MBC_EDIT_VNOR, {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor)}); if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edit_vnor, &mbuflist->ibo.points); DRW_vbo_request(cache->batch.edit_vnor, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(edit_lnor, ibo.tris, vbo.pos_nor, vbo.lnor); + assert_deps_valid(MBC_EDIT_LNOR, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.lnor)}); if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edit_lnor, &mbuflist->ibo.tris); DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.lnor); } - MDEPS_ASSERT(edit_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdots_nor); + assert_deps_valid( + MBC_EDIT_FACEDOTS, + {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdots_nor)}); if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edit_fdots, &mbuflist->ibo.fdots); DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_pos); DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_nor); } - MDEPS_ASSERT(edit_skin_roots, vbo.skin_roots); + assert_deps_valid(MBC_SKIN_ROOTS, {BUFFER_INDEX(vbo.skin_roots)}); if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) { DRW_vbo_request(cache->batch.edit_skin_roots, &mbuflist->vbo.skin_roots); } /* Selection */ - MDEPS_ASSERT(edit_selection_verts, ibo.points, vbo.pos_nor, vbo.vert_idx); + assert_deps_valid( + MBC_EDIT_SELECTION_VERTS, + {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.vert_idx)}); if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edit_selection_verts, &mbuflist->ibo.points); DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.vert_idx); } - MDEPS_ASSERT(edit_selection_edges, ibo.lines, vbo.pos_nor, vbo.edge_idx); + assert_deps_valid( + MBC_EDIT_SELECTION_EDGES, + {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_idx)}); if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.edit_selection_edges, &mbuflist->ibo.lines); DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.edge_idx); } - MDEPS_ASSERT(edit_selection_faces, ibo.tris, vbo.pos_nor, vbo.poly_idx); + assert_deps_valid( + MBC_EDIT_SELECTION_FACES, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.poly_idx)}); if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.edit_selection_faces, &mbuflist->ibo.tris); DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.pos_nor); DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.poly_idx); } - MDEPS_ASSERT(edit_selection_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdot_idx); + assert_deps_valid( + MBC_EDIT_SELECTION_FACEDOTS, + {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdot_idx)}); if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edit_selection_fdots, &mbuflist->ibo.fdots); DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdots_pos); @@ -1929,131 +1930,145 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mbuflist = (do_uvcage) ? &cache->uv_cage.buff : &cache->final.buff; /* Edit UV */ - MDEPS_ASSERT(edituv_faces, ibo.edituv_tris, vbo.uv, vbo.edituv_data); + assert_deps_valid( + MBC_EDITUV_FACES, + {BUFFER_INDEX(ibo.edituv_tris), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)}); if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.edituv_faces, &mbuflist->ibo.edituv_tris); DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.uv); DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.edituv_data); } - MDEPS_ASSERT(edituv_faces_stretch_area, - ibo.edituv_tris, - vbo.uv, - vbo.edituv_data, - vbo.edituv_stretch_area); + assert_deps_valid(MBC_EDITUV_FACES_STRETCH_AREA, + {BUFFER_INDEX(ibo.edituv_tris), + BUFFER_INDEX(vbo.uv), + BUFFER_INDEX(vbo.edituv_data), + BUFFER_INDEX(vbo.edituv_stretch_area)}); if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->ibo.edituv_tris); DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.uv); DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_data); DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_stretch_area); } - MDEPS_ASSERT(edituv_faces_stretch_angle, - ibo.edituv_tris, - vbo.uv, - vbo.edituv_data, - vbo.edituv_stretch_angle); + assert_deps_valid(MBC_EDITUV_FACES_STRETCH_ANGLE, + {BUFFER_INDEX(ibo.edituv_tris), + BUFFER_INDEX(vbo.uv), + BUFFER_INDEX(vbo.edituv_data), + BUFFER_INDEX(vbo.edituv_stretch_angle)}); if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) { DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->ibo.edituv_tris); DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.uv); DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_data); DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_stretch_angle); } - MDEPS_ASSERT(edituv_edges, ibo.edituv_lines, vbo.uv, vbo.edituv_data); + assert_deps_valid( + MBC_EDITUV_EDGES, + {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)}); if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.edituv_edges, &mbuflist->ibo.edituv_lines); DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.uv); DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.edituv_data); } - MDEPS_ASSERT(edituv_verts, ibo.edituv_points, vbo.uv, vbo.edituv_data); + assert_deps_valid( + MBC_EDITUV_VERTS, + {BUFFER_INDEX(ibo.edituv_points), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)}); if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edituv_verts, &mbuflist->ibo.edituv_points); DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.uv); DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.edituv_data); } - MDEPS_ASSERT(edituv_fdots, ibo.edituv_fdots, vbo.fdots_uv, vbo.fdots_edituv_data); + assert_deps_valid(MBC_EDITUV_FACEDOTS, + {BUFFER_INDEX(ibo.edituv_fdots), + BUFFER_INDEX(vbo.fdots_uv), + BUFFER_INDEX(vbo.fdots_edituv_data)}); if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) { DRW_ibo_request(cache->batch.edituv_fdots, &mbuflist->ibo.edituv_fdots); DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv); DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data); } - MDEPS_ASSERT_MAP(vbo.lnor); - MDEPS_ASSERT_MAP(vbo.pos_nor); - MDEPS_ASSERT_MAP(vbo.uv); - MDEPS_ASSERT_MAP(vbo.vcol); - MDEPS_ASSERT_MAP(vbo.sculpt_data); - MDEPS_ASSERT_MAP(vbo.weights); - MDEPS_ASSERT_MAP(vbo.edge_fac); - MDEPS_ASSERT_MAP(vbo.mesh_analysis); - MDEPS_ASSERT_MAP(vbo.tan); - MDEPS_ASSERT_MAP(vbo.orco); - MDEPS_ASSERT_MAP(vbo.edit_data); - MDEPS_ASSERT_MAP(vbo.fdots_pos); - MDEPS_ASSERT_MAP(vbo.fdots_nor); - MDEPS_ASSERT_MAP(vbo.skin_roots); - MDEPS_ASSERT_MAP(vbo.vert_idx); - MDEPS_ASSERT_MAP(vbo.edge_idx); - MDEPS_ASSERT_MAP(vbo.poly_idx); - MDEPS_ASSERT_MAP(vbo.fdot_idx); - MDEPS_ASSERT_MAP(vbo.edituv_data); - MDEPS_ASSERT_MAP(vbo.edituv_stretch_area); - MDEPS_ASSERT_MAP(vbo.edituv_stretch_angle); - MDEPS_ASSERT_MAP(vbo.fdots_uv); - MDEPS_ASSERT_MAP(vbo.fdots_edituv_data); - for (int i = 0; i < GPU_MAX_ATTR; i++) { - MDEPS_ASSERT_MAP(vbo.attr[i]); - } - - MDEPS_ASSERT_MAP(ibo.tris); - MDEPS_ASSERT_MAP(ibo.lines); - MDEPS_ASSERT_MAP(ibo.lines_loose); - MDEPS_ASSERT_MAP(ibo.lines_adjacency); - MDEPS_ASSERT_MAP(ibo.lines_paint_mask); - MDEPS_ASSERT_MAP(ibo.points); - MDEPS_ASSERT_MAP(ibo.fdots); - MDEPS_ASSERT_MAP(ibo.edituv_tris); - MDEPS_ASSERT_MAP(ibo.edituv_lines); - MDEPS_ASSERT_MAP(ibo.edituv_points); - MDEPS_ASSERT_MAP(ibo.edituv_fdots); - - MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX); +#ifdef DEBUG + auto assert_final_deps_valid = [&](const int buffer_index) { + BLI_assert(batches_that_use_buffer(buffer_index) == + batches_that_use_buffer_local.lookup(buffer_index)); + }; + assert_final_deps_valid(BUFFER_INDEX(vbo.lnor)); + assert_final_deps_valid(BUFFER_INDEX(vbo.pos_nor)); + assert_final_deps_valid(BUFFER_INDEX(vbo.uv)); + assert_final_deps_valid(BUFFER_INDEX(vbo.vcol)); + assert_final_deps_valid(BUFFER_INDEX(vbo.sculpt_data)); + assert_final_deps_valid(BUFFER_INDEX(vbo.weights)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edge_fac)); + assert_final_deps_valid(BUFFER_INDEX(vbo.mesh_analysis)); + assert_final_deps_valid(BUFFER_INDEX(vbo.tan)); + assert_final_deps_valid(BUFFER_INDEX(vbo.orco)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edit_data)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_pos)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_nor)); + assert_final_deps_valid(BUFFER_INDEX(vbo.skin_roots)); + assert_final_deps_valid(BUFFER_INDEX(vbo.vert_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edge_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.poly_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdot_idx)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_data)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_area)); + assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_angle)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_uv)); + assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_edituv_data)); + for (const int i : IndexRange(GPU_MAX_ATTR)) { + assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i])); + } + + assert_final_deps_valid(BUFFER_INDEX(ibo.tris)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines_loose)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines_adjacency)); + assert_final_deps_valid(BUFFER_INDEX(ibo.lines_paint_mask)); + assert_final_deps_valid(BUFFER_INDEX(ibo.points)); + assert_final_deps_valid(BUFFER_INDEX(ibo.fdots)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_tris)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_lines)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_points)); + assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_fdots)); + + assert_final_deps_valid(TRIS_PER_MAT_INDEX); +#endif if (do_uvcage) { - mesh_buffer_cache_create_requested(task_graph, - cache, - &cache->uv_cage, - ob, - me, - is_editmode, - is_paint_mode, - is_mode_active, - ob->obmat, - false, - true, - scene, - ts, - true); + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + &cache->uv_cage, + ob, + me, + is_editmode, + is_paint_mode, + is_mode_active, + ob->obmat, + false, + true, + scene, + ts, + true); } if (do_cage) { - mesh_buffer_cache_create_requested(task_graph, - cache, - &cache->cage, - ob, - me, - is_editmode, - is_paint_mode, - is_mode_active, - ob->obmat, - false, - false, - scene, - ts, - true); + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + &cache->cage, + ob, + me, + is_editmode, + is_paint_mode, + is_mode_active, + ob->obmat, + false, + false, + scene, + ts, + true); } if (do_subdivision) { - DRW_create_subdivision(scene, - ob, + DRW_create_subdivision(ob, me, cache, &cache->final, @@ -2072,20 +2087,20 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mesh_batch_cache_free_subdiv_cache(cache); } - mesh_buffer_cache_create_requested(task_graph, - cache, - &cache->final, - ob, - me, - is_editmode, - is_paint_mode, - is_mode_active, - ob->obmat, - true, - false, - scene, - ts, - use_hide); + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + &cache->final, + ob, + me, + is_editmode, + is_paint_mode, + is_mode_active, + ob->obmat, + true, + false, + scene, + ts, + use_hide); /* Ensure that all requested batches have finished. * Ideally we want to remove this sync, but there are cases where this doesn't work. diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index a0c7e064e00..afec92a894d 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -39,10 +39,10 @@ #include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" -#include "draw_cache_extract.h" +#include "draw_cache_extract.hh" #include "draw_cache_impl.h" #include "draw_cache_inline.h" -#include "mesh_extractors/extract_mesh.h" +#include "mesh_extractors/extract_mesh.hh" extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[]; extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[]; @@ -221,7 +221,7 @@ static GPUShader *get_patch_evaluation_shader(int shader_type) "#define OSD_PATCH_BASIS_GLSL\n" "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n" "#define FDOTS_EVALUATION\n" - "#define FOTS_NORMALS\n"; + "#define FDOTS_NORMALS\n"; } else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) { defines = @@ -575,6 +575,7 @@ static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache) void draw_subdiv_cache_free(DRWSubdivCache *cache) { GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords); + GPU_VERTBUF_DISCARD_SAFE(cache->corner_patch_coords); GPU_VERTBUF_DISCARD_SAFE(cache->face_ptex_offset_buffer); GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_polygon_offset_buffer); GPU_VERTBUF_DISCARD_SAFE(cache->extra_coarse_face_data); @@ -780,7 +781,7 @@ struct DRWCacheBuildingContext { DRWSubdivCache *cache; - /* Pointers into DRWSubdivCache buffers for easier access during traversal. */ + /* Pointers into #DRWSubdivCache buffers for easier access during traversal. */ CompressedPatchCoord *patch_coords; int *subdiv_loop_vert_index; int *subdiv_loop_subdiv_vert_index; @@ -792,9 +793,9 @@ struct DRWCacheBuildingContext { int *vert_origindex_map; int *edge_origindex_map; - /* Origindex layers from the mesh to directly look up during traversal the origindex from the - * base mesh for edit data so that we do not have to handle yet another GPU buffer and do this in - * the shaders. */ + /* #CD_ORIGINDEX layers from the mesh to directly look up during traversal the original-index + * from the base mesh for edit data so that we do not have to handle yet another GPU buffer and + * do this in the shaders. */ const int *v_origindex; const int *e_origindex; }; @@ -834,6 +835,11 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC); GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops); + cache->corner_patch_coords = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex( + cache->corner_patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC); + GPU_vertbuf_data_alloc(cache->corner_patch_coords, cache->num_subdiv_loops); + cache->verts_orig_index = GPU_vertbuf_calloc(); GPU_vertbuf_init_with_format_ex( cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC); @@ -861,10 +867,10 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index; ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index; - ctx->v_origindex = static_cast<int *>( + ctx->v_origindex = static_cast<const int *>( CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX)); - ctx->e_origindex = static_cast<int *>( + ctx->e_origindex = static_cast<const int *>( CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX)); if (cache->num_subdiv_verts) { @@ -1046,14 +1052,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache) static bool draw_subdiv_build_cache(DRWSubdivCache *cache, Subdiv *subdiv, Mesh *mesh_eval, - const Scene *scene, - const SubsurfModifierData *smd, - const bool is_final_render) + const SubsurfRuntimeData *runtime_data) { - const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels; - const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render); SubdivToMeshSettings to_mesh_settings; - to_mesh_settings.resolution = (1 << level) + 1; + to_mesh_settings.resolution = runtime_data->resolution; to_mesh_settings.use_optimal_display = false; if (cache->resolution != to_mesh_settings.resolution) { @@ -1124,6 +1126,31 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache, cache->resolution = to_mesh_settings.resolution; cache->num_coarse_poly = mesh_eval->totpoly; + /* To avoid floating point precision issues when evaluating patches at patch boundaries, + * ensure that all loops sharing a vertex use the same patch coordinate. This could cause + * the mesh to not be watertight, leading to shadowing artifacts (see T97877). */ + blender::Vector<int> first_loop_index(cache->num_subdiv_verts, -1); + + /* Save coordinates for corners, as attributes may vary for each loop connected to the same + * vertex. */ + memcpy(GPU_vertbuf_get_data(cache->corner_patch_coords), + cache_building_context.patch_coords, + sizeof(CompressedPatchCoord) * cache->num_subdiv_loops); + + for (int i = 0; i < cache->num_subdiv_loops; i++) { + const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i]; + if (first_loop_index[vertex] != -1) { + continue; + } + first_loop_index[vertex] = i; + } + + for (int i = 0; i < cache->num_subdiv_loops; i++) { + const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i]; + cache_building_context.patch_coords[i] = + cache_building_context.patch_coords[first_loop_index[vertex]]; + } + /* Cleanup. */ MEM_SAFE_FREE(cache_building_context.vert_origindex_map); MEM_SAFE_FREE(cache_building_context.edge_origindex_map); @@ -1177,8 +1204,8 @@ struct DRWSubdivUboStorage { * of out of bond accesses as compute dispatch are of fixed size. */ uint total_dispatch_size; - int _pad0; - int _pad2; + int is_edit_mode; + int use_hide; int _pad3; }; @@ -1209,6 +1236,8 @@ static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache, ubo->coarse_face_hidden_mask = SUBDIV_COARSE_FACE_FLAG_HIDDEN_MASK; ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK; ubo->total_dispatch_size = total_dispatch_size; + ubo->is_edit_mode = cache->is_edit_mode; + ubo->use_hide = cache->use_hide; } static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache, @@ -1405,7 +1434,7 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache, GPU_vertbuf_bind_as_ssbo(src_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, binding_point++); - GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++); + GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++); GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++); @@ -1480,7 +1509,7 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache, GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(src_data, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, binding_point++); - GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++); + GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++); GPU_vertbuf_bind_as_ssbo(dst_data, binding_point++); BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS); @@ -1806,6 +1835,7 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache, GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++); + GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++); /* Outputs */ GPU_vertbuf_bind_as_ssbo(lnor, binding_point++); @@ -1974,10 +2004,9 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache, MEM_freeN(per_polygon_mat_offset); } -static bool draw_subdiv_create_requested_buffers(const Scene *scene, - Object *ob, +static bool draw_subdiv_create_requested_buffers(Object *ob, Mesh *mesh, - struct MeshBatchCache *batch_cache, + MeshBatchCache *batch_cache, MeshBufferCache *mbc, const bool is_editmode, const bool is_paint_mode, @@ -1989,16 +2018,10 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, const bool use_hide, OpenSubdiv_EvaluatorCache *evaluator_cache) { - SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>( - BKE_modifiers_findby_session_uuid(ob, &mesh->runtime.subsurf_session_uuid)); - BLI_assert(smd); - - const bool is_final_render = DRW_state_is_scene_render(); + SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data; + BLI_assert(runtime_data && runtime_data->has_gpu_subdiv); - SubdivSettings settings; - BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render); - - if (settings.level == 0) { + if (runtime_data->settings.level == 0) { return false; } @@ -2009,9 +2032,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, bm = mesh->edit_mesh->bm; } - BKE_subsurf_modifier_ensure_runtime(smd); - - Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true); + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true); if (!subdiv) { return false; } @@ -2032,13 +2053,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, } DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache); - if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) { + if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) { return false; } /* Edges which do not come from coarse edges should not be drawn in edit mode, only in object * mode when optimal display in turned off. */ - const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges) || is_editmode; + const bool optimal_display = runtime_data->use_optimal_display || is_editmode; draw_cache->bm = bm; draw_cache->mesh = mesh_eval; @@ -2046,14 +2067,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, draw_cache->optimal_display = optimal_display; draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops); - /* Copy topology information for stats display. Use `mesh` directly, as `mesh_eval` could be the - * edit mesh. */ - mesh->runtime.subsurf_totvert = draw_cache->num_subdiv_verts; - mesh->runtime.subsurf_totedge = draw_cache->num_subdiv_edges; - mesh->runtime.subsurf_totpoly = draw_cache->num_subdiv_quads; - mesh->runtime.subsurf_totloop = draw_cache->num_subdiv_loops; + /* Copy topology information for stats display. */ + runtime_data->stats_totvert = draw_cache->num_subdiv_verts; + runtime_data->stats_totedge = draw_cache->num_subdiv_edges; + runtime_data->stats_totpoly = draw_cache->num_subdiv_quads; + runtime_data->stats_totloop = draw_cache->num_subdiv_loops; - draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) && + draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) && (mesh_eval->flag & ME_AUTOSMOOTH) && CustomData_has_layer(&mesh_eval->ldata, CD_CUSTOMLOOPNORMAL); @@ -2065,10 +2085,16 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, MeshRenderData *mr = mesh_render_data_create( ob, mesh, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts); mr->use_hide = use_hide; + draw_cache->use_hide = use_hide; + + /* Used for setting loop normals flags. Mapped extraction is only used during edit mode. + * See comments in #extract_lnor_iter_poly_mesh. + */ + draw_cache->is_edit_mode = mr->edit_bmesh != nullptr; draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval, mr); - mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); + blender::draw::mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); mesh_render_data_free(mr); @@ -2175,10 +2201,9 @@ blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWS static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr; -void DRW_create_subdivision(const Scene *scene, - Object *ob, +void DRW_create_subdivision(Object *ob, Mesh *mesh, - struct MeshBatchCache *batch_cache, + MeshBatchCache *batch_cache, MeshBufferCache *mbc, const bool is_editmode, const bool is_paint_mode, @@ -2199,8 +2224,7 @@ void DRW_create_subdivision(const Scene *scene, const double begin_time = PIL_check_seconds_timer(); #endif - if (!draw_subdiv_create_requested_buffers(scene, - ob, + if (!draw_subdiv_create_requested_buffers(ob, mesh, batch_cache, mbc, diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index b6b0c94f4bf..d31c98e0dee 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -93,7 +93,7 @@ void DRW_curves_free(void); /** * Add attributes bindings of volume grids to an existing shading group. * No draw call is added so the caller can decide how to use the data. - * \return nullptr if there is something to draw. + * \return nullptr if there is nothing to draw. */ struct DRWShadingGroup *DRW_shgroup_volume_create_sub(struct Scene *scene, struct Object *ob, diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc index 39d4845994f..d040b4eade3 100644 --- a/source/blender/draw/intern/draw_curves.cc +++ b/source/blender/draw/intern/draw_curves.cc @@ -13,6 +13,9 @@ #include "DNA_curves_types.h" #include "DNA_customdata_types.h" +#include "BKE_curves.hh" +#include "BKE_geometry_set.hh" + #include "GPU_batch.h" #include "GPU_capabilities.h" #include "GPU_compute.h" @@ -243,13 +246,14 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, c } } -static CurvesEvalCache *drw_curves_cache_get(Object *object, +static CurvesEvalCache *drw_curves_cache_get(Curves &curves, GPUMaterial *gpu_material, int subdiv, int thickness_res) { CurvesEvalCache *cache; - bool update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res); + const bool update = curves_ensure_procedural_data( + &curves, &cache, gpu_material, subdiv, thickness_res); if (update) { if (drw_curves_shader_type_get() == PART_REFINE_SHADER_COMPUTE) { @@ -265,12 +269,13 @@ static CurvesEvalCache *drw_curves_cache_get(Object *object, GPUVertBuf *DRW_curves_pos_buffer_get(Object *object) { const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; + const Scene *scene = draw_ctx->scene; - int subdiv = scene->r.hair_subdiv; - int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + const int subdiv = scene->r.hair_subdiv; + const int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; - CurvesEvalCache *cache = drw_curves_cache_get(object, nullptr, subdiv, thickness_res); + Curves &curves = *static_cast<Curves *>(object->data); + CurvesEvalCache *cache = drw_curves_cache_get(curves, nullptr, subdiv, thickness_res); return cache->final[subdiv].proc_buf; } @@ -300,15 +305,16 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, GPUMaterial *gpu_material) { const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; + const Scene *scene = draw_ctx->scene; CurvesUniformBufPool *pool = DST.vmempool->curves_ubos; CurvesInfosBuf &curves_infos = pool->alloc(); + Curves &curves_id = *static_cast<Curves *>(object->data); - int subdiv = scene->r.hair_subdiv; - int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + const int subdiv = scene->r.hair_subdiv; + const int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; CurvesEvalCache *curves_cache = drw_curves_cache_get( - object, gpu_material, subdiv, thickness_res); + curves_id, gpu_material, subdiv, thickness_res); DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); @@ -325,6 +331,27 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, float hair_rad_tip = 0.0f; bool hair_close_tip = true; + /* Use the radius of the root and tip of the first curve for now. This is a workaround that we + * use for now because we can't use a per-point radius yet. */ + const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap( + curves_id.geometry); + if (curves.curves_num() >= 1) { + CurveComponent curves_component; + curves_component.replace(&curves_id, GeometryOwnershipType::ReadOnly); + blender::VArray<float> radii = curves_component.attribute_get_for_read( + "radius", ATTR_DOMAIN_POINT, 0.005f); + const blender::IndexRange first_curve_points = curves.points_for_curve(0); + const float first_radius = radii[first_curve_points.first()]; + const float last_radius = radii[first_curve_points.last()]; + const float middle_radius = radii[first_curve_points.size() / 2]; + hair_rad_root = radii[first_curve_points.first()]; + hair_rad_tip = radii[first_curve_points.last()]; + hair_rad_shape = std::clamp( + safe_divide(middle_radius - first_radius, last_radius - first_radius) * 2.0f - 1.0f, + -1.0f, + 1.0f); + } + DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex); if (curves_cache->length_tex) { DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex); diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h index ed4dd50dfbe..31122ed5248 100644 --- a/source/blender/draw/intern/draw_curves_private.h +++ b/source/blender/draw/intern/draw_curves_private.h @@ -16,6 +16,12 @@ extern "C" { #endif +struct Curves; +struct GPUVertBuf; +struct GPUIndexBuf; +struct GPUBatch; +struct GPUTexture; + #define MAX_THICKRES 2 /* see eHairType */ #define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */ @@ -25,32 +31,31 @@ typedef enum CurvesEvalShader { } CurvesEvalShader; #define CURVES_EVAL_SHADER_NUM 3 -struct GPUVertBuf; -struct GPUIndexBuf; -struct GPUBatch; -struct GPUTexture; - typedef struct CurvesEvalFinalCache { /* Output of the subdivision stage: vertex buffer sized to subdiv level. */ GPUVertBuf *proc_buf; GPUTexture *proc_tex; - /* Just contains a huge index buffer used to draw the final curves. */ + /** Just contains a huge index buffer used to draw the final curves. */ GPUBatch *proc_hairs[MAX_THICKRES]; - /* Points per curve, at least 2. */ + /** Points per curve, at least 2. */ int strands_res; - /* Attributes currently being or about to be drawn. */ + /** Attributes currently being drawn or about to be drawn. */ DRW_Attributes attr_used; - /* Attributes which were used at some point. This is used for garbage collection, to remove - * attributes which are not used in shaders anymore due to user edits. */ + /** + * Attributes that were used at some point. This is used for garbage collection, to remove + * attributes that are not used in shaders anymore due to user edits. + */ DRW_Attributes attr_used_over_time; - /* Last time, in seconds, the `attr_used` and `attr_used_over_time` were exactly the same. + /** + * The last time in seconds that the `attr_used` and `attr_used_over_time` were exactly the same. * If the delta between this time and the current scene time is greater than the timeout set in - * user preferences (`U.vbotimeout`) then garbage collection is performed. */ + * user preferences (`U.vbotimeout`) then garbage collection is performed. + */ int last_attr_matching_time; /* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes @@ -61,7 +66,7 @@ typedef struct CurvesEvalFinalCache { /* Curves procedural display: Evaluation is done on the GPU. */ typedef struct CurvesEvalCache { - /* Input control points */ + /* Input control point positions combined with parameter data. */ GPUVertBuf *proc_point_buf; GPUTexture *point_tex; @@ -78,8 +83,8 @@ typedef struct CurvesEvalCache { CurvesEvalFinalCache final[MAX_HAIR_SUBDIV]; - /* For point attributes, which need subdivision, these are the input data. - * For spline attributes, which need not subdivision, these are the final data. */ + /* For point attributes, which need subdivision, these buffers contain the input data. + * For curve domain attributes, which do not need subdivision, these are the final data. */ GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR]; GPUTexture *proc_attributes_tex[GPU_MAX_ATTR]; @@ -89,9 +94,9 @@ typedef struct CurvesEvalCache { } CurvesEvalCache; /** - * Ensure all textures and buffers needed for GPU accelerated drawing. + * Ensure all necessary textures and buffers exist for GPU accelerated drawing. */ -bool curves_ensure_procedural_data(struct Object *object, +bool curves_ensure_procedural_data(struct Curves *curves, struct CurvesEvalCache **r_hair_cache, struct GPUMaterial *gpu_material, int subdiv, diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index f0960c5324b..188d9114cd7 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1238,7 +1238,8 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) &update_frustum, &draw_frustum, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, - scd); + scd, + scd->use_mats); if (SCULPT_DEBUG_BUFFERS) { int debug_node_nr = 0; diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h index 15c770a51c4..ef580fc116a 100644 --- a/source/blender/draw/intern/draw_subdivision.h +++ b/source/blender/draw/intern/draw_subdivision.h @@ -104,8 +104,10 @@ typedef struct DRWSubdivCache { bool optimal_display; bool use_custom_loop_normals; - /* Coordinates used to evaluate patches for UVs, positions, and normals. */ + /* Coordinates used to evaluate patches for positions and normals. */ struct GPUVertBuf *patch_coords; + /* Coordinates used to evaluate patches for attributes. */ + struct GPUVertBuf *corner_patch_coords; /* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */ struct GPUVertBuf *fdots_patch_coords; @@ -175,6 +177,10 @@ typedef struct DRWSubdivCache { /* UBO to store settings for the various compute shaders. */ struct GPUUniformBuf *ubo; + + /* Extra flags, passed to the UBO. */ + bool is_edit_mode; + bool use_hide; } DRWSubdivCache; /* Only frees the data of the cache, caller is responsible to free the cache itself if necessary. @@ -183,8 +189,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache); /** \} */ -void DRW_create_subdivision(const struct Scene *scene, - struct Object *ob, +void DRW_create_subdivision(struct Object *ob, struct Mesh *mesh, struct MeshBatchCache *batch_cache, struct MeshBufferCache *mbc, diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc index 8d9a6f486e2..c4e58ab24cb 100644 --- a/source/blender/draw/intern/draw_volume.cc +++ b/source/blender/draw/intern/draw_volume.cc @@ -129,12 +129,14 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob, volume_infos.temperature_bias = 0.0f; /* Bind volume grid textures. */ - int grid_id = 0; + int grid_id = 0, grids_len = 0; LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) { const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr->name); const DRWVolumeGrid *drw_grid = (volume_grid) ? DRW_volume_batch_cache_get_grid(volume, volume_grid) : nullptr; + /* Count number of valid attributes. */ + grids_len += int(volume_grid != nullptr); /* Handle 3 cases here: * - Grid exists and texture was loaded -> use texture. @@ -145,7 +147,13 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob, grid_default_texture(attr->default_value); DRW_shgroup_uniform_texture(grp, attr->input_name, grid_tex); - copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), drw_grid->object_to_texture); + copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), + (drw_grid) ? drw_grid->object_to_texture : g_data.dummy_grid_mat); + } + /* Render nothing if there is no attribute for the shader to render. + * This also avoids an assert caused by the bounding box being zero in size. */ + if (grids_len == 0) { + return nullptr; } volume_infos.push_update(); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.c b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc index 9dc82fa3d32..ec7d3a933b4 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.c +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc @@ -13,7 +13,7 @@ #include "ED_uvedit.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_cache_impl.h" @@ -29,7 +29,7 @@ void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuf eMRIterType mesh_extract_iter_type(const MeshExtract *ext) { - eMRIterType type = 0; + eMRIterType type = (eMRIterType)0; SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE); @@ -128,7 +128,7 @@ void mesh_render_data_loop_flag(const MeshRenderData *mr, return; } MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_ofs); - if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) { + if (luv != nullptr && (luv->flag & MLOOPUV_PINNED)) { eattr->v_flag |= VFLAG_VERT_UV_PINNED; } if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index b88cd9e77d2..8052b277d45 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -17,11 +17,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "draw_cache_extract.h" - -#ifdef __cplusplus -extern "C" { -#endif +#include "draw_cache_extract.hh" struct DRWSubdivCache; @@ -31,13 +27,13 @@ struct DRWSubdivCache; /** \name Mesh Render Data * \{ */ -typedef enum eMRExtractType { +enum eMRExtractType { MR_EXTRACT_BMESH, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH, -} eMRExtractType; +}; -typedef struct MeshRenderData { +struct MeshRenderData { eMRExtractType extract_type; int poly_len, edge_len, vert_len, loop_len; @@ -95,7 +91,7 @@ typedef struct MeshRenderData { int *mat_tri_len; int visible_tri_len; } poly_sorted; -} MeshRenderData; +}; BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx) { @@ -159,71 +155,71 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e /* TODO(jbakker): move parameters inside a struct. */ -typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data); -typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, - const MLoopTri *mlt, - int elt_index, - void *data); -typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr, - const BMFace *f, - int f_index, - void *data); -typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr, - const MPoly *mp, - int mp_index, +using ExtractTriBMeshFn = void(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data); +using ExtractTriMeshFn = void(const MeshRenderData *mr, + const MLoopTri *mlt, + int elt_index, + void *data); +using ExtractPolyBMeshFn = void(const MeshRenderData *mr, + const BMFace *f, + int f_index, void *data); -typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, - const BMEdge *eed, - int ledge_index, - void *data); -typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, - const MEdge *med, +using ExtractPolyMeshFn = void(const MeshRenderData *mr, + const MPoly *mp, + int mp_index, + void *data); +using ExtractLEdgeBMeshFn = void(const MeshRenderData *mr, + const BMEdge *eed, int ledge_index, void *data); -typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, - const BMVert *eve, - int lvert_index, - void *data); -typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, - const MVert *mv, +using ExtractLEdgeMeshFn = void(const MeshRenderData *mr, + const MEdge *med, + int ledge_index, + void *data); +using ExtractLVertBMeshFn = void(const MeshRenderData *mr, + const BMVert *eve, int lvert_index, void *data); -typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - void *buffer, - void *data); -typedef void(ExtractInitFn)(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buffer, - void *r_data); -typedef void(ExtractFinishFn)(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buffer, - void *data); -typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata); - -typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *data); -typedef void(ExtractIterSubdivBMeshFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - void *data, - uint subdiv_quad_index, - const BMFace *coarse_quad); -typedef void(ExtractIterSubdivMeshFn)(const struct DRWSubdivCache *subdiv_cache, +using ExtractLVertMeshFn = void(const MeshRenderData *mr, + const MVert *mv, + int lvert_index, + void *data); +using ExtractLooseGeomSubdivFn = void(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *buffer, + void *data); +using ExtractInitFn = void(const MeshRenderData *mr, + MeshBatchCache *cache, + void *buffer, + void *r_data); +using ExtractFinishFn = void(const MeshRenderData *mr, + MeshBatchCache *cache, + void *buffer, + void *data); +using ExtractTaskReduceFn = void(void *userdata, void *task_userdata); + +using ExtractInitSubdivFn = void(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *cache, + void *buf, + void *data); +using ExtractIterSubdivBMeshFn = void(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, void *data, uint subdiv_quad_index, - const MPoly *coarse_quad); -typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *data); - -typedef struct MeshExtract { + const BMFace *coarse_quad); +using ExtractIterSubdivMeshFn = void(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *data, + uint subdiv_quad_index, + const MPoly *coarse_quad); +using ExtractFinishSubdivFn = void(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *cache, + void *buf, + void *data); + +struct MeshExtract { /** Executed on main thread and return user data for iteration functions. */ ExtractInitFn *init; /** Executed on one (or more if use_threading) worker thread(s). */ @@ -254,7 +250,7 @@ typedef struct MeshExtract { * buffer. */ size_t mesh_buffer_offset; -} MeshExtract; +}; /** \} */ @@ -291,14 +287,14 @@ void mesh_render_data_update_looptris(MeshRenderData *mr, /* draw_cache_extract_mesh_extractors.c */ -typedef struct EditLoopData { +struct EditLoopData { uchar v_flag; uchar e_flag; /* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4 * bits, while the vertex crease is stored in the upper 4 bits. */ uchar crease; uchar bweight; -} EditLoopData; +}; void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist); eMRIterType mesh_extract_iter_type(const MeshExtract *ext); @@ -359,7 +355,3 @@ extern const MeshExtract extract_edge_idx; extern const MeshExtract extract_vert_idx; extern const MeshExtract extract_fdot_idx; extern const MeshExtract extract_attr[GPU_MAX_ATTR]; - -#ifdef __cplusplus -} -#endif 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 2c4e7bfa802..2ff093d0bd8 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 @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -22,7 +22,7 @@ struct MeshExtract_EditUvElem_Data { }; static void extract_edituv_tris_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { @@ -69,7 +69,7 @@ static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr, } static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -142,7 +142,7 @@ static void extract_edituv_tris_iter_subdiv_mesh(const DRWSubdivCache *UNUSED(su static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -176,7 +176,7 @@ constexpr MeshExtract create_extractor_edituv_tris() * \{ */ static void extract_edituv_lines_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { @@ -236,7 +236,7 @@ static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, } static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -307,7 +307,7 @@ static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_c static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -341,7 +341,7 @@ constexpr MeshExtract create_extractor_edituv_lines() * \{ */ static void extract_edituv_points_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { @@ -394,7 +394,7 @@ static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, } static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -459,7 +459,7 @@ static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_ static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -493,7 +493,7 @@ constexpr MeshExtract create_extractor_edituv_points() * \{ */ static void extract_edituv_fdots_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { @@ -557,7 +557,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, } static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -584,9 +584,7 @@ constexpr MeshExtract create_extractor_edituv_fdots() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_tris = blender::draw::create_extractor_edituv_tris(); const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_lines(); const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points(); const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc index 4bf732caf0a..cc0b383f12b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -15,7 +15,7 @@ namespace blender::draw { * \{ */ static void extract_fdots_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *tls_data) { @@ -68,7 +68,7 @@ static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr, } static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_userdata) { @@ -95,6 +95,4 @@ constexpr MeshExtract create_extractor_fdots() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots = blender::draw::create_extractor_fdots(); -} 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 3cecaf81b8a..51d98d1ff26 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 @@ -7,7 +7,7 @@ #include "MEM_guardedalloc.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -18,7 +18,7 @@ namespace blender::draw { * \{ */ static void extract_lines_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *tls_data) { @@ -132,7 +132,7 @@ static void extract_lines_task_reduce(void *_userdata_to, void *_userdata_from) } static void extract_lines_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *data) { @@ -143,7 +143,7 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr), static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buffer, void *UNUSED(data)) { @@ -183,10 +183,18 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, uint *flags_data = static_cast<uint *>(GPU_vertbuf_get_data(flags)); - const MEdge *medge = mr->medge; - - for (DRWSubdivLooseEdge edge : loose_edges) { - *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0; + if (mr->extract_type == MR_EXTRACT_MESH) { + const MEdge *medge = mr->medge; + for (DRWSubdivLooseEdge edge : loose_edges) { + *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0; + } + } + else { + BMesh *bm = mr->bm; + for (DRWSubdivLooseEdge edge : loose_edges) { + const BMEdge *bm_edge = BM_edge_at_index(bm, edge.coarse_edge_index); + *flags_data++ = BM_elem_flag_test_bool(bm_edge, BM_ELEM_HIDDEN) != 0; + } } GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); @@ -221,7 +229,7 @@ constexpr MeshExtract create_extractor_lines() /** \name Extract Lines and Loose Edges Sub Buffer * \{ */ -static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache) +static void extract_lines_loose_subbuffer(const MeshRenderData *mr, MeshBatchCache *cache) { BLI_assert(cache->final.buff.ibo.lines); /* Multiply by 2 because these are edges indices. */ @@ -233,7 +241,7 @@ static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshB } static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *data) { @@ -245,7 +253,7 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, static void extract_lines_with_lines_loose_finish_subdiv(const struct DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *UNUSED(buf), void *UNUSED(_data)) { @@ -284,7 +292,7 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose() * \{ */ static void extract_lines_loose_only_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *UNUSED(tls_data)) { @@ -295,7 +303,7 @@ static void extract_lines_loose_only_init(const MeshRenderData *mr, static void extract_lines_loose_only_init_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -320,9 +328,7 @@ constexpr MeshExtract create_extractor_lines_loose_only() } // namespace blender::draw -extern "C" { const MeshExtract extract_lines = blender::draw::create_extractor_lines(); const MeshExtract extract_lines_with_lines_loose = blender::draw::create_extractor_lines_with_lines_loose(); const MeshExtract extract_lines_loose_only = blender::draw::create_extractor_lines_loose_only(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc index de464fb286f..c2cfb66ec28 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc @@ -11,7 +11,7 @@ #include "MEM_guardedalloc.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -42,7 +42,7 @@ static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data, } static void extract_lines_adjacency_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *tls_data) { @@ -132,7 +132,7 @@ static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr, } static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *_data) { @@ -166,7 +166,7 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *_data) { @@ -222,7 +222,7 @@ static void extract_lines_adjacency_iter_subdiv_mesh(const DRWSubdivCache *subdi static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *_data) { @@ -253,6 +253,4 @@ constexpr MeshExtract create_extractor_lines_adjacency() } // namespace blender::draw -extern "C" { const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency(); -} 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 286c7ea9c43..11c71d61775 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 @@ -12,7 +12,7 @@ #include "MEM_guardedalloc.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -26,7 +26,7 @@ struct MeshExtract_LinePaintMask_Data { }; static void extract_lines_paint_mask_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { @@ -78,7 +78,7 @@ static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, } static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -126,7 +126,8 @@ static void extract_lines_paint_mask_iter_subdiv_mesh(const DRWSubdivCache *subd if (!((mr->use_hide && (me->flag & ME_HIDE)) || ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && (mr->e_origindex[coarse_edge_index] == ORIGINDEX_NONE)))) { - const uint ml_index_other = (loop_idx == end_loop_idx) ? start_loop_idx : loop_idx + 1; + const uint ml_index_other = (loop_idx == (end_loop_idx - 1)) ? start_loop_idx : + loop_idx + 1; if (coarse_quad->flag & ME_FACE_SEL) { if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, coarse_edge_index)) { /* Hide edge as it has more than 2 selected loop. */ @@ -154,7 +155,7 @@ static void extract_lines_paint_mask_iter_subdiv_mesh(const DRWSubdivCache *subd static void extract_lines_paint_mask_finish_subdiv( const struct DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *_data) { @@ -181,6 +182,4 @@ constexpr MeshExtract create_extractor_lines_paint_mask() } // namespace blender::draw -extern "C" { const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask(); -} 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 503ce0e79e9..f7c5505422b 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 @@ -10,7 +10,7 @@ #include "MEM_guardedalloc.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -19,7 +19,7 @@ namespace blender::draw { * \{ */ static void extract_points_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *tls_data) { @@ -131,7 +131,7 @@ static void extract_points_task_reduce(void *_userdata_to, void *_userdata_from) } static void extract_points_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_userdata) { @@ -142,7 +142,7 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr), static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buffer), void *data) { @@ -285,7 +285,7 @@ static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_userdata) { @@ -322,6 +322,4 @@ constexpr MeshExtract create_extractor_points() } // namespace blender::draw -extern "C" { const MeshExtract extract_points = blender::draw::create_extractor_points(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc index 6ca5692f387..9fc18620d11 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -7,7 +7,7 @@ #include "MEM_guardedalloc.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -25,7 +25,7 @@ static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_fro * \{ */ static void extract_tris_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { @@ -81,7 +81,7 @@ static void extract_tris_iter_poly_mesh(const MeshRenderData *mr, } static void extract_tris_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *_data) { @@ -111,7 +111,7 @@ static void extract_tris_finish(const MeshRenderData *mr, static void extract_tris_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -157,7 +157,7 @@ constexpr MeshExtract create_extractor_tris() * \{ */ static void extract_tris_single_mat_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(ibo), void *tls_data) { @@ -199,7 +199,7 @@ static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr, } static void extract_tris_single_mat_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *_data) { @@ -243,7 +243,5 @@ constexpr MeshExtract create_extractor_tris_single_mat() } // namespace blender::draw -extern "C" { const MeshExtract extract_tris = blender::draw::create_extractor_tris(); const MeshExtract extract_tris_single_mat = blender::draw::create_extractor_tris_single_mat(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index d595abc6dd3..ff86bc768a3 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -16,7 +16,7 @@ #include "draw_attributes.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -24,24 +24,19 @@ namespace blender::draw { /** \name Extract Attributes * \{ */ -static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain) +static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDomain domain) { switch (domain) { - default: { - return nullptr; - } - case ATTR_DOMAIN_POINT: { + case ATTR_DOMAIN_POINT: return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; - } - case ATTR_DOMAIN_CORNER: { + case ATTR_DOMAIN_CORNER: return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - } - case ATTR_DOMAIN_FACE: { + case ATTR_DOMAIN_FACE: return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata; - } - case ATTR_DOMAIN_EDGE: { + case ATTR_DOMAIN_EDGE: return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata; - } + default: + return nullptr; } } @@ -50,7 +45,7 @@ static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, Attribut * etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4 * in the shader. */ -template<typename AttributeType, typename VBOType> struct attribute_type_converter { +template<typename AttributeType, typename VBOType> struct AttributeTypeConverter { static VBOType convert_value(AttributeType value) { if constexpr (std::is_same_v<AttributeType, VBOType>) { @@ -67,7 +62,7 @@ struct gpuMeshCol { ushort r, g, b, a; }; -template<> struct attribute_type_converter<MPropCol, gpuMeshCol> { +template<> struct AttributeTypeConverter<MPropCol, gpuMeshCol> { static gpuMeshCol convert_value(MPropCol value) { gpuMeshCol result; @@ -80,64 +75,52 @@ template<> struct attribute_type_converter<MPropCol, gpuMeshCol> { }; /* Return the number of component for the attribute's value type, or 0 if is it unsupported. */ -static uint gpu_component_size_for_attribute_type(CustomDataType type) +static uint gpu_component_size_for_attribute_type(eCustomDataType type) { switch (type) { case CD_PROP_BOOL: case CD_PROP_INT8: case CD_PROP_INT32: - case CD_PROP_FLOAT: { + case CD_PROP_FLOAT: /* TODO(@kevindietrich): should be 1 when scalar attributes conversion is handled by us. See * comment #extract_attr_init. */ return 3; - } - case CD_PROP_FLOAT2: { + case CD_PROP_FLOAT2: return 2; - } - case CD_PROP_FLOAT3: { + case CD_PROP_FLOAT3: return 3; - } - case CD_PROP_COLOR: { + case CD_PROP_COLOR: return 4; - } - default: { + default: return 0; - } } } -static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type) +static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type) { switch (type) { - case CD_PROP_INT32: { + case CD_PROP_INT32: return GPU_FETCH_INT_TO_FLOAT; - } - case CD_PROP_COLOR: { + case CD_PROP_COLOR: return GPU_FETCH_INT_TO_FLOAT_UNIT; - } - default: { + default: return GPU_FETCH_FLOAT; - } } } -static GPUVertCompType get_comp_type_for_type(CustomDataType type) +static GPUVertCompType get_comp_type_for_type(eCustomDataType type) { switch (type) { - case CD_PROP_INT32: { + case CD_PROP_INT32: return GPU_COMP_I32; - } - case CD_PROP_COLOR: { + case CD_PROP_COLOR: return GPU_COMP_U16; - } - default: { + default: return GPU_COMP_F32; - } } } -static void init_vbo_for_attribute(const MeshRenderData *mr, - GPUVertBuf *vbo, +static void init_vbo_for_attribute(GPUVertBuf *vbo, const DRW_AttributeRequest &request, bool build_on_device, uint32_t len) @@ -148,11 +131,8 @@ static void init_vbo_for_attribute(const MeshRenderData *mr, /* We should not be here if the attribute type is not supported. */ BLI_assert(comp_size != 0); - const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain); char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name( - custom_data, request.cd_type, request.layer_index); - GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + GPU_vertformat_safe_attr_name(request.attribute_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); /* Attributes use auto-name. */ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); @@ -184,41 +164,36 @@ static void fill_vertbuf_with_attribute(const MeshRenderData *mr, const AttributeType *attr_data = static_cast<const AttributeType *>( CustomData_get_layer_n(custom_data, request.cd_type, layer_index)); - using converter = attribute_type_converter<AttributeType, VBOType>; + using Converter = AttributeTypeConverter<AttributeType, VBOType>; switch (request.domain) { - default: { - BLI_assert(false); - break; - } - case ATTR_DOMAIN_POINT: { + case ATTR_DOMAIN_POINT: for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) { - *vbo_data = converter::convert_value(attr_data[mloop->v]); + *vbo_data = Converter::convert_value(attr_data[mloop->v]); } break; - } - case ATTR_DOMAIN_CORNER: { + case ATTR_DOMAIN_CORNER: for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) { - *vbo_data = converter::convert_value(attr_data[ml_index]); + *vbo_data = Converter::convert_value(attr_data[ml_index]); } break; - } - case ATTR_DOMAIN_EDGE: { + case ATTR_DOMAIN_EDGE: for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) { - *vbo_data = converter::convert_value(attr_data[mloop->e]); + *vbo_data = Converter::convert_value(attr_data[mloop->e]); } break; - } - case ATTR_DOMAIN_FACE: { + case ATTR_DOMAIN_FACE: for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { const MPoly &poly = mpoly[mp_index]; - const VBOType value = converter::convert_value(attr_data[mp_index]); + const VBOType value = Converter::convert_value(attr_data[mp_index]); for (int l = 0; l < poly.totloop; l++) { *vbo_data++ = value; } } break; - } + default: + BLI_assert_unreachable(); + break; } } @@ -231,9 +206,9 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr, BLI_assert(custom_data); const int layer_index = request.layer_index; - int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index); + const int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index); - using converter = attribute_type_converter<AttributeType, VBOType>; + using Converter = AttributeTypeConverter<AttributeType, VBOType>; BMIter f_iter; BMFace *efa; @@ -255,10 +230,10 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr, attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs)); } else { - BLI_assert(false); + BLI_assert_unreachable(); continue; } - *vbo_data = converter::convert_value(*attr_data); + *vbo_data = Converter::convert_value(*attr_data); vbo_data++; } while ((l_iter = l_iter->next) != l_first); } @@ -279,55 +254,44 @@ static void extract_attr_generic(const MeshRenderData *mr, } } -static void extract_attr_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data), - int index) +static void extract_attr_init( + const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void *UNUSED(tls_data), int index) { const DRW_Attributes *attrs_used = &cache->attr_used; const DRW_AttributeRequest &request = attrs_used->requests[index]; GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len)); + init_vbo_for_attribute(vbo, request, false, static_cast<uint32_t>(mr->loop_len)); /* TODO(@kevindietrich): float3 is used for scalar attributes as the implicit conversion done by * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the * Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar * texture as for volume attribute, so we can control the conversion ourselves. */ switch (request.cd_type) { - case CD_PROP_BOOL: { + case CD_PROP_BOOL: extract_attr_generic<bool, float3>(mr, vbo, request); break; - } - case CD_PROP_INT8: { + case CD_PROP_INT8: extract_attr_generic<int8_t, float3>(mr, vbo, request); break; - } - case CD_PROP_INT32: { + case CD_PROP_INT32: extract_attr_generic<int32_t, float3>(mr, vbo, request); break; - } - case CD_PROP_FLOAT: { + case CD_PROP_FLOAT: extract_attr_generic<float, float3>(mr, vbo, request); break; - } - case CD_PROP_FLOAT2: { + case CD_PROP_FLOAT2: extract_attr_generic<float2>(mr, vbo, request); break; - } - case CD_PROP_FLOAT3: { + case CD_PROP_FLOAT3: extract_attr_generic<float3>(mr, vbo, request); break; - } - case CD_PROP_COLOR: { + case CD_PROP_COLOR: extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request); break; - } - default: { - BLI_assert(false); - } + default: + BLI_assert_unreachable(); } } @@ -353,41 +317,33 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache, GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop)); switch (request.cd_type) { - case CD_PROP_BOOL: { + case CD_PROP_BOOL: extract_attr_generic<bool, float3>(mr, src_data, request); break; - } - case CD_PROP_INT8: { + case CD_PROP_INT8: extract_attr_generic<int8_t, float3>(mr, src_data, request); break; - } - case CD_PROP_INT32: { + case CD_PROP_INT32: extract_attr_generic<int32_t, float3>(mr, src_data, request); break; - } - case CD_PROP_FLOAT: { + case CD_PROP_FLOAT: extract_attr_generic<float, float3>(mr, src_data, request); break; - } - case CD_PROP_FLOAT2: { + case CD_PROP_FLOAT2: extract_attr_generic<float2>(mr, src_data, request); break; - } - case CD_PROP_FLOAT3: { + case CD_PROP_FLOAT3: extract_attr_generic<float3>(mr, src_data, request); break; - } - case CD_PROP_COLOR: { + case CD_PROP_COLOR: extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request); break; - } - default: { - BLI_assert(false); - } + default: + BLI_assert_unreachable(); } GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); - init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops); + init_vbo_for_attribute(dst_buffer, request, true, subdiv_cache->num_subdiv_loops); /* Ensure data is uploaded properly. */ GPU_vertbuf_tag_dirty(src_data); @@ -401,13 +357,13 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache, * extract. The overall API does not allow us to pass this in a convenient way. */ #define EXTRACT_INIT_WRAPPER(index) \ static void extract_attr_init##index( \ - const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \ + const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void *tls_data) \ { \ extract_attr_init(mr, cache, buf, tls_data, index); \ } \ static void extract_attr_init_subdiv##index(const DRWSubdivCache *subdiv_cache, \ const MeshRenderData *mr, \ - struct MeshBatchCache *cache, \ + MeshBatchCache *cache, \ void *buf, \ void *tls_data) \ { \ @@ -430,7 +386,7 @@ EXTRACT_INIT_WRAPPER(12) EXTRACT_INIT_WRAPPER(13) EXTRACT_INIT_WRAPPER(14) -template<int index> +template<int Index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn) { MeshExtract extractor = {nullptr}; @@ -439,7 +395,7 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[Index]); return extractor; } @@ -447,7 +403,6 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF } // namespace blender::draw -extern "C" { #define CREATE_EXTRACTOR_ATTR(index) \ blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \ blender::draw::extract_attr_init_subdiv##index) @@ -469,4 +424,3 @@ const MeshExtract extract_attr[GPU_MAX_ATTR] = { CREATE_EXTRACTOR_ATTR(13), CREATE_EXTRACTOR_ATTR(14), }; -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc index f3b41efe1c3..eb6e800023a 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc @@ -10,7 +10,7 @@ #include "GPU_capabilities.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -43,7 +43,7 @@ static float loop_edge_factor_get(const float f_no[3], } static void extract_edge_fac_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -167,7 +167,7 @@ static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, } static void extract_edge_fac_finish(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *_data) { @@ -218,7 +218,7 @@ static GPUVertFormat *get_subdiv_edge_fac_format() static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -303,6 +303,4 @@ constexpr MeshExtract create_extractor_edge_fac() } // namespace blender::draw -extern "C" { const MeshExtract extract_edge_fac = blender::draw::create_extractor_edge_fac(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc index 1e158a7e6d7..27fd6546b8c 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_cache_impl.h" @@ -112,7 +112,7 @@ static GPUVertFormat *get_edit_data_format() } static void extract_edit_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -367,6 +367,4 @@ constexpr MeshExtract create_extractor_edit_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_edit_data = blender::draw::create_extractor_edit_data(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc index f79fe345f5a..0b9043e3289 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_cache_impl.h" @@ -43,7 +43,7 @@ static void extract_edituv_data_init_common(const MeshRenderData *mr, } static void extract_edituv_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -199,6 +199,4 @@ constexpr MeshExtract create_extractor_edituv_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_data = blender::draw::create_extractor_edituv_data(); -} 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 fb4b95885fc..969ff9f6f09 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 @@ -9,7 +9,7 @@ #include "BKE_mesh.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -74,7 +74,7 @@ static void edituv_get_edituv_stretch_angle(float auv[2][2], } static void extract_edituv_stretch_angle_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -212,7 +212,7 @@ static GPUVertFormat *get_edituv_stretch_angle_format_subdiv() static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(tls_data)) { @@ -292,7 +292,5 @@ constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_stretch_angle = blender::draw::create_extractor_edituv_edituv_stretch_angle(); -} 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 ab397cc1717..2bb786303c4 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 @@ -9,7 +9,7 @@ #include "BKE_mesh.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -20,7 +20,7 @@ namespace blender::draw { * \{ */ static void extract_edituv_stretch_area_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { @@ -89,7 +89,7 @@ static void compute_area_ratio(const MeshRenderData *mr, } static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *UNUSED(data)) { @@ -131,7 +131,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_edituv_stretch_area() } // namespace blender::draw -extern "C" { const MeshExtract extract_edituv_stretch_area = blender::draw::create_extractor_edituv_stretch_area(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc index 1c4f6112877..27d1975d67b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_cache_impl.h" @@ -21,7 +21,7 @@ struct MeshExtract_EditUVFdotData_Data { }; static void extract_fdots_edituv_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -81,6 +81,4 @@ constexpr MeshExtract create_extractor_fdots_edituv_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_edituv_data = blender::draw::create_extractor_fdots_edituv_data(); -} 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 909c9ac2300..c2af7f2c9bd 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 @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -19,7 +19,7 @@ namespace blender::draw { #define NOR_AND_FLAG_HIDDEN -2 static void extract_fdots_nor_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { @@ -34,7 +34,7 @@ static void extract_fdots_nor_init(const MeshRenderData *mr, } static void extract_fdots_nor_finish(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(data)) { @@ -101,7 +101,7 @@ constexpr MeshExtract create_extractor_fdots_nor() * \{ */ static void extract_fdots_nor_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { @@ -116,7 +116,7 @@ static void extract_fdots_nor_hq_init(const MeshRenderData *mr, } static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(data)) { @@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_fdots_nor_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_nor = blender::draw::create_extractor_fdots_nor(); const MeshExtract extract_fdots_nor_hq = blender::draw::create_extractor_fdots_nor_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc index 1671a1cd1e7..c391cb6ca5a 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -36,7 +36,7 @@ static GPUVertFormat *get_fdots_nor_format_subdiv() } static void extract_fdots_pos_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -101,7 +101,7 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -139,6 +139,4 @@ constexpr MeshExtract create_extractor_fdots_pos() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_pos = blender::draw::create_extractor_fdots_pos(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc index e7a3cb03903..b0403cf7c4c 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc @@ -7,7 +7,7 @@ #include "BLI_bitmap.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -22,7 +22,7 @@ struct MeshExtract_FdotUV_Data { }; static void extract_fdots_uv_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -109,6 +109,4 @@ constexpr MeshExtract create_extractor_fdots_uv() } // namespace blender::draw -extern "C" { const MeshExtract extract_fdots_uv = blender::draw::create_extractor_fdots_uv(); -} 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 8bc8b32fdf3..ac517269e7d 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 @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -16,7 +16,7 @@ namespace blender::draw { * \{ */ static void extract_lnor_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -105,7 +105,7 @@ static GPUVertFormat *get_subdiv_lnor_format() static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -141,7 +141,7 @@ struct gpuHQNor { }; static void extract_lnor_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -234,7 +234,5 @@ constexpr MeshExtract create_extractor_lnor_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_lnor = blender::draw::create_extractor_lnor(); const MeshExtract extract_lnor_hq = blender::draw::create_extractor_lnor_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc index 968c1f693fb..951990466d0 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc @@ -14,7 +14,7 @@ #include "BKE_editmesh_bvh.h" #include "BKE_editmesh_cache.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -23,7 +23,7 @@ namespace blender::draw { * \{ */ static void extract_mesh_analysis_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { @@ -587,7 +587,7 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) } static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(data)) { @@ -633,6 +633,4 @@ constexpr MeshExtract create_extractor_mesh_analysis() } // namespace blender::draw -extern "C" { const MeshExtract extract_mesh_analysis = blender::draw::create_extractor_mesh_analysis(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc index 94674a54f12..4fcbdb1fc7c 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -19,7 +19,7 @@ struct MeshExtract_Orco_Data { }; static void extract_orco_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -94,6 +94,4 @@ constexpr MeshExtract create_extractor_orco() } // namespace blender::draw -extern "C" { const MeshExtract extract_orco = blender::draw::create_extractor_orco(); -} 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 f80b33e28f2..9788beabeb5 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 @@ -7,7 +7,7 @@ #include "MEM_guardedalloc.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -28,7 +28,7 @@ struct MeshExtract_PosNor_Data { }; static void extract_pos_nor_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -171,7 +171,7 @@ static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, } static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *_data) { @@ -201,7 +201,7 @@ static GPUVertFormat *get_custom_normals_format() static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -234,7 +234,7 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, if (subdiv_cache->use_custom_loop_normals) { Mesh *coarse_mesh = subdiv_cache->mesh; - const float(*lnors)[3] = static_cast<float(*)[3]>( + const float(*lnors)[3] = static_cast<const float(*)[3]>( CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL)); BLI_assert(lnors != nullptr); @@ -372,7 +372,7 @@ struct MeshExtract_PosNorHQ_Data { }; static void extract_pos_nor_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -521,7 +521,7 @@ static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr, } static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *_data) { @@ -552,7 +552,5 @@ constexpr MeshExtract create_extractor_pos_nor_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_pos_nor = blender::draw::create_extractor_pos_nor(); const MeshExtract extract_pos_nor_hq = blender::draw::create_extractor_pos_nor_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc index 5658ed85c8b..492721b4853 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc @@ -12,7 +12,7 @@ #include "BKE_paint.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -31,7 +31,7 @@ static GPUVertFormat *get_sculpt_data_format() } static void extract_sculpt_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { @@ -113,7 +113,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr, static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buffer, void *UNUSED(data)) { @@ -215,6 +215,4 @@ constexpr MeshExtract create_extractor_sculpt_data() } // namespace blender::draw -extern "C" { const MeshExtract extract_sculpt_data = blender::draw::create_extractor_sculpt_data(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc index f4c54b2f881..9e0d171c9e4 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc @@ -6,7 +6,7 @@ */ #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -30,7 +30,7 @@ static void extract_select_idx_init_impl(const MeshRenderData *UNUSED(mr), } static void extract_select_idx_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -366,7 +366,7 @@ constexpr MeshExtract create_extractor_vert_idx() } static void extract_fdot_idx_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *tls_data) { @@ -411,9 +411,7 @@ constexpr MeshExtract create_extractor_fdot_idx() } // namespace blender::draw -extern "C" { const MeshExtract extract_poly_idx = blender::draw::create_extractor_poly_idx(); const MeshExtract extract_edge_idx = blender::draw::create_extractor_edge_idx(); const MeshExtract extract_vert_idx = blender::draw::create_extractor_vert_idx(); const MeshExtract extract_fdot_idx = blender::draw::create_extractor_fdot_idx(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc index bb6331dd377..f7655658bdd 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc @@ -5,7 +5,7 @@ * \ingroup draw */ -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -19,7 +19,7 @@ struct SkinRootData { }; static void extract_skin_roots_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), + MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { @@ -72,6 +72,4 @@ constexpr MeshExtract create_extractor_skin_roots() } // namespace blender::draw -extern "C" { const MeshExtract extract_skin_roots = blender::draw::create_extractor_skin_roots(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc index 91cd675d32f..049fa416523 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -14,7 +14,7 @@ #include "BKE_mesh.h" #include "BKE_mesh_tangent.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" #include "draw_subdivision.h" @@ -25,7 +25,7 @@ namespace blender::draw { * \{ */ static void extract_tan_init_common(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, GPUVertFormat *format, GPUVertCompType comp_type, GPUVertFetchMode fetch_mode, @@ -161,7 +161,7 @@ static void extract_tan_init_common(const MeshRenderData *mr, } static void extract_tan_ex_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, GPUVertBuf *vbo, const bool do_hq) { @@ -235,7 +235,7 @@ static void extract_tan_ex_init(const MeshRenderData *mr, } static void extract_tan_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *UNUSED(tls_data)) { @@ -254,7 +254,7 @@ static GPUVertFormat *get_coarse_tan_format() static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -344,7 +344,7 @@ constexpr MeshExtract create_extractor_tan() * \{ */ static void extract_tan_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *UNUSED(tls_data)) { @@ -367,7 +367,5 @@ constexpr MeshExtract create_extractor_tan_hq() } // namespace blender::draw -extern "C" { const MeshExtract extract_tan = blender::draw::create_extractor_tan(); const MeshExtract extract_tan_hq = blender::draw::create_extractor_tan_hq(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc index 2808a0a3a71..6606912850d 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -8,7 +8,7 @@ #include "BLI_string.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -19,7 +19,7 @@ namespace blender::draw { /* Initialize the vertex format to be used for UVs. Return true if any UV layer is * found, false otherwise. */ static bool mesh_extract_uv_format_init(GPUVertFormat *format, - struct MeshBatchCache *cache, + MeshBatchCache *cache, CustomData *cd_ldata, eMRExtractType extract_type, uint32_t &r_uv_layers) @@ -72,7 +72,7 @@ static bool mesh_extract_uv_format_init(GPUVertFormat *format, } static void extract_uv_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *UNUSED(tls_data)) { @@ -120,7 +120,7 @@ static void extract_uv_init(const MeshRenderData *mr, static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { @@ -168,6 +168,4 @@ constexpr MeshExtract create_extractor_uv() } // namespace blender::draw -extern "C" { const MeshExtract extract_uv = blender::draw::create_extractor_uv(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc index fa5bf35198b..419cbb0267f 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -12,11 +12,13 @@ #include "BLI_vector.hh" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" + +namespace blender::draw { struct VColRef { const CustomDataLayer *layer; - AttributeDomain domain; + eAttrDomain domain; }; /** Get all vcol layers as AttributeRefs. @@ -25,14 +27,14 @@ struct VColRef { * corresponds to the integer position of the attribute * within the global color attribute list. */ -static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata, - const CustomData *cd_ldata, - const uint vcol_layers) +static Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata, + const CustomData *cd_ldata, + const uint vcol_layers) { - blender::Vector<VColRef> refs; + Vector<VColRef> refs; uint layeri = 0; - auto buildList = [&](const CustomData *cdata, AttributeDomain domain) { + auto buildList = [&](const CustomData *cdata, eAttrDomain domain) { for (int i = 0; i < cdata->totlayer; i++) { const CustomDataLayer *layer = cdata->layers + i; @@ -64,8 +66,6 @@ static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata, return refs; } -namespace blender::draw { - /* ---------------------------------------------------------------------- */ /** \name Extract VCol * \{ */ @@ -73,16 +73,16 @@ namespace blender::draw { /* Initialize the common vertex format for vcol for coarse and subdivided meshes. */ static void init_vcol_format(GPUVertFormat *format, const MeshBatchCache *cache, - CustomData *cd_vdata, - CustomData *cd_ldata, - CustomDataLayer *active, - CustomDataLayer *render) + const CustomData *cd_vdata, + const CustomData *cd_ldata, + const CustomDataLayer *active, + const CustomDataLayer *render) { GPU_vertformat_deinterleave(format); const uint32_t vcol_layers = cache->cd_used.vcol; - blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers); + Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers); for (const VColRef &ref : refs) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; @@ -111,35 +111,37 @@ static GPUVertFormat *get_coarse_vcol_format() { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "c"); GPU_vertformat_alias_add(&format, "ac"); } return &format; } -using gpuMeshVcol = struct gpuMeshVcol { +struct gpuMeshVcol { ushort r, g, b, a; }; static void extract_vcol_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *UNUSED(tls_data)) { GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); GPUVertFormat format = {0}; - CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + const CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : + &mr->me->vdata; + const CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : + &mr->me->ldata; Mesh me_query = blender::dna::shallow_zero_initialize(); BKE_id_attribute_copy_domains_temp( ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id); - CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id); - CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id); + const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id); + const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id); const uint32_t vcol_layers = cache->cd_used.vcol; init_vcol_format(&format, cache, cd_vdata, cd_ldata, active_color, render_color); @@ -149,10 +151,10 @@ static void extract_vcol_init(const MeshRenderData *mr, gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo); - blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers); + Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers); for (const VColRef &ref : refs) { - CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata; + const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata; if (mr->extract_type == MR_EXTRACT_BMESH) { int cd_ofs = ref.layer->offset; @@ -168,10 +170,10 @@ static void extract_vcol_init(const MeshRenderData *mr, BMFace *f; BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) { - BMLoop *l_iter = f->l_first; + const BMLoop *l_iter = f->l_first; do { - BMElem *elem = is_point ? reinterpret_cast<BMElem *>(l_iter->v) : - reinterpret_cast<BMElem *>(l_iter); + const BMElem *elem = is_point ? reinterpret_cast<const BMElem *>(l_iter->v) : + reinterpret_cast<const BMElem *>(l_iter); if (is_byte) { const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs); vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); @@ -193,17 +195,17 @@ static void extract_vcol_init(const MeshRenderData *mr, } else { int totloop = mr->loop_len; - int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name); + const int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name); - MLoopCol *mcol = nullptr; - MPropCol *pcol = nullptr; + const MLoopCol *mcol = nullptr; + const MPropCol *pcol = nullptr; const MLoop *mloop = mr->mloop; if (ref.layer->type == CD_PROP_COLOR) { - pcol = static_cast<MPropCol *>(cdata->layers[idx].data); + pcol = static_cast<const MPropCol *>(cdata->layers[idx].data); } else { - mcol = static_cast<MLoopCol *>(cdata->layers[idx].data); + mcol = static_cast<const MLoopCol *>(cdata->layers[idx].data); } const bool is_corner = ref.domain == ATTR_DOMAIN_CORNER; @@ -232,12 +234,12 @@ static void extract_vcol_init(const MeshRenderData *mr, static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *UNUSED(data)) { GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); - Mesh *coarse_mesh = subdiv_cache->mesh; + const Mesh *coarse_mesh = subdiv_cache->mesh; bool extract_bmesh = mr->extract_type == MR_EXTRACT_BMESH; @@ -245,13 +247,14 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, &coarse_mesh->vdata; const CustomData *cd_ldata = extract_bmesh ? &coarse_mesh->edit_mesh->bm->ldata : &coarse_mesh->ldata; + const int totloop = extract_bmesh ? coarse_mesh->edit_mesh->bm->totloop : coarse_mesh->totloop; Mesh me_query = blender::dna::shallow_copy(*coarse_mesh); BKE_id_attribute_copy_domains_temp( ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id); - CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id); - CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id); + const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id); + const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id); GPUVertFormat format = {0}; init_vcol_format( @@ -263,13 +266,13 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, /* Dynamic as we upload and interpolate layers one at a time. */ GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC); - GPU_vertbuf_data_alloc(src_data, coarse_mesh->totloop); + GPU_vertbuf_data_alloc(src_data, totloop); gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data); const uint vcol_layers = cache->cd_used.vcol; - blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers); + Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers); /* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in * a single buffer. */ @@ -279,8 +282,6 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++; const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata; - const MLoop *ml = coarse_mesh->mloop; - int layer_i = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name); if (layer_i == -1) { @@ -289,15 +290,6 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, } gpuMeshVcol *vcol = mesh_vcol; - MLoopCol *mcol = nullptr; - MPropCol *pcol = nullptr; - - if (ref.layer->type == CD_PROP_COLOR) { - pcol = static_cast<MPropCol *>(cdata->layers[layer_i].data); - } - else { - mcol = static_cast<MLoopCol *>(cdata->layers[layer_i].data); - } const bool is_vert = ref.domain == ATTR_DOMAIN_POINT; @@ -309,14 +301,15 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter = f->l_first; + const BMLoop *l_iter = f->l_first; do { - BMElem *elem = is_vert ? reinterpret_cast<BMElem *>(l_iter->v) : - reinterpret_cast<BMElem *>(l_iter); + const BMElem *elem = is_vert ? reinterpret_cast<const BMElem *>(l_iter->v) : + reinterpret_cast<const BMElem *>(l_iter); if (is_byte) { - MLoopCol *mcol2 = static_cast<MLoopCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs)); + const MLoopCol *mcol2 = static_cast<const MLoopCol *>( + BM_ELEM_CD_GET_VOID_P(elem, cd_ofs)); vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]); vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]); @@ -324,17 +317,31 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, vcol->a = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f)); } else { - MPropCol *pcol2 = static_cast<MPropCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs)); + const MPropCol *pcol2 = static_cast<const MPropCol *>( + BM_ELEM_CD_GET_VOID_P(elem, cd_ofs)); vcol->r = unit_float_to_ushort_clamp(pcol2->color[0]); vcol->g = unit_float_to_ushort_clamp(pcol2->color[1]); vcol->b = unit_float_to_ushort_clamp(pcol2->color[2]); vcol->a = unit_float_to_ushort_clamp(pcol2->color[3]); } + + vcol++; } while ((l_iter = l_iter->next) != f->l_first); } } else { + const MLoop *ml = coarse_mesh->mloop; + const MLoopCol *mcol = nullptr; + const MPropCol *pcol = nullptr; + + if (ref.layer->type == CD_PROP_COLOR) { + pcol = static_cast<const MPropCol *>(cdata->layers[layer_i].data); + } + else { + mcol = static_cast<const MLoopCol *>(cdata->layers[layer_i].data); + } + for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, ml++) { int idx = is_vert ? ml->v : ml_index; @@ -377,6 +384,4 @@ constexpr MeshExtract create_extractor_vcol() } // namespace blender::draw -extern "C" { const MeshExtract extract_vcol = blender::draw::create_extractor_vcol(); -} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc index 89aa16ca0c7..ba194a4b167 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -10,7 +10,7 @@ #include "BKE_deform.h" #include "draw_subdivision.h" -#include "extract_mesh.h" +#include "extract_mesh.hh" namespace blender::draw { @@ -79,7 +79,7 @@ static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeig } static void extract_weights_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buf, void *tls_data) { @@ -154,7 +154,7 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, - struct MeshBatchCache *cache, + MeshBatchCache *cache, void *buffer, void *_data) { @@ -208,6 +208,4 @@ constexpr MeshExtract create_extractor_weights() } // namespace blender::draw -extern "C" { const MeshExtract extract_weights = blender::draw::create_extractor_weights(); -} diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index dfa2f307800..e235da91e8d 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -5,6 +5,8 @@ * of data the CPU has to precompute and transfer for each update. */ +#define COMMON_HAIR_LIB + /* TODO(fclem): Keep documentation but remove the uniform declaration. */ #ifndef USE_GPU_SHADER_CREATE_INFO diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl index 3244b7960d8..eacdf8e6333 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl @@ -35,7 +35,7 @@ void emit_line(uint line_offset, uint quad_index, uint start_loop_index, uint co uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index, coarse_poly_count); - if (is_face_hidden(coarse_quad_index) || + if (use_hide && is_face_hidden(coarse_quad_index) || (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display)) { output_lines[line_offset + 0] = 0xffffffff; output_lines[line_offset + 1] = 0xffffffff; diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl index ce3c8478d3f..a46d69eca88 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl @@ -45,7 +45,7 @@ void main() int triangle_loop_index = (int(quad_index) + mat_offset) * 6; #endif - if (is_face_hidden(coarse_quad_index)) { + if (use_hide && is_face_hidden(coarse_quad_index)) { output_tris[triangle_loop_index + 0] = 0xffffffff; output_tris[triangle_loop_index + 1] = 0xffffffff; output_tris[triangle_loop_index + 2] = 0xffffffff; diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl index 55e4ac20271..4183b4a1cd3 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl @@ -36,6 +36,10 @@ layout(std140) uniform shader_data /* Total number of elements to process. */ uint total_dispatch_size; + + bool is_edit_mode; + + bool use_hide; }; uint get_global_invocation_index() @@ -139,20 +143,20 @@ void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos) vertex_data.z = pos.z; } -void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint flag) +/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the + * vertex normals when we cannot use the limit surface, in which case the flag and the normal are + * set by two separate compute pass. */ +void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor) { vertex_data.nx = nor.x; vertex_data.ny = nor.y; vertex_data.nz = nor.z; - vertex_data.flag = float(flag); } -/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the - * vertex normals when we cannot use the limit surface, in which case the flag and the normal are - * set by two separate compute pass. */ -void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor) +void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, float flag) { - set_vertex_nor(vertex_data, nor, 0); + set_vertex_nor(vertex_data, nor); + vertex_data.flag = flag; } void add_newell_cross_v3_v3v3(inout vec3 n, vec3 v_prev, vec3 v_curr) diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl index 0ffb216fc6f..81e346863c2 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl @@ -427,7 +427,7 @@ void main() output_nors[coarse_quad_index] = fnor; # endif - if (is_face_hidden(coarse_quad_index)) { + if (use_hide && is_face_hidden(coarse_quad_index)) { output_indices[coarse_quad_index] = 0xffffffff; } else { @@ -459,9 +459,9 @@ void main() vec3 nor = vec3(0.0); int origindex = input_vert_origindex[loop_index]; - uint flag = 0; + float flag = 0.0; if (origindex == -1) { - flag = -1; + flag = -1.0; } PosNorLoop vertex_data; diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl index b7bcfd2d369..97c07704c06 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl @@ -11,7 +11,12 @@ layout(std430, binding = 2) readonly buffer extraCoarseFaceData uint extra_coarse_face_data[]; }; -layout(std430, binding = 3) writeonly buffer outputLoopNormals +layout(std430, binding = 3) readonly buffer inputVertOrigIndices +{ + int input_vert_origindex[]; +}; + +layout(std430, binding = 4) writeonly buffer outputLoopNormals { LoopNormal output_lnor[]; }; @@ -21,6 +26,23 @@ bool is_face_selected(uint coarse_quad_index) return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0; } +bool is_face_hidden(uint coarse_quad_index) +{ + return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0; +} + +/* Flag for paint mode overlay and normals drawing in edit-mode. */ +float get_loop_flag(uint coarse_quad_index, int vert_origindex) +{ + if (is_face_hidden(coarse_quad_index) || (is_edit_mode && vert_origindex == -1)) { + return -1.0; + } + if (is_face_selected(coarse_quad_index)) { + return 1.0; + } + return 0.0; +} + void main() { /* We execute for each quad. */ @@ -39,7 +61,11 @@ void main() /* Face is smooth, use vertex normals. */ for (int i = 0; i < 4; i++) { PosNorLoop pos_nor_loop = pos_nor[start_loop_index + i]; - output_lnor[start_loop_index + i] = get_normal_and_flag(pos_nor_loop); + int origindex = input_vert_origindex[start_loop_index + i]; + LoopNormal loop_normal = get_normal_and_flag(pos_nor_loop); + loop_normal.flag = get_loop_flag(coarse_quad_index, origindex); + + output_lnor[start_loop_index + i] = loop_normal; } } else { @@ -60,13 +86,11 @@ void main() loop_normal.nx = face_normal.x; loop_normal.ny = face_normal.y; loop_normal.nz = face_normal.z; - loop_normal.flag = 0.0; - - if (is_face_selected(coarse_quad_index)) { - loop_normal.flag = 1.0; - } for (int i = 0; i < 4; i++) { + int origindex = input_vert_origindex[start_loop_index + i]; + loop_normal.flag = get_loop_flag(coarse_quad_index, origindex); + output_lnor[start_loop_index + i] = loop_normal; } } diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index c2d517588b2..9eeabf2d05e 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -4351,15 +4351,15 @@ void ANIM_channel_setting_set(bAnimContext *ac, /* --------------------------- */ -/* size of icons */ +/** Size of icons. */ #define ICON_WIDTH (0.85f * U.widget_unit) -/* width of sliders */ +/** Width of sliders. */ #define SLIDER_WIDTH (4 * U.widget_unit) -/* min-width of rename textboxes */ +/** Min-width of rename text-boxes. */ #define RENAME_TEXT_MIN_WIDTH (U.widget_unit) -/* width of graph editor color bands */ +/** Width of graph editor color bands. */ #define GRAPH_COLOR_BAND_WIDTH (0.3f * U.widget_unit) -/* extra offset for the visibility icons in the graph editor */ +/** Extra offset for the visibility icons in the graph editor. */ #define GRAPH_ICON_VISIBILITY_OFFSET (GRAPH_COLOR_BAND_WIDTH * 1.5f) /* Helper - Check if a channel needs renaming */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index f148bb5b77d..b223a1493fd 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -711,14 +711,14 @@ static bool animedit_poll_channels_active(bContext *C) /* channels region test */ /* TODO: could enhance with actually testing if channels region? */ if (ELEM(NULL, area, CTX_wm_region(C))) { - return 0; + return false; } /* animation editor test */ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) { - return 0; + return false; } - return 1; + return true; } /* Poll callback for Animation Editor channels list region + not in NLA-tweak-mode for NLA. */ @@ -730,21 +730,21 @@ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C) /* channels region test */ /* TODO: could enhance with actually testing if channels region? */ if (ELEM(NULL, area, CTX_wm_region(C))) { - return 0; + return false; } /* animation editor test */ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) { - return 0; + return false; } /* NLA tweak-mode test. */ if (area->spacetype == SPACE_NLA) { if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) { - return 0; + return false; } } - return 1; + return true; } /* ****************** Rearrange Channels Operator ******************* */ @@ -791,7 +791,7 @@ static bool rearrange_island_ok(tReorderChannelIsland *island) { /* island must not be untouchable */ if (island->flag & REORDER_ISLAND_UNTOUCHABLE) { - return 0; + return false; } /* island should be selected to be moved */ @@ -809,10 +809,10 @@ static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island) /* make it first element */ BLI_insertlinkbefore(list, list->first, island); - return 1; + return true; } - return 0; + return false; } static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island) @@ -833,11 +833,11 @@ static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island) /* push it up */ BLI_insertlinkbefore(list, prev, island); - return 1; + return true; } } - return 0; + return false; } static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island) @@ -1083,7 +1083,7 @@ static bool rearrange_animchannel_islands(ListBase *list, /* don't waste effort on an empty list */ if (BLI_listbase_is_empty(list)) { - return 0; + return false; } /* group channels into islands */ @@ -1589,7 +1589,7 @@ static bool animchannels_grouping_poll(bContext *C) /* channels region test */ /* TODO: could enhance with actually testing if channels region? */ if (ELEM(NULL, area, CTX_wm_region(C))) { - return 0; + return false; } /* animation editor test - must be suitable modes only */ @@ -1602,7 +1602,7 @@ static bool animchannels_grouping_poll(bContext *C) /* dopesheet and action only - all others are for other datatypes or have no groups */ if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0) { - return 0; + return false; } break; @@ -1612,17 +1612,17 @@ static bool animchannels_grouping_poll(bContext *C) /* drivers can't have groups... */ if (sipo->mode != SIPO_MODE_ANIMATION) { - return 0; + return false; } break; } /* unsupported... */ default: - return 0; + return false; } - return 1; + return true; } /* ----------------------------------------------------------- */ @@ -2428,15 +2428,15 @@ static bool animchannels_enable_poll(bContext *C) /* channels region test */ /* TODO: could enhance with actually testing if channels region? */ if (ELEM(NULL, area, CTX_wm_region(C))) { - return 0; + return false; } /* animation editor test - Action/Dopesheet/etc. and Graph only */ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) { - return 0; + return false; } - return 1; + return true; } static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op)) @@ -2504,7 +2504,7 @@ static bool animchannels_select_filter_poll(bContext *C) ScrArea *area = CTX_wm_area(C); if (area == NULL) { - return 0; + return false; } /* animation editor with dopesheet */ @@ -2791,13 +2791,35 @@ static bool rename_anim_channels(bAnimContext *ac, int channel_index) return false; } - /* don't allow renaming linked channels */ - if ((ale->fcurve_owner_id != NULL && - (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) || - (ale->id != NULL && (ID_IS_LINKED(ale->id) || ID_IS_OVERRIDE_LIBRARY(ale->id)))) { + /* Don't allow renaming linked/liboverride channels. */ + if (ale->fcurve_owner_id != NULL && + (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) { ANIM_animdata_freelist(&anim_data); return false; } + if (ale->id != NULL) { + if (ID_IS_LINKED(ale->id)) { + ANIM_animdata_freelist(&anim_data); + return false; + } + /* There is one exception to not allowing renaming on liboverride channels: locally-inserted + * NLA tracks. */ + if (ID_IS_OVERRIDE_LIBRARY(ale->id)) { + switch (ale->type) { + case ANIMTYPE_NLATRACK: { + NlaTrack *nlt = (NlaTrack *)ale->data; + if ((nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0) { + ANIM_animdata_freelist(&anim_data); + return false; + } + break; + } + default: + ANIM_animdata_freelist(&anim_data); + return false; + } + } + } /* check that channel can be renamed */ acf = ANIM_channel_get_typeinfo(ale); diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 8519b2061f2..ad06b185132 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -543,7 +543,6 @@ void ED_markers_draw(const bContext *C, int flag) View2D *v2d = UI_view2d_fromcontext(C); int cfra = CTX_data_scene(C)->r.cfra; - const float line_width = GPU_line_width_get(); GPU_line_width(1.0f); rctf markers_region_rect; @@ -578,7 +577,6 @@ void ED_markers_draw(const bContext *C, int flag) } } - GPU_line_width(line_width); GPU_matrix_pop(); } diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 1b759f5dfa2..c6f68228807 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -180,7 +180,7 @@ static int add_driver_with_target(ReportList *UNUSED(reports), } else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) && (RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) { - /* Rotation Source: radians -> normal, so convert src to degrees + /* Rotation Source: radians -> normal, so convert src to degrees * (However, if both input and output is a rotation, don't apply such corrections) */ BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression)); diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc index 3356ef4d47d..8dc598e6e2d 100644 --- a/source/blender/editors/animation/keyframes_keylist.cc +++ b/source/blender/editors/animation/keyframes_keylist.cc @@ -132,7 +132,7 @@ static void ED_keylist_runtime_init_listbase(AnimKeylist *keylist) return; } - keylist->runtime.list_wrapper.first = &keylist->runtime.key_columns[0]; + keylist->runtime.list_wrapper.first = keylist->runtime.key_columns.data(); keylist->runtime.list_wrapper.last = &keylist->runtime.key_columns[keylist->column_len - 1]; } @@ -309,7 +309,7 @@ static void keylist_first_last(const struct AnimKeylist *keylist, const struct ActKeyColumn **last_column) { if (keylist->is_runtime_initialized) { - *first_column = &keylist->runtime.key_columns[0]; + *first_column = keylist->runtime.key_columns.data(); *last_column = &keylist->runtime.key_columns[keylist->column_len - 1]; } else { diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 941125b9ad5..aa99a4e50c3 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -3094,8 +3094,13 @@ bool ED_autokeyframe_pchan( return false; } -bool ED_autokeyframe_property( - bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra) +bool ED_autokeyframe_property(bContext *C, + Scene *scene, + PointerRNA *ptr, + PropertyRNA *prop, + int rnaindex, + float cfra, + const bool only_if_property_keyed) { Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); @@ -3114,7 +3119,9 @@ bool ED_autokeyframe_property( fcu = BKE_fcurve_find_by_rna_context_ui( C, ptr, prop, rnaindex_check, NULL, &action, &driven, &special); - if (fcu == NULL) { + /* Only early out when we actually want an existing F-curve already + * (e.g. auto-keyframing from buttons). */ + if (fcu == NULL && (driven || special || only_if_property_keyed)) { return changed; } @@ -3150,23 +3157,28 @@ bool ED_autokeyframe_property( ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; const eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true); + char *path = RNA_path_from_ID_to_property(ptr, prop); - /* NOTE: We use rnaindex instead of fcu->array_index, - * because a button may control all items of an array at once. - * E.g., color wheels (see T42567). */ - BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1)); + if (only_if_property_keyed) { + /* NOTE: We use rnaindex instead of fcu->array_index, + * because a button may control all items of an array at once. + * E.g., color wheels (see T42567). */ + BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1)); + } changed = insert_keyframe(bmain, reports, id, action, - ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, + (fcu && fcu->grp) ? fcu->grp->name : NULL, + fcu ? fcu->rna_path : path, rnaindex, &anim_eval_context, ts->keyframe_type, NULL, flag) != 0; - + if (path) { + MEM_freeN(path); + } WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index f9b973733af..dd43e3e6613 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -375,13 +375,10 @@ static void updateDuplicateSubtarget(EditBone *dup_bone, /* does this constraint have a subtarget in * this armature? */ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(curcon, &targets); - + if (BKE_constraint_targets_get(curcon, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if ((ct->tar == ob) && (ct->subtarget[0])) { oldtarget = get_named_editbone(editbones, ct->subtarget); @@ -409,9 +406,7 @@ static void updateDuplicateSubtarget(EditBone *dup_bone, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(curcon, &targets, 0); - } + BKE_constraint_targets_flush(curcon, &targets, 0); } } } @@ -1152,7 +1147,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) } if (axis_delta == 0.0f) { - /* both mirrored bones exist and point to eachother and overlap exactly. + /* Both mirrored bones exist and point to each other and overlap exactly. * * in this case there's no well defined solution, so de-select both and skip. */ diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 963d7ea1149..3c445f46902 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -229,7 +229,7 @@ typedef enum eCalcRollTypes { } eCalcRollTypes; static const EnumPropertyItem prop_calc_roll_types[] = { - {0, "", 0, N_("Positive"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Positive"), NULL), {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""}, {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""}, @@ -237,8 +237,7 @@ static const EnumPropertyItem prop_calc_roll_types[] = { {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""}, {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""}, - {0, "", 0, N_("Negative"), ""}, - + RNA_ENUM_ITEM_HEADING(N_("Negative"), NULL), {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""}, {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""}, @@ -246,7 +245,7 @@ static const EnumPropertyItem prop_calc_roll_types[] = { {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""}, {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""}, - {0, "", 0, N_("Other"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Other"), NULL), {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""}, {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""}, {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""}, diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index e1f2605481f..1f02e24666d 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -109,13 +109,10 @@ static void constraint_bone_name_fix(Object *ob, bConstraintTarget *ct; for (curcon = conlist->first; curcon; curcon = curcon->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(curcon, &targets); - + if (BKE_constraint_targets_get(curcon, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if (ct->tar == ob) { if (STREQ(ct->subtarget, oldname)) { @@ -124,9 +121,7 @@ static void constraint_bone_name_fix(Object *ob, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(curcon, &targets, 0); - } + BKE_constraint_targets_flush(curcon, &targets, 0); } /* action constraints */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index be4829c02be..0825d6968c6 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -68,14 +68,11 @@ static void joined_armature_fix_links_constraints(Main *bmain, bool changed = false; for (con = lb->first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if (ct->tar == srcArm) { if (ct->subtarget[0] == '\0') { @@ -90,9 +87,7 @@ static void joined_armature_fix_links_constraints(Main *bmain, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } /* action constraint? (pose constraints only) */ @@ -164,6 +159,11 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data ChannelDriver *driver = fcu->driver; DriverVar *dvar; + /* Ensure that invalid drivers gets re-evaluated in case they become valid once the join + * operation is finished. */ + fcu->flag &= ~FCURVE_DISABLED; + driver->flag &= ~DRIVER_FLAG_INVALID; + /* Fix driver references to invalid ID's */ for (dvar = driver->variables.first; dvar; dvar = dvar->next) { /* only change the used targets, since the others will need fixing manually anyway */ @@ -459,14 +459,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n if (ob->type == OB_ARMATURE) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { /* Any targets which point to original armature * are redirected to the new one only if: @@ -487,9 +484,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } } } @@ -498,14 +493,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n /* fix object-level constraints */ if (ob != origArm) { for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { /* any targets which point to original armature are redirected to the new one only if: * - the target isn't origArm/newArm itself @@ -525,9 +517,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } } } diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index d0f0bd55eea..1b78d3cc77e 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -42,6 +42,7 @@ static bool pose_group_poll(bContext *C) { if (!ED_operator_posemode_context(C)) { + CTX_wm_operator_poll_msg_set(C, "Bone groups can only be edited in pose mode"); return false; } diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index e0e5693c79b..ea54c3014ca 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1431,7 +1431,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con ret = OPERATOR_PASS_THROUGH; break; - /* quicky compare to original */ + /* Quickly compare to original. */ case EVT_TABKEY: pld->flag &= ~PL_PREVIEW_SHOWORIGINAL; pld->redraw = PL_PREVIEW_REDRAWALL; diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 8790a10f3e5..b6b5d3ee495 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -680,13 +680,10 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) { if (pchan->bone->flag & BONE_SELECTED) { for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { Object *ob = ct->tar; @@ -702,9 +699,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 1); - } + BKE_constraint_targets_flush(con, &targets, 1); } } } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 9da9845116d..4c0df48f65b 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4729,6 +4729,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot) bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], const int dist_px, + const bool vert_without_handles, const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -4744,6 +4745,9 @@ bool ED_curve_editnurb_select_pick(bContext *C, ED_view3d_viewcontext_init(C, &vc, depsgraph); copy_v2_v2_int(vc.mval, mval); + const bool use_handle_select = vert_without_handles && + (vc.v3d->overlay.handle_display != CURVE_HANDLE_NONE); + bool found = ED_curve_pick_vert_ex(&vc, 1, dist_px, &nu, &bezt, &bp, &hand, &basact); if (params->sel_op == SEL_OP_SET) { @@ -4779,7 +4783,12 @@ bool ED_curve_editnurb_select_pick(bContext *C, case SEL_OP_ADD: { if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 |= SELECT; + } + else { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); + } } else { if (hand == 0) { @@ -4800,7 +4809,12 @@ bool ED_curve_editnurb_select_pick(bContext *C, case SEL_OP_SUB: { if (bezt) { if (hand == 1) { - select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 &= ~SELECT; + } + else { + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + } if (bezt == vert) { cu->actvert = CU_ACT_NONE; } @@ -4824,13 +4838,23 @@ bool ED_curve_editnurb_select_pick(bContext *C, if (bezt) { if (hand == 1) { if (bezt->f2 & SELECT) { - select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 &= ~SELECT; + } + else { + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + } if (bezt == vert) { cu->actvert = CU_ACT_NONE; } } else { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 |= SELECT; + } + else { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); + } BKE_curve_nurb_vert_active_set(cu, nu, bezt); } } @@ -4861,7 +4885,12 @@ bool ED_curve_editnurb_select_pick(bContext *C, if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 |= SELECT; + } + else { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); + } } else { if (hand == 0) { @@ -5568,7 +5597,8 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) vc.v3d, SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ - .snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL, + .snap_target_select = (vc.obedit != NULL) ? SCE_SNAP_TARGET_NOT_ACTIVE : + SCE_SNAP_TARGET_ALL, .edit_mode_type = SNAP_GEOM_FINAL, }, mval, diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 598779c6ace..6946c09e6f1 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -105,7 +105,7 @@ struct CurveDrawData { } radius; struct { - float mouse[2]; + float mval[2]; /* Used in case we can't calculate the depth. */ float location_world[3]; @@ -463,8 +463,8 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event) } copy_v3_v3(cdd->prev.location_world, selem->location_world); - float len_sq = len_squared_v2v2(cdd->prev.mouse, selem->mval); - copy_v2_v2(cdd->prev.mouse, selem->mval); + float len_sq = len_squared_v2v2(cdd->prev.mval, selem->mval); + copy_v2_v2(cdd->prev.mval, selem->mval); if (cdd->sample.use_substeps && cdd->prev.selem) { const struct StrokeElem selem_target = *selem; @@ -1165,7 +1165,7 @@ static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { if (cdd->state == CURVE_DRAW_PAINTING) { const float mval_fl[2] = {UNPACK2(event->mval)}; - if (len_squared_v2v2(mval_fl, cdd->prev.mouse) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) { + if (len_squared_v2v2(mval_fl, cdd->prev.mval) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) { curve_draw_event_add(op, event); } } diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c index fca850076ae..729ad46877a 100644 --- a/source/blender/editors/curve/editcurve_pen.c +++ b/source/blender/editors/curve/editcurve_pen.c @@ -843,7 +843,7 @@ static bool insert_point_to_segment(const ViewContext *vc, const wmEvent *event) { Curve *cu = vc->obedit->data; CutData cd = init_cut_data(event); - float mval[2] = {UNPACK2(event->mval)}; + const float mval[2] = {UNPACK2(event->mval)}; const float threshold_dist_px = ED_view3d_select_dist_px() * SEL_DIST_FACTOR; const bool near_spline = update_cut_data_for_all_nurbs( vc, BKE_curve_editNurbs_get(cu), mval, threshold_dist_px, &cd); @@ -985,7 +985,7 @@ static void extrude_vertices_from_selected_endpoints(EditNurb *editnurb, else { BPoint *last_bp = nu1->bp + nu1->pntsu - 1; const bool first_sel = nu1->bp->f1 & SELECT; - const bool last_sel = last_bp->f1 & SELECT; + const bool last_sel = last_bp->f1 & SELECT && nu1->pntsu > 1; if (first_sel) { if (last_sel) { BPoint *new_bp = (BPoint *)MEM_mallocN((nu1->pntsu + 2) * sizeof(BPoint), __func__); @@ -1134,7 +1134,7 @@ static bool is_spline_nearby(ViewContext *vc, ListBase *nurbs = BKE_curve_editNurbs_get(cu); CutData cd = init_cut_data(event); - float mval[2] = {UNPACK2(event->mval)}; + const float mval[2] = {UNPACK2(event->mval)}; const bool nearby = update_cut_data_for_all_nurbs(vc, nurbs, mval, sel_dist, &cd); if (nearby) { @@ -1655,7 +1655,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event) else if (ELEM(event->type, LEFTMOUSE)) { if (ELEM(event->val, KM_RELEASE, KM_DBL_CLICK)) { if (delete_point && !cpd->new_point && !cpd->dragging) { - if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, ¶ms)) { + if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, ¶ms)) { cpd->acted = delete_point_under_mouse(&vc, event); } } @@ -1714,7 +1714,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event) } } else if (select_point) { - ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, ¶ms); + ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, ¶ms); } } diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt index a5d8390e7f2..3c31e8014ff 100644 --- a/source/blender/editors/curves/CMakeLists.txt +++ b/source/blender/editors/curves/CMakeLists.txt @@ -7,6 +7,7 @@ set(INC ../../blentranslation ../../depsgraph ../../functions + ../../geometry ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index 5588f7440a8..25bcba6cfb3 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -6,18 +6,24 @@ #include <atomic> +#include "BLI_devirtualize_parameters.hh" #include "BLI_utildefines.h" +#include "BLI_vector_set.hh" #include "ED_curves.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "WM_api.h" +#include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_curves.hh" +#include "BKE_geometry_set.hh" #include "BKE_layer.h" +#include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_object.h" @@ -37,8 +43,11 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "RNA_prototypes.h" +#include "GEO_reverse_uv_sampler.hh" + /** * The code below uses a suffix naming convention to indicate the coordinate space: * `cu`: Local space of the curves object that is being edited. @@ -49,6 +58,41 @@ namespace blender::ed::curves { +static bool object_has_editable_curves(const Main &bmain, const Object &object) +{ + if (object.type != OB_CURVES) { + return false; + } + if (!ELEM(object.mode, OB_MODE_SCULPT_CURVES, OB_MODE_EDIT)) { + return false; + } + if (!BKE_id_is_editable(&bmain, static_cast<const ID *>(object.data))) { + return false; + } + return true; +} + +static VectorSet<Curves *> get_unique_editable_curves(const bContext &C) +{ + VectorSet<Curves *> unique_curves; + + const Main &bmain = *CTX_data_main(&C); + + Object *object = CTX_data_active_object(&C); + if (object && object_has_editable_curves(bmain, *object)) { + unique_curves.add_new(static_cast<Curves *>(object->data)); + } + + CTX_DATA_BEGIN (&C, Object *, object, selected_objects) { + if (object_has_editable_curves(bmain, *object)) { + unique_curves.add(static_cast<Curves *>(object->data)); + } + } + CTX_DATA_END; + + return unique_curves; +} + using bke::CurvesGeometry; namespace convert_to_particle_system { @@ -143,25 +187,20 @@ static void try_convert_single_object(Object &curves_ob, } Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data); + BVHTreeFromMesh surface_bvh; + BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_me, BVHTREE_FROM_LOOPTRI, 2); + BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); }); + const Span<float3> positions_cu = curves.positions(); - const VArray<int> looptri_indices = curves.surface_triangle_indices(); const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&surface_me), BKE_mesh_runtime_looptri_len(&surface_me)}; - /* Find indices of curves that can be transferred to the old hair system. */ - Vector<int> curves_indices_to_transfer; - for (const int curve_i : curves.curves_range()) { - const int looptri_i = looptri_indices[curve_i]; - if (looptri_i >= 0 && looptri_i < looptris.size()) { - curves_indices_to_transfer.append(curve_i); - } - else { - *r_could_not_convert_some_curves = true; - } + if (looptris.is_empty()) { + *r_could_not_convert_some_curves = true; } - const int hairs_num = curves_indices_to_transfer.size(); - if (hairs_num == 0) { + const int hair_num = curves.curves_num(); + if (hair_num == 0) { return; } @@ -187,13 +226,13 @@ static void try_convert_single_object(Object &curves_ob, psys_changed_type(&surface_ob, particle_system); MutableSpan<ParticleData> particles{ - static_cast<ParticleData *>(MEM_calloc_arrayN(hairs_num, sizeof(ParticleData), __func__)), - hairs_num}; + static_cast<ParticleData *>(MEM_calloc_arrayN(hair_num, sizeof(ParticleData), __func__)), + hair_num}; /* The old hair system still uses #MFace, so make sure those are available on the mesh. */ BKE_mesh_tessface_calc(&surface_me); - /* Prepare utility data structure to map hair roots to mfaces. */ + /* Prepare utility data structure to map hair roots to #MFace's. */ const Span<int> mface_to_poly_map{ static_cast<const int *>(CustomData_get_layer(&surface_me.fdata, CD_ORIGINDEX)), surface_me.totface}; @@ -209,17 +248,23 @@ static void try_convert_single_object(Object &curves_ob, const float4x4 world_to_surface_mat = surface_to_world_mat.inverted(); const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat; - for (const int new_hair_i : curves_indices_to_transfer.index_range()) { - const int curve_i = curves_indices_to_transfer[new_hair_i]; + for (const int new_hair_i : IndexRange(hair_num)) { + const int curve_i = new_hair_i; const IndexRange points = curves.points_for_curve(curve_i); - const int looptri_i = looptri_indices[curve_i]; - const MLoopTri &looptri = looptris[looptri_i]; - const int poly_i = looptri.poly; - const float3 &root_pos_cu = positions_cu[points.first()]; const float3 root_pos_su = curves_to_surface_mat * root_pos_cu; + BVHTreeNearest nearest; + nearest.dist_sq = FLT_MAX; + BLI_bvhtree_find_nearest( + surface_bvh.tree, root_pos_su, &nearest, surface_bvh.nearest_callback, &surface_bvh); + BLI_assert(nearest.index >= 0); + + const int looptri_i = nearest.index; + const MLoopTri &looptri = looptris[looptri_i]; + const int poly_i = looptri.poly; + const int mface_i = find_mface_for_root_position( surface_me, poly_to_mface_map[poly_i], root_pos_su); const MFace &mface = surface_me.mface[mface_i]; @@ -479,7 +524,7 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op) { const AttachMode attach_mode = static_cast<AttachMode>(RNA_enum_get(op->ptr, "attach_mode")); - std::atomic<bool> found_invalid_looptri_index = false; + std::atomic<bool> found_invalid_uv = false; CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) { if (curves_ob->type != OB_CURVES) { @@ -496,9 +541,19 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op) } Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data); + MeshComponent surface_mesh_component; + surface_mesh_component.replace(&surface_mesh, GeometryOwnershipType::ReadOnly); + + VArray_Span<float2> surface_uv_map; + if (curves_id.surface_uv_map != nullptr) { + surface_uv_map = surface_mesh_component + .attribute_try_get_for_read( + curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2) + .typed<float2>(); + } + MutableSpan<float3> positions_cu = curves.positions_for_write(); - MutableSpan<int> surface_triangle_indices = curves.surface_triangle_indices_for_write(); - MutableSpan<float2> surface_triangle_coords = curves.surface_triangle_coords_for_write(); + MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write(); const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh), BKE_mesh_runtime_looptri_len(&surface_mesh)}; @@ -544,36 +599,51 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op) pos_cu += pos_diff_cu; } - surface_triangle_indices[curve_i] = looptri_index; - - const MLoopTri &looptri = surface_looptris[looptri_index]; - const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co; - const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co; - const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co; - float3 bary_coords; - interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su); - surface_triangle_coords[curve_i] = bke::curves::encode_surface_bary_coord(bary_coords); + if (!surface_uv_map.is_empty()) { + const MLoopTri &looptri = surface_looptris[looptri_index]; + const int corner0 = looptri.tri[0]; + const int corner1 = looptri.tri[1]; + const int corner2 = looptri.tri[2]; + const float2 &uv0 = surface_uv_map[corner0]; + const float2 &uv1 = surface_uv_map[corner1]; + const float2 &uv2 = surface_uv_map[corner2]; + const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co; + const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co; + const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co; + float3 bary_coords; + interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su); + const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2); + surface_uv_coords[curve_i] = uv; + } } }); break; } case AttachMode::Deform: { + if (surface_uv_map.is_empty()) { + BKE_report(op->reports, + RPT_ERROR, + "Curves do not have attachment information that can be used for deformation"); + break; + } + using geometry::ReverseUVSampler; + ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris}; + threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) { for (const int curve_i : curves_range) { const IndexRange points = curves.points_for_curve(curve_i); const int first_point_i = points.first(); const float3 old_first_point_pos_cu = positions_cu[first_point_i]; - const int looptri_index = surface_triangle_indices[curve_i]; - if (!surface_looptris.index_range().contains(looptri_index)) { - found_invalid_looptri_index = true; + const float2 uv = surface_uv_coords[curve_i]; + ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv); + if (lookup_result.type != ReverseUVSampler::ResultType::Ok) { + found_invalid_uv = true; continue; } - const MLoopTri &looptri = surface_looptris[looptri_index]; - - const float3 bary_coords = bke::curves::decode_surface_bary_coord( - surface_triangle_coords[curve_i]); + const MLoopTri &looptri = *lookup_result.looptri; + const float3 &bary_coords = lookup_result.bary_weights; const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co; const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co; @@ -597,7 +667,7 @@ static int snap_curves_to_surface_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - if (found_invalid_looptri_index) { + if (found_invalid_uv) { BKE_report(op->reports, RPT_INFO, "Could not snap some curves to the surface"); } @@ -645,6 +715,222 @@ static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot) "How to find the point on the surface to attach to"); } +static bool selection_poll(bContext *C) +{ + const Object *object = CTX_data_active_object(C); + if (object == nullptr) { + return false; + } + if (object->type != OB_CURVES) { + return false; + } + if (!BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(object->data))) { + return false; + } + return true; +} + +namespace set_selection_domain { + +static int curves_set_selection_domain_exec(bContext *C, wmOperator *op) +{ + const eAttrDomain domain = eAttrDomain(RNA_enum_get(op->ptr, "domain")); + + for (Curves *curves_id : get_unique_editable_curves(*C)) { + if (curves_id->selection_domain == domain && (curves_id->flag & CV_SCULPT_SELECTION_ENABLED)) { + continue; + } + + const eAttrDomain old_domain = eAttrDomain(curves_id->selection_domain); + curves_id->selection_domain = domain; + curves_id->flag |= CV_SCULPT_SELECTION_ENABLED; + + CurveComponent component; + component.replace(curves_id, GeometryOwnershipType::Editable); + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); + + if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) { + VArray<float> curve_selection = curves.adapt_domain( + curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + curve_selection.materialize(curves.selection_curve_float_for_write()); + component.attribute_try_delete(".selection_point_float"); + } + else if (old_domain == ATTR_DOMAIN_CURVE && domain == ATTR_DOMAIN_POINT) { + VArray<float> point_selection = curves.adapt_domain( + curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); + point_selection.materialize(curves.selection_point_float_for_write()); + component.attribute_try_delete(".selection_curve_float"); + } + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic + * attribute for now. */ + DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id); + } + + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr); + + return OPERATOR_FINISHED; +} + +} // namespace set_selection_domain + +static void CURVES_OT_set_selection_domain(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Set Select Mode"; + ot->idname = __func__; + ot->description = "Change the mode used for selection masking in curves sculpt mode"; + + ot->exec = set_selection_domain::curves_set_selection_domain_exec; + ot->poll = selection_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = prop = RNA_def_enum( + ot->srna, "domain", rna_enum_attribute_curves_domain_items, 0, "Domain", ""); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE)); +} + +namespace disable_selection { + +static int curves_disable_selection_exec(bContext *C, wmOperator *UNUSED(op)) +{ + for (Curves *curves_id : get_unique_editable_curves(*C)) { + curves_id->flag &= ~CV_SCULPT_SELECTION_ENABLED; + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic + * attribute for now. */ + DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id); + } + + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr); + + return OPERATOR_FINISHED; +} + +} // namespace disable_selection + +static void CURVES_OT_disable_selection(wmOperatorType *ot) +{ + ot->name = "Disable Selection"; + ot->idname = __func__; + ot->description = "Disable the drawing of influence of selection in sculpt mode"; + + ot->exec = disable_selection::curves_disable_selection_exec; + ot->poll = selection_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +namespace select_all { + +static bool varray_contains_nonzero(const VArray<float> &data) +{ + bool contains_nonzero = false; + devirtualize_varray(data, [&](const auto array) { + for (const int i : data.index_range()) { + if (array[i] != 0.0f) { + contains_nonzero = true; + break; + } + } + }); + return contains_nonzero; +} + +static bool any_point_selected(const CurvesGeometry &curves) +{ + return varray_contains_nonzero(curves.selection_point_float()); +} + +static bool any_point_selected(const Span<Curves *> curves_ids) +{ + for (const Curves *curves_id : curves_ids) { + if (any_point_selected(CurvesGeometry::wrap(curves_id->geometry))) { + return true; + } + } + return false; +} + +static void invert_selection(MutableSpan<float> selection) +{ + threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) { + for (const int i : range) { + selection[i] = 1.0f - selection[i]; + } + }); +} + +static int select_all_exec(bContext *C, wmOperator *op) +{ + int action = RNA_enum_get(op->ptr, "action"); + + VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C); + + if (action == SEL_TOGGLE) { + action = any_point_selected(unique_curves) ? SEL_DESELECT : SEL_SELECT; + } + + for (Curves *curves_id : unique_curves) { + if (action == SEL_SELECT) { + /* The optimization to avoid storing the selection when everything is selected causes too + * many problems at the moment, since there is no proper visualization yet. Keep the code but + * disable it for now. */ +#if 0 + CurveComponent component; + component.replace(curves_id, GeometryOwnershipType::Editable); + component.attribute_try_delete(".selection_point_float"); + component.attribute_try_delete(".selection_curve_float"); +#else + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); + MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ? + curves.selection_point_float_for_write() : + curves.selection_curve_float_for_write(); + selection.fill(1.0f); +#endif + } + else { + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); + MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ? + curves.selection_point_float_for_write() : + curves.selection_curve_float_for_write(); + if (action == SEL_DESELECT) { + selection.fill(0.0f); + } + else if (action == SEL_INVERT) { + invert_selection(selection); + } + } + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic + * attribute for now. */ + DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id); + } + + return OPERATOR_FINISHED; +} + +} // namespace select_all + +static void SCULPT_CURVES_OT_select_all(wmOperatorType *ot) +{ + ot->name = "(De)select All"; + ot->idname = __func__; + ot->description = "(De)select all control points"; + + ot->exec = select_all::select_all_exec; + ot->poll = selection_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + WM_operator_properties_select_all(ot); +} + } // namespace blender::ed::curves void ED_operatortypes_curves() @@ -653,4 +939,7 @@ void ED_operatortypes_curves() WM_operatortype_append(CURVES_OT_convert_to_particle_system); WM_operatortype_append(CURVES_OT_convert_from_particle_system); WM_operatortype_append(CURVES_OT_snap_curves_to_surface); + WM_operatortype_append(CURVES_OT_set_selection_domain); + WM_operatortype_append(SCULPT_CURVES_OT_select_all); + WM_operatortype_append(CURVES_OT_disable_selection); } diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 59370b53995..9da2c4819a3 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -776,9 +776,12 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.curves.sculpt_comb ops.curves.sculpt_cut ops.curves.sculpt_delete + ops.curves.sculpt_density ops.curves.sculpt_grow_shrink ops.curves.sculpt_pinch ops.curves.sculpt_puff + ops.curves.sculpt_slide + ops.curves.sculpt_smooth ops.curves.sculpt_snake_hook ops.generic.cursor ops.generic.select @@ -930,6 +933,7 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/brushicons/mask.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/mix.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/nudge.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/paint_select.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/pinch.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/scrape.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/smear.png SRC) @@ -967,6 +971,19 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC) + # curve sculpt + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_add.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_comb.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_cut.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_delete.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_density.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_grow_shrink.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_pinch.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_puff.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_slide.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_smooth.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_snake_hook.png SRC) + endif() data_to_c_simple(../../../../release/datafiles/startup.blend SRC) diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index ed16b8a903a..c7e782b7b89 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -33,6 +33,7 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "ED_geometry.h" #include "ED_object.h" #include "geometry_intern.hh" @@ -43,9 +44,9 @@ namespace blender::ed::geometry { static bool geometry_attributes_poll(bContext *C) { - Object *ob = ED_object_context(C); - Main *bmain = CTX_data_main(C); - ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr; + const Object *ob = ED_object_context(C); + const Main *bmain = CTX_data_main(C); + const ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr; return (ob && BKE_id_is_editable(bmain, &ob->id) && data && BKE_id_is_editable(bmain, data)) && BKE_id_attributes_supported(data); } @@ -89,8 +90,8 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op) char name[MAX_NAME]; RNA_string_get(op->ptr, "name", name); - CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); - AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); + eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); + eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain"); CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); if (layer == nullptr) { @@ -105,7 +106,7 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_render) +static void next_color_attribute(ID *id, CustomDataLayer *layer, bool is_render) { int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); @@ -128,7 +129,7 @@ static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_ } } -static void next_color_attributes(struct ID *id, CustomDataLayer *layer) +static void next_color_attributes(ID *id, CustomDataLayer *layer) { next_color_attribute(id, layer, false); /* active */ next_color_attribute(id, layer, true); /* render */ @@ -181,7 +182,7 @@ static int geometry_attribute_remove_exec(bContext *C, wmOperator *op) next_color_attributes(id, layer); - if (!BKE_id_attribute_remove(id, layer, op->reports)) { + if (!BKE_id_attribute_remove(id, layer->name, op->reports)) { return OPERATOR_CANCELLED; } @@ -218,8 +219,8 @@ static int geometry_color_attribute_add_exec(bContext *C, wmOperator *op) char name[MAX_NAME]; RNA_string_get(op->ptr, "name", name); - CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); - AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); + eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); + eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain"); CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); float color[4]; @@ -260,8 +261,11 @@ static bool geometry_attribute_convert_poll(bContext *C) if (GS(data->name) != ID_ME) { return false; } - CustomDataLayer *layer = BKE_id_attributes_active_get(data); - if (layer == nullptr) { + if (CTX_data_edit_object(C) != nullptr) { + CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode"); + return false; + } + if (BKE_id_attributes_active_get(data) == nullptr) { return false; } return true; @@ -288,9 +292,8 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) * 4. Create a new attribute based on the previously copied data. */ switch (mode) { case ConvertAttributeMode::Generic: { - const AttributeDomain dst_domain = static_cast<AttributeDomain>( - RNA_enum_get(op->ptr, "domain")); - const CustomDataType dst_type = static_cast<CustomDataType>( + const eAttrDomain dst_domain = static_cast<eAttrDomain>(RNA_enum_get(op->ptr, "domain")); + const eCustomDataType dst_type = static_cast<eCustomDataType>( RNA_enum_get(op->ptr, "data_type")); if (ELEM(dst_type, CD_PROP_STRING)) { @@ -465,7 +468,7 @@ static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op) next_color_attributes(id, layer); - if (!BKE_id_attribute_remove(id, layer, op->reports)) { + if (!BKE_id_attribute_remove(id, layer->name, op->reports)) { return OPERATOR_CANCELLED; } @@ -495,6 +498,7 @@ static bool geometry_color_attributes_remove_poll(bContext *C) return false; } + void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot) { /* identifiers */ @@ -510,6 +514,64 @@ void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + ID *id = static_cast<ID *>(ob->data); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id); + + if (layer == nullptr) { + return OPERATOR_CANCELLED; + } + + CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, layer->name, op->reports); + if (new_layer == nullptr) { + return OPERATOR_CANCELLED; + } + + BKE_id_attributes_active_color_set(id, new_layer); + + DEG_id_tag_update(id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, id); + + return OPERATOR_FINISHED; +} + +static bool geometry_color_attributes_duplicate_poll(bContext *C) +{ + if (!geometry_attributes_poll(C)) { + return false; + } + if (CTX_data_edit_object(C) != nullptr) { + CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode"); + return false; + } + + Object *ob = ED_object_context(C); + ID *data = ob ? static_cast<ID *>(ob->data) : nullptr; + + if (BKE_id_attributes_active_color_get(data) != nullptr) { + return true; + } + + return false; +} + +void GEOMETRY_OT_color_attribute_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Color Attribute"; + ot->description = "Duplicate color attribute"; + ot->idname = "GEOMETRY_OT_color_attribute_duplicate"; + + /* api callbacks */ + ot->exec = geometry_color_attribute_duplicate_exec; + ot->poll = geometry_color_attributes_duplicate_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op) { uiLayout *layout = op->layout; @@ -572,3 +634,38 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) } } // namespace blender::ed::geometry + +using blender::CPPType; +using blender::GVArray; + +bool ED_geometry_attribute_convert(Mesh *mesh, + const char *layer_name, + eCustomDataType old_type, + eAttrDomain old_domain, + eCustomDataType new_type, + eAttrDomain new_domain) +{ + CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, layer_name, old_type, old_domain); + const std::string name = layer->name; + + if (!layer) { + return false; + } + + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + GVArray src_varray = mesh_component.attribute_get_for_read(name, new_domain, new_type); + + const CPPType &cpp_type = src_varray.type(); + void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); + src_varray.materialize_to_uninitialized(new_data); + mesh_component.attribute_try_delete(name); + mesh_component.attribute_try_create(name, new_domain, new_type, AttributeInitMove(new_data)); + + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } + + return true; +} diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh index bbcb682d6bf..a1000a5d01f 100644 --- a/source/blender/editors/geometry/geometry_intern.hh +++ b/source/blender/editors/geometry/geometry_intern.hh @@ -17,6 +17,7 @@ void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot); void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot); void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot); void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot); +void GEOMETRY_OT_color_attribute_duplicate(struct wmOperatorType *ot); void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot); } // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc index 23f6e6f29f4..acac757ecf1 100644 --- a/source/blender/editors/geometry/geometry_ops.cc +++ b/source/blender/editors/geometry/geometry_ops.cc @@ -22,5 +22,6 @@ void ED_operatortypes_geometry(void) WM_operatortype_append(GEOMETRY_OT_color_attribute_add); WM_operatortype_append(GEOMETRY_OT_color_attribute_remove); WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set); + WM_operatortype_append(GEOMETRY_OT_color_attribute_duplicate); WM_operatortype_append(GEOMETRY_OT_attribute_convert); } diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c index 5b514e02099..429bf39234f 100644 --- a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c +++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c @@ -7,6 +7,8 @@ #include "../gizmo_geometry.h" +/* The numerical values in the `verts` array are used in arrow3d_gizmo.c + * If you change this mesh geometry, update the selection code also. */ static float verts[][3] = { {-0.000000, 0.012320, 0.000000}, {-0.000000, 0.012320, 0.974306}, {0.008711, 0.008711, 0.000000}, {0.008711, 0.008711, 0.974306}, diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c index a1fb0e205b1..cde702294d0 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c @@ -50,16 +50,19 @@ /* to use custom arrows exported to geom_arrow_gizmo.c */ //#define USE_GIZMO_CUSTOM_ARROWS -/** Margins to add when selecting the arrow stem. */ -#define ARROW_SELECT_THRESHOLD_PX_STEM (5 * UI_DPI_FAC) -/** Margins to add when selecting the arrow head. */ -#define ARROW_SELECT_THRESHOLD_PX_HEAD (12 * UI_DPI_FAC) +/* Margin to add when selecting the arrow. */ +#define ARROW_SELECT_THRESHOLD_PX (5) typedef struct ArrowGizmo3D { wmGizmo gizmo; GizmoCommonData data; } ArrowGizmo3D; +typedef struct ArrowGizmoInteraction { + GizmoInteraction inter; + float init_arrow_length; +} ArrowGizmoInteraction; + /* -------------------------------------------------------------------- */ static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4]) @@ -70,7 +73,10 @@ static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4] madd_v3_v3fl(r_matrix[3], arrow->gizmo.matrix_basis[2], arrow->data.offset); } -static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const float color[4]) +static void arrow_draw_geom(const ArrowGizmo3D *arrow, + const bool select, + const float color[4], + const float arrow_length) { uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); bool unbind_shader = true; @@ -113,16 +119,14 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const #ifdef USE_GIZMO_CUSTOM_ARROWS wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_arrow, select, color); #else - const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length"); - const float vec[2][3] = { {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, arrow_length}, }; if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) { - const float stem_width = (arrow->gizmo.line_width * U.pixelsize) + - (select ? ARROW_SELECT_THRESHOLD_PX_STEM : 0); + const float stem_width = arrow->gizmo.line_width * U.pixelsize + + (select ? ARROW_SELECT_THRESHOLD_PX * U.dpi_fac : 0); immUniform1f("lineWidth", stem_width); wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP); } @@ -134,7 +138,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const GPU_matrix_push(); - /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX_HEAD would be added here, however adding a + /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX would be added here, however adding a * margin in pixel space isn't so simple, nor is it as important as for the arrow stem. */ if (draw_style == ED_GIZMO_ARROW_STYLE_BOX) { const float size = 0.05f; @@ -178,6 +182,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool highlight) { wmGizmo *gz = &arrow->gizmo; + const float arrow_length = RNA_float_get(gz->ptr, "length"); float color[4]; float matrix_final[4][4]; @@ -188,19 +193,20 @@ static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool GPU_matrix_push(); GPU_matrix_mul(matrix_final); GPU_blend(GPU_BLEND_ALPHA); - arrow_draw_geom(arrow, select, color); + arrow_draw_geom(arrow, select, color, arrow_length); GPU_blend(GPU_BLEND_NONE); GPU_matrix_pop(); if (gz->interaction_data) { - GizmoInteraction *inter = gz->interaction_data; + ArrowGizmoInteraction *arrow_inter = gz->interaction_data; GPU_matrix_push(); - GPU_matrix_mul(inter->init_matrix_final); + GPU_matrix_mul(arrow_inter->inter.init_matrix_final); GPU_blend(GPU_BLEND_ALPHA); - arrow_draw_geom(arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}); + arrow_draw_geom( + arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, arrow_inter->init_arrow_length); GPU_blend(GPU_BLEND_NONE); GPU_matrix_pop(); @@ -223,9 +229,15 @@ static void gizmo_arrow_draw(const bContext *UNUSED(C), wmGizmo *gz) */ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) { + /* This following values are based on manual inspection of `verts[]` defined in + * geom_arrow_gizmo.c */ + const float head_center_z = (0.974306f + 1.268098f) / 2; + const float head_geo_x = 0.051304f; + const float stem_geo_x = 0.012320f; + /* Project into 2D space since it simplifies pixel threshold tests. */ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz; - const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length"); + const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length") * head_center_z; float matrix_final[4][4]; WM_gizmo_calc_matrix_final(gz, matrix_final); @@ -239,12 +251,15 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m copy_v2_v2(arrow_end, co); } + const float scale_final = mat4_to_scale(matrix_final); + const float head_width = ARROW_SELECT_THRESHOLD_PX * scale_final * head_geo_x; + const float stem_width = ARROW_SELECT_THRESHOLD_PX * scale_final * stem_geo_x; + float select_threshold_base = gz->line_width * U.pixelsize; + const float mval_fl[2] = {UNPACK2(mval)}; - const float arrow_stem_threshold_px = ARROW_SELECT_THRESHOLD_PX_STEM; - const float arrow_head_threshold_px = ARROW_SELECT_THRESHOLD_PX_HEAD; /* Distance to arrow head. */ - if (len_squared_v2v2(mval_fl, arrow_end) < square_f(arrow_head_threshold_px)) { + if (len_squared_v2v2(mval_fl, arrow_end) < square_f(select_threshold_base + head_width)) { return 0; } @@ -253,8 +268,8 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m const float lambda = closest_to_line_v2(co_isect, mval_fl, arrow_start, arrow_end); /* Clamp inside the line, to avoid overlapping with other gizmos, * especially around the start of the arrow. */ - if (lambda >= 0.0 && lambda <= 1.0) { - if (len_squared_v2v2(mval_fl, co_isect) < square_f(arrow_stem_threshold_px)) { + if (lambda >= 0.0f && lambda <= 1.0f) { + if (len_squared_v2v2(mval_fl, co_isect) < square_f(select_threshold_base + stem_width)) { return 0; } } @@ -373,7 +388,7 @@ static void gizmo_arrow_setup(wmGizmo *gz) static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event) { ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz; - GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__); + GizmoInteraction *inter = MEM_callocN(sizeof(ArrowGizmoInteraction), __func__); wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset"); /* Some gizmos don't use properties. */ @@ -389,6 +404,8 @@ static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *e gizmo_arrow_matrix_basis_get(gz, inter->init_matrix_basis); WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final); + ((ArrowGizmoInteraction *)inter)->init_arrow_length = RNA_float_get(gz->ptr, "length"); + gz->interaction_data = inter; return OPERATOR_RUNNING_MODAL; @@ -513,7 +530,8 @@ static void GIZMO_GT_arrow_3d(wmGizmoType *gzt) ""); RNA_def_enum_flag(gzt->srna, "transform", rna_enum_transform_items, 0, "Transform", ""); - RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX); + RNA_def_float( + gzt->srna, "length", 1.0f, -FLT_MAX, FLT_MAX, "Arrow Line Length", "", -FLT_MAX, FLT_MAX); RNA_def_float_vector( gzt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX); diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c index a0e30c7518a..11309402220 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c @@ -57,8 +57,6 @@ typedef struct ButtonGizmo2D { GPUBatch *shape_batch[2]; } ButtonGizmo2D; -#define CIRCLE_RESOLUTION 32 - /** \} */ /* -------------------------------------------------------------------- */ @@ -68,11 +66,17 @@ typedef struct ButtonGizmo2D { static void button2d_geom_draw_backdrop(const wmGizmo *gz, const float color[4], const float fill_alpha, - const bool select) + const bool select, + const float screen_scale) { float viewport[4]; GPU_viewport_size_get_f(viewport); + const float max_pixel_error = 0.25f; + int nsegments = (int)(ceilf(M_PI / acosf(1.0f - max_pixel_error / screen_scale))); + nsegments = max_ff(nsegments, 8); + nsegments = min_ff(nsegments, 1000); + GPUVertFormat *format = immVertexFormat(); /* NOTE(Metal): Prefer 3D coordinate for 2D rendering when using 3D shader. */ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); @@ -81,14 +85,14 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz, if (color[3] == 1.0 && fill_alpha == 1.0 && select == false) { immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4fv(color); - imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION); + imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments); immUnbindProgram(); immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); immUniform2fv("viewportSize", &viewport[2]); immUniform1f("lineWidth", gz->line_width * U.pixelsize); immUniformColor4fv(color); - imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION); + imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments); immUnbindProgram(); } else { @@ -97,7 +101,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz, const float fill_color[4] = {UNPACK3(color), fill_alpha * color[3]}; immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4fv(fill_color); - imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION); + imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments); immUnbindProgram(); } @@ -107,7 +111,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz, immUniform2fv("viewportSize", &viewport[2]); immUniform1f("lineWidth", gz->line_width * U.pixelsize); immUniformColor4fv(color); - imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION); + imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments); immUnbindProgram(); } } @@ -184,9 +188,11 @@ static void button2d_draw_intern(const bContext *C, GPU_matrix_mul(matrix_align); } + const float screen_scale = mat4_to_scale(matrix_final); + if (select) { BLI_assert(is_3d); - button2d_geom_draw_backdrop(gz, color, 1.0, select); + button2d_geom_draw_backdrop(gz, color, 1.0, select, screen_scale); } else { @@ -194,7 +200,7 @@ static void button2d_draw_intern(const bContext *C, if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) { const float fill_alpha = RNA_float_get(gz->ptr, "backdrop_fill_alpha"); - button2d_geom_draw_backdrop(gz, color, fill_alpha, select); + button2d_geom_draw_backdrop(gz, color, fill_alpha, select, screen_scale); } if (button->shape_batch[0] != NULL) { @@ -315,10 +321,11 @@ static int gizmo_button2d_cursor_get(wmGizmo *gz) return WM_CURSOR_DEFAULT; } +#define CIRCLE_RESOLUTION_3D 32 static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box) { ScrArea *area = CTX_wm_area(C); - float rad = CIRCLE_RESOLUTION * U.dpi_fac / 2.0f; + float rad = CIRCLE_RESOLUTION_3D * U.dpi_fac / 2.0f; const float *co = NULL; float matrix_final[4][4]; float co_proj[3]; @@ -342,6 +349,7 @@ static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box } } else { + rad = mat4_to_scale(matrix_final); co = matrix_final[3]; } diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c index 1d9fc35eda8..9b7b157dc7e 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c @@ -77,6 +77,21 @@ typedef struct DialInteraction { #define DIAL_CLIP_BIAS 0.02 /* -------------------------------------------------------------------- */ +struct Dial3dParams { + int draw_options; + float angle_ofs; + float angle_delta; + float angle_increment; + float arc_partial_angle; + float arc_inner_factor; + float *clip_plane; +}; +static void dial_3d_draw_util(const float matrix_basis[4][4], + const float matrix_final[4][4], + const float line_width, + const float color[4], + const bool select, + struct Dial3dParams *params); static void dial_geom_draw(const float color[4], const float line_width, @@ -411,23 +426,26 @@ static void dial_draw_intern( if (WM_gizmo_target_property_is_valid(gz_prop)) { angle_delta = WM_gizmo_target_property_float_get(gz, gz_prop); } + if (gz->state & WM_GIZMO_STATE_MODAL) { + angle_increment = RNA_float_get(gz->ptr, "incremental_angle"); + } } } - ED_gizmotypes_dial_3d_draw_util(gz->matrix_basis, - matrix_final, - gz->line_width, - color, - select, - &(struct Dial3dParams){ - .draw_options = draw_options, - .angle_ofs = angle_ofs, - .angle_delta = angle_delta, - .angle_increment = angle_increment, - .arc_partial_angle = arc_partial_angle, - .arc_inner_factor = arc_inner_factor, - .clip_plane = clip_plane, - }); + dial_3d_draw_util(gz->matrix_basis, + matrix_final, + gz->line_width, + color, + select, + &(struct Dial3dParams){ + .draw_options = draw_options, + .angle_ofs = angle_ofs, + .angle_delta = angle_delta, + .angle_increment = angle_increment, + .arc_partial_angle = arc_partial_angle, + .arc_inner_factor = arc_inner_factor, + .clip_plane = clip_plane, + }); } static void gizmo_dial_draw_select(const bContext *C, wmGizmo *gz, int select_id) @@ -479,6 +497,10 @@ static int gizmo_dial_modal(bContext *C, eWM_GizmoFlagTweak tweak_flag) { DialInteraction *inter = gz->interaction_data; + if (!inter) { + return OPERATOR_CANCELLED; + } + if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) { return OPERATOR_RUNNING_MODAL; } @@ -519,30 +541,33 @@ static int gizmo_dial_modal(bContext *C, static void gizmo_dial_exit(bContext *C, wmGizmo *gz, const bool cancel) { DialInteraction *inter = gz->interaction_data; - bool use_reset_value = false; - float reset_value = 0.0f; - if (cancel) { - /* Set the property for the operator and call its modal function. */ - wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset"); - if (WM_gizmo_target_property_is_valid(gz_prop)) { - use_reset_value = true; - reset_value = inter->init.prop_angle; - } - } - else { - if (inter->has_drag == false) { - PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value"); - if (RNA_property_is_set(gz->ptr, prop)) { + if (inter) { + bool use_reset_value = false; + float reset_value = 0.0f; + + if (cancel) { + /* Set the property for the operator and call its modal function. */ + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset"); + if (WM_gizmo_target_property_is_valid(gz_prop)) { use_reset_value = true; - reset_value = RNA_property_float_get(gz->ptr, prop); + reset_value = inter->init.prop_angle; + } + } + else { + if (inter->has_drag == false) { + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value"); + if (RNA_property_is_set(gz->ptr, prop)) { + use_reset_value = true; + reset_value = RNA_property_float_get(gz->ptr, prop); + } } } - } - if (use_reset_value) { - wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset"); - if (WM_gizmo_target_property_is_valid(gz_prop)) { - WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value); + if (use_reset_value) { + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset"); + if (WM_gizmo_target_property_is_valid(gz_prop)) { + WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value); + } } } @@ -564,6 +589,11 @@ static void gizmo_dial_setup(wmGizmo *gz) static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event) { + if (gz->custom_modal) { + /* #DialInteraction is only used for the inner modal. */ + return OPERATOR_RUNNING_MODAL; + } + DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__); inter->init.mval[0] = event->mval[0]; @@ -583,12 +613,12 @@ static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *ev /** \name Dial Gizmo API * \{ */ -void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4], - const float matrix_final[4][4], - const float line_width, - const float color[4], - const bool select, - struct Dial3dParams *params) +static void dial_3d_draw_util(const float matrix_basis[4][4], + const float matrix_final[4][4], + const float line_width, + const float color[4], + const bool select, + struct Dial3dParams *params) { GPU_matrix_push(); GPU_matrix_mul(matrix_final); diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c index 46fede8f6be..1ce67185c1e 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c @@ -280,7 +280,7 @@ static int gizmo_move_modal(bContext *C, CTX_wm_view3d(C), (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE), &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, .edit_mode_type = SNAP_GEOM_EDIT, .use_occlusion_test = true, }, diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index 1659afb1254..d468906f127 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -96,7 +96,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C, float r_loc[3], float r_nor[3], int r_elem_index[3], - int *r_snap_elem) + eSnapMode *r_snap_elem) { if (C) { /* Snap values are updated too late at the cursor. Be sure to update ahead of time. */ @@ -283,7 +283,7 @@ static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) ED_view3d_cursor_snap_data_update(snap_gizmo->snap_state, C, x, y); V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(); - if (snap_data->snap_elem) { + if (snap_data->snap_elem != SCE_SNAP_MODE_NONE) { return 0; } return -1; diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 011a5a66695..24de50db397 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -80,9 +80,9 @@ typedef enum eDrawStrokeFlags { GP_DRAWDATA_ONLYI2D = (1 << 3), /** special hack for drawing strokes in Image Editor (weird coordinates) */ GP_DRAWDATA_IEDITHACK = (1 << 4), - /** don't draw xray in 3D view (which is default) */ + /** Don't draw XRAY in 3D view (which is default). */ GP_DRAWDATA_NO_XRAY = (1 << 5), - /** no onionskins should be drawn (for animation playback) */ + /** No onion-skins should be drawn (for animation playback). */ GP_DRAWDATA_NO_ONIONS = (1 << 6), /** draw strokes as "volumetric" circular billboards */ GP_DRAWDATA_VOLUMETRIC = (1 << 7), diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 4f9468cc9c4..0601d009bf7 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1104,7 +1104,7 @@ static void gpencil_stroke_to_bezier(bContext *C, rad_fac, minmax_weights); - /* shift coord vects */ + /* Shift coord vectors. */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 3c8e6d6e5f5..5028baf1589 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1811,7 +1811,16 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) } else { /* Create a new layer. */ - target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false); + PropertyRNA *prop; + char name[128]; + prop = RNA_struct_find_property(op->ptr, "new_layer_name"); + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_string_get(op->ptr, prop, name); + } + else { + strcpy(name, "GP_Layer"); + } + target_layer = BKE_gpencil_layer_addnew(gpd, name, true, false); } if (target_layer == NULL) { @@ -1888,8 +1897,46 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void layer_new_name_get(bGPdata *gpd, char *rname) +{ + int index = 0; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (strstr(gpl->info, "GP_Layer")) { + index++; + } + } + + if (index == 0) { + BLI_strncpy(rname, "GP_Layer", 128); + return; + } + char *name = BLI_sprintfN("%.*s.%03d", 128, "GP_Layer", index); + BLI_strncpy(rname, name, 128); + MEM_freeN(name); +} + +static int gpencil_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + PropertyRNA *prop; + if (RNA_int_get(op->ptr, "layer") == -1) { + prop = RNA_struct_find_property(op->ptr, "new_layer_name"); + if (!RNA_property_is_set(op->ptr, prop)) { + char name[MAX_NAME]; + bGPdata *gpd = ob->data; + layer_new_name_get(gpd, name); + RNA_property_string_set(op->ptr, prop, name); + return WM_operator_props_dialog_popup(C, op, 200); + } + } + + return gpencil_move_to_layer_exec(C, op); +} + void GPENCIL_OT_move_to_layer(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Move Strokes to Layer"; ot->idname = "GPENCIL_OT_move_to_layer"; @@ -1898,15 +1945,20 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) /* callbacks */ ot->exec = gpencil_move_to_layer_exec; - ot->poll = gpencil_stroke_edit_poll; /* XXX? */ + ot->invoke = gpencil_move_to_layer_invoke; + ot->poll = gpencil_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* GPencil layer to use. */ - ot->prop = RNA_def_int( - ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX); - RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_string( + ot->srna, "new_layer_name", NULL, MAX_NAME, "Name", "Name of the newly added layer"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + ot->prop = prop; } /** \} */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 56c94e4494d..d656241c463 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -726,16 +726,16 @@ struct GP_EditableStrokes_Iter { (void)0 /** - * Iterate over all editable editcurves in the current context, - * stopping on each usable layer + stroke + curve pair (i.e. gpl, gps and gpc) + * Iterate over all editable edit-curves in the current context, + * stopping on each usable layer + stroke + curve pair (i.e. `gpl`, `gps` and `gpc`) * to perform some operations on the curve. * * \param gpl: The identifier to use for the layer of the stroke being processed. - * Choose a suitable value to avoid name clashes. + * Choose a suitable value to avoid name clashes. * \param gps: The identifier to use for current stroke being processed. - * Choose a suitable value to avoid name clashes. + * Choose a suitable value to avoid name clashes. * \param gpc: The identifier to use for current editcurve being processed. - * Choose a suitable value to avoid name clashes. + * Choose a suitable value to avoid name clashes. */ #define GP_EDITABLE_CURVES_BEGIN(gpstroke_iter, C, gpl, gps, gpc) \ { \ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 8630b7f23d4..0039dbae674 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -1482,8 +1482,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) * Changes here will likely apply there too. */ static const EnumPropertyItem gpencil_interpolation_type_items[] = { - /* interpolation */ - {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"}, + /* Interpolation. */ + RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"), {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, @@ -1495,13 +1495,10 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) "Custom", "Custom interpolation defined using a curve map"}, - /* easing */ - {0, - "", - 0, - N_("Easing (by strength)"), - "Predefined inertial transitions, useful for motion graphics (from least to most " - "''dramatic'')"}, + /* Easing. */ + RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"), + "Predefined inertial transitions, useful for motion graphics " + "(from least to most \"dramatic\")"), {GP_IPO_SINE, "SINE", ICON_IPO_SINE, @@ -1518,7 +1515,7 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) "Circular", "Circular easing (strongest and most dynamic)"}, - {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"}, + RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "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_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 01ac02a9a1d..6d0848de36d 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -829,7 +829,7 @@ static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso, mul_v2_fl(svec, fac); } - /* convert to dataspace */ + /* Convert to data-space. */ if (gps->flag & GP_STROKE_3DSPACE) { /* 3D: Project to 3D space */ bool flip; diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index a37dc99229c..e903d11a1e0 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -1701,7 +1701,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op) const bool select = (sel_op != SEL_OP_SUB); bool changed = false; - /* for bounding rect around circle (for quicky intersection testing) */ + /* For bounding `rect` around circle (for quickly intersection testing). */ rcti rect = {0}; rect.xmin = mx - radius; rect.ymin = my - radius; diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 23c385c1213..7b659511aaa 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -388,6 +388,17 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, /* Create new layer */ /* TODO: have some way of specifying that we don't want this? */ + { + /* "New Layer" entry */ + item_tmp.identifier = "__CREATE__"; + item_tmp.name = "New Layer"; + item_tmp.value = -1; + item_tmp.icon = ICON_ADD; + RNA_enum_item_add(&item, &totitem, &item_tmp); + + /* separator */ + RNA_enum_item_add_separator(&item, &totitem); + } const int tot = BLI_listbase_count(&gpd->layers); /* Existing layers */ @@ -405,17 +416,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, RNA_enum_item_add(&item, &totitem, &item_tmp); } - { - /* separator */ - RNA_enum_item_add_separator(&item, &totitem); - - /* "New Layer" entry */ - item_tmp.identifier = "__CREATE__"; - item_tmp.name = "New Layer"; - item_tmp.value = -1; - item_tmp.icon = ICON_ADD; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -525,7 +525,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps return (area->spacetype == SPACE_IMAGE); } if (gps->flag & GP_STROKE_2DSPACE) { - /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */ + /* 2D strokes (data-space) - for any 2D view (i.e. everything other than 3D view). */ return (area->spacetype != SPACE_VIEW3D); } /* view aligned - anything goes */ @@ -1149,7 +1149,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, depsgraph, v3d, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, }, &ray_start[0], &ray_normal[0], @@ -1747,7 +1747,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat float darkcolor[3]; float radius = 3.0f; - int mval_i[2] = {x, y}; + const int mval_i[2] = {x, y}; /* Check if cursor is in drawing region and has valid data-block. */ if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) { return; @@ -2962,7 +2962,7 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc, bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc, bGPDstroke *gps, - const float mouse[2], + const float mval[2], const int radius, const float diff_mat[4][4]) { @@ -2980,7 +2980,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc, rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]}; /* For mouse, add a small offset to avoid false negative in corners. */ - rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset}; + rcti rect_mouse = {mval[0] - offset, mval[0] + offset, mval[1] - offset, mval[1] + offset}; /* Check collision between both rectangles. */ return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL); @@ -2988,7 +2988,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc, bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps, const GP_SpaceConversion *gsc, - const int mouse[2], + const int mval[2], const float diff_mat[4][4]) { bool hit = false; @@ -3014,9 +3014,8 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps, BLI_lasso_boundbox(&rect, mcoords, len); /* Test if point inside stroke. */ - hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) && - BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) && - BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX)); + hit = ((!ELEM(V2D_IS_CLIPPED, mval[0], mval[1])) && BLI_rcti_isect_pt(&rect, mval[0], mval[1]) && + BLI_lasso_is_point_inside(mcoords, len, mval[0], mval[1], INT_MAX)); /* Free memory. */ MEM_SAFE_FREE(mcoords); diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index c0888968a2d..865c4e360b5 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -587,7 +587,7 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op) srgb_to_linearrgb_v4(color, color); for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) { - copy_v3_v3(pt->vert_color, color); + copy_v4_v4(pt->vert_color, color); } } } diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 3f1b8d6ecda..84512653a24 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -55,17 +55,17 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin); * finished. */ void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, - const float x, - const float y, - const int img_w, - const int img_h, - const eGPUTextureFormat gpu_format, - const bool use_filter, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, const void *rect, - const float scaleX, - const float scaleY, - const float xzoom, - const float yzoom, + float scaleX, + float scaleY, + float xzoom, + float yzoom, const float color[4]); /** diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 2c67b02611b..0f981e270a0 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -22,15 +22,53 @@ struct bScreen; /* ** clip_editor.c ** */ -/* common poll functions */ +/* Returns true when the following conditions are met: + * - Current space is Space Clip. + * - There is a movie clip opened in it. */ bool ED_space_clip_poll(struct bContext *C); +/* Returns true when the following conditions are met: + * - Current space is Space Clip. + * - It is set to Clip view. + * + * It is not required to have movie clip opened for editing. */ bool ED_space_clip_view_clip_poll(struct bContext *C); +/* Returns true when the following conditions are met: + * - Current space is Space Clip. + * - It is set to Tracking mode. + * + * It is not required to have movie clip opened for editing. */ bool ED_space_clip_tracking_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space is Space Clip. + * - It is set to Mask mode. + * + * It is not required to have mask opened for editing. */ bool ED_space_clip_maskedit_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space is Space Clip. + * - It is set to Mask mode. + * - Mask has visible and editable splines. + * + * It is not required to have mask opened for editing. */ +bool ED_space_clip_maskedit_visible_splines_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space is Space Clip. + * - It is set to Mask mode. + * - The space has mask opened. */ bool ED_space_clip_maskedit_mask_poll(struct bContext *C); +/* Returns true when the following conditions are met: + * - Current space is Space Clip. + * - It is set to Mask mode. + * - The space has mask opened. + * - Mask has visible and editable splines. */ +bool ED_space_clip_maskedit_mask_visible_splines_poll(struct bContext *C); + void ED_space_clip_get_size(struct SpaceClip *sc, int *width, int *height); void ED_space_clip_get_size_fl(struct SpaceClip *sc, float size[2]); void ED_space_clip_get_zoom(struct SpaceClip *sc, @@ -60,7 +98,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc, */ bool ED_space_clip_color_sample(struct SpaceClip *sc, struct ARegion *region, - int mval[2], + const int mval[2], float r_col[3]); void ED_clip_update_frame(const struct Main *mainp, int cfra); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 9f4833bf1d7..061b783797d 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -49,10 +49,12 @@ void ED_curve_editnurb_free(struct Object *obedit); /** * \param dist_px: Maximum distance to pick (in pixels). + * \param vert_without_handles: When true, selecting the knot doesn't select the handles. */ bool ED_curve_editnurb_select_pick(struct bContext *C, const int mval[2], int dist_px, + bool vert_without_handles, const struct SelectPick_Params *params); struct Nurb *ED_curve_add_nurbs_primitive( diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h index c3a66e4a7dd..e3b091430e8 100644 --- a/source/blender/editors/include/ED_datafiles.h +++ b/source/blender/editors/include/ED_datafiles.h @@ -103,6 +103,9 @@ extern const char datatoc_multiply_png[]; extern int datatoc_nudge_png_size; extern const char datatoc_nudge_png[]; +extern int datatoc_paint_select_png_size; +extern const char datatoc_paint_select_png[]; + extern int datatoc_pinch_png_size; extern const char datatoc_pinch_png[]; @@ -284,6 +287,41 @@ extern const char datatoc_gp_brush_erase_hard_png[]; extern int datatoc_gp_brush_erase_stroke_png_size; extern const char datatoc_gp_brush_erase_stroke_png[]; +/* curves sculpt brushes files */ + +extern int datatoc_curves_sculpt_add_png_size; +extern const char datatoc_curves_sculpt_add_png[]; + +extern int datatoc_curves_sculpt_comb_png_size; +extern const char datatoc_curves_sculpt_comb_png[]; + +extern int datatoc_curves_sculpt_cut_png_size; +extern const char datatoc_curves_sculpt_cut_png[]; + +extern int datatoc_curves_sculpt_delete_png_size; +extern const char datatoc_curves_sculpt_delete_png[]; + +extern int datatoc_curves_sculpt_density_png_size; +extern const char datatoc_curves_sculpt_density_png[]; + +extern int datatoc_curves_sculpt_grow_shrink_png_size; +extern const char datatoc_curves_sculpt_grow_shrink_png[]; + +extern int datatoc_curves_sculpt_pinch_png_size; +extern const char datatoc_curves_sculpt_pinch_png[]; + +extern int datatoc_curves_sculpt_puff_png_size; +extern const char datatoc_curves_sculpt_puff_png[]; + +extern int datatoc_curves_sculpt_slide_png_size; +extern const char datatoc_curves_sculpt_slide_png[]; + +extern int datatoc_curves_sculpt_smooth_png_size; +extern const char datatoc_curves_sculpt_smooth_png[]; + +extern int datatoc_curves_sculpt_snake_hook_png_size; +extern const char datatoc_curves_sculpt_snake_hook_png[]; + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h index 74ff968828c..4620181894a 100644 --- a/source/blender/editors/include/ED_geometry.h +++ b/source/blender/editors/include/ED_geometry.h @@ -7,12 +7,22 @@ #pragma once +#include "BKE_attribute.h" +#include "DNA_customdata_types.h" + #ifdef __cplusplus extern "C" { #endif -void ED_operatortypes_geometry(void); +struct Mesh; +void ED_operatortypes_geometry(void); +bool ED_geometry_attribute_convert(struct Mesh *mesh, + const char *layer_name, + eCustomDataType old_type, + eAttrDomain old_domain, + eCustomDataType new_type, + eAttrDomain new_domain); #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index 067e5ba4d7f..31c1f93f5bc 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -14,6 +14,8 @@ extern "C" { #endif +#include "DNA_scene_types.h" + /* initialize gizmos */ void ED_gizmotypes_arrow_3d(void); void ED_gizmotypes_button_2d(void); @@ -223,24 +225,6 @@ enum { /* -------------------------------------------------------------------- */ /* Specific gizmos utils */ -/* dial3d_gizmo.c */ - -struct Dial3dParams { - int draw_options; - float angle_ofs; - float angle_delta; - float angle_increment; - float arc_partial_angle; - float arc_inner_factor; - float *clip_plane; -}; -void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4], - const float matrix_final[4][4], - float line_width, - const float color[4], - bool select, - struct Dial3dParams *params); - /* snap3d_gizmo.c */ struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene, @@ -258,7 +242,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C, float r_loc[3], float r_nor[3], int r_elem_index[3], - int *r_snap_elem); + eSnapMode *r_snap_elem); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 01f60a81288..0943636a452 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -579,7 +579,7 @@ void ED_gpencil_init_random_settings(struct Brush *brush, */ bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc, struct bGPDstroke *gps, - const float mouse[2], + const float mval[2], int radius, const float diff_mat[4][4]); /** @@ -587,13 +587,13 @@ bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc, * * \param gps: Stroke to check. * \param gsc: Space conversion data. - * \param mouse: Mouse position. + * \param mval: Region relative cursor position. * \param diff_mat: View matrix. * \return True if the point is inside. */ bool ED_gpencil_stroke_point_is_inside(const struct bGPDstroke *gps, const struct GP_SpaceConversion *gsc, - const int mouse[2], + const int mval[2], const float diff_mat[4][4]); /** * Get the bigger 2D bound box points. diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 774115fa188..91ae8286531 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -24,6 +24,7 @@ struct Scene; struct SpaceImage; struct View2D; struct bContext; +struct Paint; struct wmOperator; struct wmWindowManager; @@ -63,8 +64,11 @@ bool ED_space_image_get_position(struct SpaceImage *sima, /** * Returns color in linear space, matching #ED_space_node_color_sample(). */ -bool ED_space_image_color_sample( - struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data); +bool ED_space_image_color_sample(struct SpaceImage *sima, + struct ARegion *region, + const int mval[2], + float r_col[3], + bool *r_is_data); struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile); /** * Get the #SpaceImage flag that is valid for the given ibuf. @@ -133,8 +137,39 @@ bool ED_space_image_paint_curve(const struct bContext *C); * Matches clip function. */ bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct Object *obedit); + +/* Returns true when the following conditions are met: + * - Current space is Image Editor. + * - The image editor is not a UV Editor. + * - It is set to Mask mode. + * + * It is not required to have mask opened for editing. */ bool ED_space_image_maskedit_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space is Image Editor. + * - The image editor is not a UV Editor. + * - It is set to Mask mode. + * - Mask has visible and editable splines. + * + * It is not required to have mask opened for editing. */ +bool ED_space_image_maskedit_visible_splines_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space is Image Editor. + * - The image editor is not an UV Editor. + * - It is set to Mask mode. + * - The space has mask opened. */ bool ED_space_image_maskedit_mask_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space is Image Editor. + * - The image editor is not an UV Editor. + * - It is set to Mask mode. + * - The space has mask opened. + * - Mask has visible and editable splines. */ +bool ED_space_image_maskedit_mask_visible_splines_poll(struct bContext *C); + bool ED_space_image_cursor_poll(struct bContext *C); /** @@ -187,6 +222,9 @@ ListBase ED_image_filesel_detect_sequences(struct Main *bmain, struct wmOperator *op, bool detect_udim); +bool ED_image_tools_paint_poll(struct bContext *C); +void ED_paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C)); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 8c0147612fb..a53042b70d6 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -658,15 +658,20 @@ bool ED_autokeyframe_pchan(struct bContext *C, struct Object *ob, struct bPoseChannel *pchan, struct KeyingSet *ks); + /** - * Use for auto-key-framing from the UI. + * Use for auto-key-framing + * \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed + * properties. This is by design when using buttons. For other callers such as gizmos or VSE + * preview transform, creating new animation/keyframes also on non-keyed properties is desired. */ bool ED_autokeyframe_property(struct bContext *C, struct Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, - float cfra); + float cfra, + bool only_if_property_keyed); /* Names for builtin keying sets so we don't confuse these with labels/text, * defined in python script: `keyingsets_builtins.py`. */ diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 7039d6d9fc7..8cadbfde185 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -22,6 +22,34 @@ struct wmKeyConfig; /* mask_edit.c */ +/* Returns true when the following conditions are met: + * - Current space supports mask editing. + * - The space is configured to interact with mask. + * + * It is not required to have mask opened for editing. */ +bool ED_maskedit_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space supports mask editing. + * - The space is configured to interact with mask. + * - Mask has visible and editable splines. + * + * It is not required to have mask opened for editing. */ +bool ED_maskedit_visible_splines_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space supports mask editing. + * - The space is configured to interact with mask. + * - The space has mask open for editing. */ +bool ED_maskedit_mask_poll(struct bContext *C); + +/* Returns true when the following conditions are met: + * - Current space supports mask editing. + * - The space is configured to interact with mask. + * - The space has mask opened. + * - Mask has visible and editable splines. */ +bool ED_maskedit_mask_visible_splines_poll(struct bContext *C); + void ED_mask_deselect_all(const struct bContext *C); void ED_operatortypes_mask(void); @@ -73,6 +101,7 @@ void ED_mask_draw_region(struct Depsgraph *depsgraph, char draw_flag, char draw_type, eMaskOverlayMode overlay_mode, + float blend_factor, int width_i, int height_i, float aspx, diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 0078c1087a0..39c7ad3556c 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -536,12 +536,12 @@ bool ED_object_modifier_move_to_index(struct ReportList *reports, struct ModifierData *md, int index); -bool ED_object_modifier_convert(struct ReportList *reports, - struct Main *bmain, - struct Depsgraph *depsgraph, - struct ViewLayer *view_layer, - struct Object *ob, - struct ModifierData *md); +bool ED_object_modifier_convert_psys_to_mesh(struct ReportList *reports, + struct Main *bmain, + struct Depsgraph *depsgraph, + struct ViewLayer *view_layer, + struct Object *ob, + struct ModifierData *md); bool ED_object_modifier_apply(struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph, diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index aa62a6209e4..a24c8625a63 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -595,7 +595,6 @@ bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext bool ED_operator_posemode_context(struct bContext *C); bool ED_operator_posemode(struct bContext *C); bool ED_operator_posemode_local(struct bContext *C); -bool ED_operator_mask(struct bContext *C); bool ED_operator_camera_poll(struct bContext *C); /* screen_user_menu.c */ diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 54d67c50d5c..550040d2bc6 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -51,7 +51,7 @@ void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, int new_id); int ED_sculpt_face_sets_active_update_and_get(struct bContext *C, struct Object *ob, - const float mval[2]); + const float mval_fl[2]); /* Undo for changes happening on a base mesh for multires sculpting. * if there is no multi-res sculpt active regular undo is used. */ diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h index fa02ebe18f6..8c856794ec8 100644 --- a/source/blender/editors/include/ED_select_utils.h +++ b/source/blender/editors/include/ED_select_utils.h @@ -40,11 +40,11 @@ typedef enum { } eSelectOp; /* Select Similar */ -enum { +typedef enum { SIM_CMP_EQ = 0, SIM_CMP_GT, SIM_CMP_LT, -}; +} eSimilarCmp; #define SEL_OP_USE_OUTSIDE(sel_op) (ELEM(sel_op, SEL_OP_AND)) #define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET)) @@ -63,11 +63,11 @@ int ED_select_op_action(eSelectOp sel_op, bool is_select, bool is_inside); */ int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside); -int ED_select_similar_compare_float(float delta, float thresh, int compare); +bool ED_select_similar_compare_float(float delta, float thresh, eSimilarCmp compare); bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree, float length, float thresh, - int compare); + eSimilarCmp compare); /** * Utility to use for selection operations that run multiple times (circle select). diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 2919001c5ce..20353c21f93 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -6,6 +6,8 @@ #pragma once +#include "DNA_scene_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -25,14 +27,6 @@ struct View3D; /* ED_transform_snap_object_*** API */ -typedef enum eSnapSelect { - SNAP_ALL = 0, - SNAP_NOT_SELECTED = 1, - SNAP_NOT_ACTIVE = 2, - SNAP_NOT_EDITED = 3, - SNAP_SELECTABLE = 4, -} eSnapSelect; - typedef enum eSnapEditType { SNAP_GEOM_FINAL = 0, SNAP_GEOM_CAGE = 1, @@ -59,7 +53,7 @@ struct SnapObjectHitDepth { /** parameters that define which objects will be used to snap. */ struct SnapObjectParams { /* Special context sensitive handling for the active or selected object. */ - eSnapSelect snap_select; + eSnapTargetSelect snap_target_select; /* Geometry for snapping in edit mode. */ eSnapEditType edit_mode_type; /* snap to the closest element, use when using more than one snap type */ @@ -120,21 +114,21 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, bool sort, struct ListBase *r_hit_list); -short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, - struct Depsgraph *depsgraph, - const ARegion *region, - const View3D *v3d, - unsigned short snap_to, - const struct SnapObjectParams *params, - const float mval[2], - const float prev_co[3], - float *dist_px, - float r_loc[3], - float r_no[3], - int *r_index, - struct Object **r_ob, - float r_obmat[4][4], - float r_face_nor[3]); +eSnapMode ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, + struct Depsgraph *depsgraph, + const ARegion *region, + const View3D *v3d, + eSnapMode snap_to, + const struct SnapObjectParams *params, + const float mval[2], + const float prev_co[3], + float *dist_px, + float r_loc[3], + float r_no[3], + int *r_index, + struct Object **r_ob, + float r_obmat[4][4], + float r_face_nor[3]); /** * Convenience function for performing snapping. * @@ -148,18 +142,18 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, * \param r_no: hit normal (optional). * \return Snap success. */ -short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, - struct Depsgraph *depsgraph, - const ARegion *region, - const View3D *v3d, - unsigned short snap_to, - const struct SnapObjectParams *params, - const float mval[2], - const float prev_co[3], - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3]); +eSnapMode ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, + struct Depsgraph *depsgraph, + const ARegion *region, + const View3D *v3d, + eSnapMode snap_to, + const struct SnapObjectParams *params, + const float mval[2], + const float prev_co[3], + float *dist_px, + /* return args */ + float r_loc[3], + float r_no[3]); /** * see: #ED_transform_snap_object_project_ray_all diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 8695e03a57f..0298983ed26 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -8,6 +8,7 @@ #pragma once #include "BLI_utildefines.h" +#include "DNA_scene_types.h" #ifdef __cplusplus extern "C" { @@ -299,7 +300,7 @@ typedef enum { } eV3DPlaceOrient; typedef struct V3DSnapCursorData { - short snap_elem; + eSnapMode snap_elem; float loc[3]; float nor[3]; float obmat[4][4]; @@ -322,7 +323,7 @@ typedef struct V3DSnapCursorState { struct wmGizmoGroupType *gzgrp_type; /* Force cursor to be drawn only when gizmo is available. */ float *prevpoint; float box_dimensions[3]; - short snap_elem_force; /* If zero, use scene settings. */ + eSnapMode snap_elem_force; /* If SCE_SNAP_MODE_NONE, use scene settings. */ short plane_axis; bool use_plane_axis_auto; bool draw_point; @@ -347,7 +348,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d, const float normal[3], const uchar color_line[4], const uchar color_point[4], - short snap_elem_type); + eSnapMode snap_elem_type); /* view3d_iterators.c */ diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh new file mode 100644 index 00000000000..6f553f4fad1 --- /dev/null +++ b/source/blender/editors/include/UI_grid_view.hh @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup editorui + * + * API for simple creation of grid UIs, supporting typically needed features. + * https://wiki.blender.org/wiki/Source/Interface/Views/Grid_Views + */ + +#pragma once + +#include "BLI_function_ref.hh" +#include "BLI_map.hh" +#include "BLI_vector.hh" + +#include "UI_resources.h" + +struct bContext; +struct PreviewImage; +struct uiBlock; +struct uiButGridTile; +struct uiLayout; +struct View2D; +struct wmNotifier; + +namespace blender::ui { + +class AbstractGridView; + +/* ---------------------------------------------------------------------- */ +/** \name Grid-View Item Type + * \{ */ + +class AbstractGridViewItem { + friend class AbstractGridView; + friend class GridViewLayoutBuilder; + + const AbstractGridView *view_; + + bool is_active_ = false; + + protected: + /** Reference to a string that uniquely identifies this item in the view. */ + StringRef identifier_{}; + /** Every visible item gets a button of type #UI_BTYPE_GRID_TILE during the layout building. */ + uiButGridTile *grid_tile_but_ = nullptr; + + public: + virtual ~AbstractGridViewItem() = default; + + virtual void build_grid_tile(uiLayout &layout) const = 0; + + /** + * Compare this item's identifier to \a other to check if they represent the same data. + * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active, + * renaming, etc.). + */ + bool matches(const AbstractGridViewItem &other) const; + + const AbstractGridView &get_view() const; + + /** + * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we + * can't be sure about the item state. + */ + bool is_active() const; + + protected: + AbstractGridViewItem(StringRef identifier); + + /** Called when the item's state changes from inactive to active. */ + virtual void on_activate(); + /** + * If the result is not empty, it controls whether the item should be active or not, + * usually depending on the data that the view represents. + */ + virtual std::optional<bool> should_be_active() const; + + /** + * Copy persistent state (e.g. active, selection, etc.) from a matching item of + * the last redraw to this item. If sub-classes introduce more advanced state they should + * override this and make it update their state accordingly. + */ + virtual void update_from_old(const AbstractGridViewItem &old); + + /** + * Activates this item, deactivates other items, and calls the + * #AbstractGridViewItem::on_activate() function. + * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the + * actual item state is unknown, possibly calling state-change update functions incorrectly. + */ + void activate(); + void deactivate(); + + private: + /** See #AbstractTreeView::change_state_delayed() */ + void change_state_delayed(); + static void grid_tile_click_fn(bContext *, void *but_arg1, void *); + void add_grid_tile_button(uiBlock &block); +}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Grid-View Base Class + * \{ */ + +struct GridViewStyle { + GridViewStyle(int width, int height); + int tile_width = 0; + int tile_height = 0; +}; + +class AbstractGridView { + friend class AbstractGridViewItem; + friend class GridViewBuilder; + friend class GridViewLayoutBuilder; + + protected: + Vector<std::unique_ptr<AbstractGridViewItem>> items_; + /** <identifier, item> map to lookup items by identifier, used for efficient lookups in + * #update_from_old(). */ + Map<StringRef, AbstractGridViewItem *> item_map_; + GridViewStyle style_; + bool is_reconstructed_ = false; + + public: + AbstractGridView(); + virtual ~AbstractGridView() = default; + + using ItemIterFn = FunctionRef<void(AbstractGridViewItem &)>; + void foreach_item(ItemIterFn iter_fn) const; + + /** Listen to a notifier, returning true if a redraw is needed. */ + virtual bool listen(const wmNotifier &) const; + + /** + * Convenience wrapper constructing the item by forwarding given arguments to the constructor of + * the type (\a ItemT). + * + * E.g. if your grid-item type has the following constructor: + * \code{.cpp} + * MyGridItem(std::string str, int i); + * \endcode + * You can add an item like this: + * \code + * add_item<MyGridItem>("blabla", 42); + * \endcode + */ + template<class ItemT, typename... Args> inline ItemT &add_item(Args &&...args); + const GridViewStyle &get_style() const; + int get_item_count() const; + + protected: + virtual void build_items() = 0; + + /** + * Check if the view is fully (re-)constructed. That means, both #build_items() and + * #update_from_old() have finished. + */ + bool is_reconstructed() const; + + private: + /** + * Match the grid-view against an earlier version of itself (if any) and copy the old UI state + * (e.g. active, selected, renaming, etc.) to the new one. See + * #AbstractGridViewItem.update_from_old(). + */ + void update_from_old(uiBlock &new_block); + AbstractGridViewItem *find_matching_item(const AbstractGridViewItem &item_to_match, + const AbstractGridView &view_to_search_in) const; + /** + * Items may want to do additional work when state changes. But these state changes can only be + * reliably detected after the view has completed reconstruction (see #is_reconstructed()). So + * the actual state changes are done in a delayed manner through this function. + */ + void change_state_delayed(); + + /** + * Add an already constructed item, moving ownership to the grid-view. + * All items must be added through this, it handles important invariants! + */ + AbstractGridViewItem &add_item(std::unique_ptr<AbstractGridViewItem> item); +}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Grid-View Builder + * + * TODO unify this with `TreeViewBuilder` and call view-specific functions via type erased view? + * \{ */ + +class GridViewBuilder { + uiBlock &block_; + + public: + GridViewBuilder(uiBlock &block); + + /** Build \a grid_view into the previously provided block, clipped by \a view_bounds (view space, + * typically `View2D.cur`). */ + void build_grid_view(AbstractGridView &grid_view, const View2D &v2d); +}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Predefined Grid-View Item Types + * + * Common, Basic Grid-View Item Types. + * \{ */ + +/** + * A grid item that shows preview image icons at a nicely readable size (multiple of the normal UI + * unit size). + */ +class PreviewGridItem : public AbstractGridViewItem { + public: + using IsActiveFn = std::function<bool()>; + using ActivateFn = std::function<void(PreviewGridItem &new_active)>; + + protected: + /** See #set_on_activate_fn() */ + ActivateFn activate_fn_; + /** See #set_is_active_fn() */ + IsActiveFn is_active_fn_; + + public: + std::string label{}; + int preview_icon_id = ICON_NONE; + + PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id); + + void build_grid_tile(uiLayout &layout) const override; + + /** + * Set a custom callback to execute when activating this view item. This way users don't have to + * sub-class #PreviewGridItem, just to implement custom activation behavior (a common thing to + * do). + */ + void set_on_activate_fn(ActivateFn fn); + /** + * Set a custom callback to check if this item should be active. + */ + void set_is_active_fn(IsActiveFn fn); + + private: + std::optional<bool> should_be_active() const override; + void on_activate() override; +}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ + +template<class ItemT, typename... Args> inline ItemT &AbstractGridView::add_item(Args &&...args) +{ + static_assert(std::is_base_of<AbstractGridViewItem, ItemT>::value, + "Type must derive from and implement the AbstractGridViewItem interface"); + + return dynamic_cast<ItemT &>(add_item(std::make_unique<ItemT>(std::forward<Args>(args)...))); +} + +} // namespace blender::ui diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index ea1095b26ff..f1c0acf43f7 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -891,6 +891,7 @@ DEF_ICON_COLOR(BRUSH_LAYER) DEF_ICON_COLOR(BRUSH_MASK) DEF_ICON_COLOR(BRUSH_MIX) DEF_ICON_COLOR(BRUSH_NUDGE) +DEF_ICON_COLOR(BRUSH_PAINT_SELECT) DEF_ICON_COLOR(BRUSH_PINCH) DEF_ICON_COLOR(BRUSH_SCRAPE) DEF_ICON_COLOR(BRUSH_SCULPT_DRAW) @@ -903,7 +904,6 @@ DEF_ICON_COLOR(BRUSH_TEXFILL) DEF_ICON_COLOR(BRUSH_TEXMASK) DEF_ICON_COLOR(BRUSH_THUMB) DEF_ICON_COLOR(BRUSH_ROTATE) -DEF_ICON_COLOR(BRUSH_PAINT) /* grease pencil sculpt */ DEF_ICON_COLOR(GPBRUSH_SMOOTH) @@ -929,6 +929,19 @@ DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT) DEF_ICON_COLOR(GPBRUSH_ERASE_HARD) DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE) +/* Curves sculpt. */ +DEF_ICON_COLOR(BRUSH_CURVES_ADD) +DEF_ICON_COLOR(BRUSH_CURVES_COMB) +DEF_ICON_COLOR(BRUSH_CURVES_CUT) +DEF_ICON_COLOR(BRUSH_CURVES_DELETE) +DEF_ICON_COLOR(BRUSH_CURVES_DENSITY) +DEF_ICON_COLOR(BRUSH_CURVES_GROW_SHRINK) +DEF_ICON_COLOR(BRUSH_CURVES_PINCH) +DEF_ICON_COLOR(BRUSH_CURVES_PUFF) +DEF_ICON_COLOR(BRUSH_CURVES_SLIDE) +DEF_ICON_COLOR(BRUSH_CURVES_SMOOTH) +DEF_ICON_COLOR(BRUSH_CURVES_SNAKE_HOOK) + /* Vector icons. */ DEF_ICON_VECTOR(KEYTYPE_KEYFRAME_VEC) DEF_ICON_VECTOR(KEYTYPE_BREAKDOWN_VEC) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a9a9c98cab8..b2ec2102ddd 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -64,6 +64,7 @@ struct wmKeyMapItem; struct wmMsgBus; struct wmOperator; struct wmOperatorType; +struct wmRegionListenerParams; struct wmWindow; typedef struct uiBlock uiBlock; @@ -75,6 +76,10 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle; typedef struct uiTreeViewHandle uiTreeViewHandle; /* C handle for C++ #ui::AbstractTreeViewItem type. */ typedef struct uiTreeViewItemHandle uiTreeViewItemHandle; +/* C handle for C++ #ui::AbstractGridView type. */ +typedef struct uiGridViewHandle uiGridViewHandle; +/* C handle for C++ #ui::AbstractGridViewItem type. */ +typedef struct uiGridViewItemHandle uiGridViewItemHandle; /* Defines */ @@ -390,6 +395,8 @@ typedef enum { UI_BTYPE_DECORATOR = 58 << 9, /* An item in a tree view. Parent items may be collapsible. */ UI_BTYPE_TREEROW = 59 << 9, + /* An item in a grid view. */ + UI_BTYPE_GRID_TILE = 60 << 9, } eButType; #define BUTTYPE (63 << 9) @@ -851,33 +858,6 @@ void UI_block_translate(uiBlock *block, int x, int y); int UI_but_return_value_get(uiBut *but); -void UI_but_drag_set_id(uiBut *but, struct ID *id); -/** - * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`). - * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image. - */ -void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale); -/** - * \param asset: May be passed from a temporary variable, drag data only stores a copy of this. - */ -void UI_but_drag_set_asset(uiBut *but, - const struct AssetHandle *asset, - const char *path, - struct AssetMetaData *metadata, - int import_type, /* eFileAssetImportType */ - int icon, - struct ImBuf *imb, - float scale); -void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr); -void UI_but_drag_set_path(uiBut *but, const char *path, bool use_free); -void UI_but_drag_set_name(uiBut *but, const char *name); -/** - * Value from button itself. - */ -void UI_but_drag_set_value(uiBut *but); -void UI_but_drag_set_image( - uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free); - uiBut *UI_but_active_drop_name_button(const struct bContext *C); /** * Returns true if highlighted button allows drop of names. @@ -1767,6 +1747,14 @@ struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon); struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon); +/** + * A decent size for a button (typically #UI_BTYPE_PREVIEW_TILE) to display a nicely readable + * preview with label in. + */ +int UI_preview_tile_size_x(void); +int UI_preview_tile_size_y(void); +int UI_preview_tile_size_y_no_label(void); + /* Autocomplete * * Tab complete helper functions, for use in uiButCompleteFunc callbacks. @@ -1783,6 +1771,38 @@ AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxlen); void UI_autocomplete_update_name(AutoComplete *autocpl, const char *name); int UI_autocomplete_end(AutoComplete *autocpl, char *autoname); +/* Button drag-data (interface_drag.cc). + * + * Functions to set drag data for buttons. This enables dragging support, whereby the drag data is + * "dragged", not the button itself. */ + +void UI_but_drag_set_id(uiBut *but, struct ID *id); +/** + * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`). + * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image. + */ +void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale); +/** + * \param asset: May be passed from a temporary variable, drag data only stores a copy of this. + */ +void UI_but_drag_set_asset(uiBut *but, + const struct AssetHandle *asset, + const char *path, + struct AssetMetaData *metadata, + int import_type, /* eFileAssetImportType */ + int icon, + struct ImBuf *imb, + float scale); +void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr); +void UI_but_drag_set_path(uiBut *but, const char *path, bool use_free); +void UI_but_drag_set_name(uiBut *but, const char *name); +/** + * Value from button itself. + */ +void UI_but_drag_set_value(uiBut *but); +void UI_but_drag_set_image( + uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free); + /* Panels * * Functions for creating, freeing and drawing panels. The API here @@ -1866,7 +1886,7 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex const struct wmEvent *event); void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data); -/* Polyinstantiated panels for representing a list of data. */ +/* Poly-instantiated panels for representing a list of data. */ /** * Called in situations where panels need to be added dynamically rather than * having only one panel corresponding to each #PanelType. @@ -3180,7 +3200,12 @@ void UI_interface_tag_script_reload(void); /* Support click-drag motion which presses the button and closes a popover (like a menu). */ #define USE_UI_POPOVER_ONCE +void UI_block_views_listen(const uiBlock *block, + const struct wmRegionListenerParams *listener_params); + +bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle); bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item); +bool UI_grid_view_item_matches(const uiGridViewItemHandle *a, const uiGridViewItemHandle *b); bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b); /** * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't @@ -3218,6 +3243,15 @@ uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *regi const int xy[2]) ATTR_NONNULL(1, 2); uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region); +/** + * Listen to \a notifier, returning true if the region should redraw. + */ +bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view, const wmNotifier *notifier); +/** + * Listen to \a notifier, returning true if the region should redraw. + */ +bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view, const wmNotifier *notifier); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index db43ec54431..3dc56b01993 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -23,6 +23,7 @@ struct uiSearchItems; namespace blender::ui { +class AbstractGridView; class AbstractTreeView; /** @@ -55,6 +56,10 @@ void attribute_search_add_items( /** * Override this for all available tree types. */ +blender::ui::AbstractGridView *UI_block_add_view( + uiBlock &block, + blender::StringRef idname, + std::unique_ptr<blender::ui::AbstractGridView> tree_view); blender::ui::AbstractTreeView *UI_block_add_view( uiBlock &block, blender::StringRef idname, diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 5504e426f34..1aeb13ca5cc 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -28,6 +28,7 @@ struct uiButTreeRow; struct uiLayout; struct wmDrag; struct wmEvent; +struct wmNotifier; namespace blender::ui { @@ -128,6 +129,9 @@ class AbstractTreeView : public TreeViewItemContainer { void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const; + /** Listen to a notifier, returning true if a redraw is needed. */ + virtual bool listen(const wmNotifier &) const; + /** Only one item can be renamed at a time. */ bool is_renaming() const; @@ -185,7 +189,7 @@ class AbstractTreeViewItem : public TreeViewItemContainer { bool is_renaming_ = false; protected: - /** This label is used for identifying an item within its parent. */ + /** This label is used as the default way to identifying an item within its parent. */ std::string label_{}; /** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */ uiButTreeRow *tree_row_but_ = nullptr; diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 444bb08f3fb..2a1852bd6e7 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -25,12 +25,14 @@ set(INC ) set(SRC + grid_view.cc interface.cc interface_align.c interface_anim.c interface_button_group.c interface_context_menu.c interface_context_path.cc + interface_drag.cc interface_draw.c interface_dropboxes.cc interface_eyedropper.c diff --git a/source/blender/editors/interface/grid_view.cc b/source/blender/editors/interface/grid_view.cc new file mode 100644 index 00000000000..a82cb7798fe --- /dev/null +++ b/source/blender/editors/interface/grid_view.cc @@ -0,0 +1,525 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edinterface + */ + +#include <limits> +#include <stdexcept> + +#include "BLI_index_range.hh" + +#include "WM_types.h" + +#include "UI_interface.h" +#include "interface_intern.h" + +#include "UI_grid_view.hh" + +namespace blender::ui { + +/* ---------------------------------------------------------------------- */ + +AbstractGridView::AbstractGridView() : style_(UI_preview_tile_size_x(), UI_preview_tile_size_y()) +{ +} + +AbstractGridViewItem &AbstractGridView::add_item(std::unique_ptr<AbstractGridViewItem> item) +{ + items_.append(std::move(item)); + + AbstractGridViewItem &added_item = *items_.last(); + added_item.view_ = this; + + item_map_.add(added_item.identifier_, &added_item); + + return added_item; +} + +void AbstractGridView::foreach_item(ItemIterFn iter_fn) const +{ + for (auto &item_ptr : items_) { + iter_fn(*item_ptr); + } +} + +bool AbstractGridView::listen(const wmNotifier &) const +{ + /* Nothing by default. */ + return false; +} + +AbstractGridViewItem *AbstractGridView::find_matching_item( + const AbstractGridViewItem &item_to_match, const AbstractGridView &view_to_search_in) const +{ + AbstractGridViewItem *const *match = view_to_search_in.item_map_.lookup_ptr( + item_to_match.identifier_); + BLI_assert(!match || item_to_match.matches(**match)); + + return match ? *match : nullptr; +} + +void AbstractGridView::change_state_delayed() +{ + BLI_assert_msg( + is_reconstructed(), + "These state changes are supposed to be delayed until reconstruction is completed"); + foreach_item([](AbstractGridViewItem &item) { item.change_state_delayed(); }); +} + +void AbstractGridView::update_from_old(uiBlock &new_block) +{ + uiGridViewHandle *old_view_handle = ui_block_grid_view_find_matching_in_old_block( + &new_block, reinterpret_cast<uiGridViewHandle *>(this)); + if (!old_view_handle) { + /* Initial construction, nothing to update. */ + is_reconstructed_ = true; + return; + } + + AbstractGridView &old_view = reinterpret_cast<AbstractGridView &>(*old_view_handle); + + foreach_item([this, &old_view](AbstractGridViewItem &new_item) { + const AbstractGridViewItem *matching_old_item = find_matching_item(new_item, old_view); + if (!matching_old_item) { + return; + } + + new_item.update_from_old(*matching_old_item); + }); + + /* Finished (re-)constructing the tree. */ + is_reconstructed_ = true; +} + +bool AbstractGridView::is_reconstructed() const +{ + return is_reconstructed_; +} + +const GridViewStyle &AbstractGridView::get_style() const +{ + return style_; +} + +int AbstractGridView::get_item_count() const +{ + return items_.size(); +} + +GridViewStyle::GridViewStyle(int width, int height) : tile_width(width), tile_height(height) +{ +} + +/* ---------------------------------------------------------------------- */ + +AbstractGridViewItem::AbstractGridViewItem(StringRef identifier) : identifier_(identifier) +{ +} + +bool AbstractGridViewItem::matches(const AbstractGridViewItem &other) const +{ + return identifier_ == other.identifier_; +} + +void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/, + void *but_arg1, + void * /*arg2*/) +{ + uiButGridTile *grid_tile_but = (uiButGridTile *)but_arg1; + AbstractGridViewItem &grid_item = reinterpret_cast<AbstractGridViewItem &>( + *grid_tile_but->view_item); + + grid_item.activate(); +} + +void AbstractGridViewItem::add_grid_tile_button(uiBlock &block) +{ + const GridViewStyle &style = get_view().get_style(); + grid_tile_but_ = (uiButGridTile *)uiDefBut(&block, + UI_BTYPE_GRID_TILE, + 0, + "", + 0, + 0, + style.tile_width, + style.tile_height, + nullptr, + 0, + 0, + 0, + 0, + ""); + + grid_tile_but_->view_item = reinterpret_cast<uiGridViewItemHandle *>(this); + UI_but_func_set(&grid_tile_but_->but, grid_tile_click_fn, grid_tile_but_, nullptr); +} + +bool AbstractGridViewItem::is_active() const +{ + BLI_assert_msg(get_view().is_reconstructed(), + "State can't be queried until reconstruction is completed"); + return is_active_; +} + +void AbstractGridViewItem::on_activate() +{ + /* Do nothing by default. */ +} + +std::optional<bool> AbstractGridViewItem::should_be_active() const +{ + return std::nullopt; +} + +void AbstractGridViewItem::change_state_delayed() +{ + const std::optional<bool> should_be_active = this->should_be_active(); + if (should_be_active.has_value() && *should_be_active) { + activate(); + } +} + +void AbstractGridViewItem::update_from_old(const AbstractGridViewItem &old) +{ + is_active_ = old.is_active_; +} + +void AbstractGridViewItem::activate() +{ + BLI_assert_msg(get_view().is_reconstructed(), + "Item activation can't be done until reconstruction is completed"); + + if (is_active()) { + return; + } + + /* Deactivate other items in the tree. */ + get_view().foreach_item([](auto &item) { item.deactivate(); }); + + on_activate(); + + is_active_ = true; +} + +void AbstractGridViewItem::deactivate() +{ + is_active_ = false; +} + +const AbstractGridView &AbstractGridViewItem::get_view() const +{ + if (UNLIKELY(!view_)) { + throw std::runtime_error( + "Invalid state, item must be added through AbstractGridView::add_item()"); + } + return *view_; +} + +/* ---------------------------------------------------------------------- */ + +/** + * Helper for only adding layout items for grid items that are actually in view. 3 main functions: + * - #is_item_visible(): Query if an item of a given index is visible in the view (others should be + * skipped when building the layout). + * - #fill_layout_before_visible(): Add empty space to the layout before a visible row is drawn, so + * the layout height is the same as if all items were added (important to get the correct scroll + * height). + * - #fill_layout_after_visible(): Same thing, just adds empty space for after the last visible + * row. + * + * Does two assumptions: + * - Top-to-bottom flow (ymax = 0 and ymin < 0). If that's not good enough, View2D should + * probably provide queries for the scroll offset. + * - Only vertical scrolling. For horizontal scrolling, spacers would have to be added on the + * side(s) as well. + */ +class BuildOnlyVisibleButtonsHelper { + const View2D &v2d_; + const AbstractGridView &grid_view_; + const GridViewStyle &style_; + const int cols_per_row_ = 0; + /* Indices of items within the view. Calculated by constructor */ + IndexRange visible_items_range_{}; + + public: + BuildOnlyVisibleButtonsHelper(const View2D &, + const AbstractGridView &grid_view, + int cols_per_row); + + bool is_item_visible(int item_idx) const; + void fill_layout_before_visible(uiBlock &) const; + void fill_layout_after_visible(uiBlock &) const; + + private: + IndexRange get_visible_range() const; + void add_spacer_button(uiBlock &, int row_count) const; +}; + +BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(const View2D &v2d, + const AbstractGridView &grid_view, + const int cols_per_row) + : v2d_(v2d), grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row) +{ + visible_items_range_ = get_visible_range(); +} + +IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range() const +{ + int first_idx_in_view = 0; + int max_items_in_view = 0; + + const float scroll_ofs_y = abs(v2d_.cur.ymax - v2d_.tot.ymax); + if (!IS_EQF(scroll_ofs_y, 0)) { + const int scrolled_away_rows = (int)scroll_ofs_y / style_.tile_height; + + first_idx_in_view = scrolled_away_rows * cols_per_row_; + } + + const float view_height = BLI_rctf_size_y(&v2d_.cur); + const int count_rows_in_view = std::max(round_fl_to_int(view_height / style_.tile_height), 1); + max_items_in_view = (count_rows_in_view + 1) * cols_per_row_; + + BLI_assert(max_items_in_view > 0); + return IndexRange(first_idx_in_view, max_items_in_view); +} + +bool BuildOnlyVisibleButtonsHelper::is_item_visible(const int item_idx) const +{ + return visible_items_range_.contains(item_idx); +} + +void BuildOnlyVisibleButtonsHelper::fill_layout_before_visible(uiBlock &block) const +{ + const float scroll_ofs_y = abs(v2d_.cur.ymax - v2d_.tot.ymax); + + if (IS_EQF(scroll_ofs_y, 0)) { + return; + } + + const int scrolled_away_rows = (int)scroll_ofs_y / style_.tile_height; + add_spacer_button(block, scrolled_away_rows); +} + +void BuildOnlyVisibleButtonsHelper::fill_layout_after_visible(uiBlock &block) const +{ + const int last_item_idx = grid_view_.get_item_count() - 1; + const int last_visible_idx = visible_items_range_.last(); + + if (last_item_idx > last_visible_idx) { + const int remaining_rows = (cols_per_row_ > 0) ? + (last_item_idx - last_visible_idx) / cols_per_row_ : + 0; + BuildOnlyVisibleButtonsHelper::add_spacer_button(block, remaining_rows); + } +} + +void BuildOnlyVisibleButtonsHelper::add_spacer_button(uiBlock &block, const int row_count) const +{ + /* UI code only supports button dimensions of `signed short` size, the layout height we want to + * fill may be bigger than that. So add multiple labels of the maximum size if necessary. */ + for (int remaining_rows = row_count; remaining_rows > 0;) { + const short row_count_this_iter = std::min( + std::numeric_limits<short>::max() / style_.tile_height, remaining_rows); + + uiDefBut(&block, + UI_BTYPE_LABEL, + 0, + "", + 0, + 0, + UI_UNIT_X, + row_count_this_iter * style_.tile_height, + nullptr, + 0, + 0, + 0, + 0, + ""); + remaining_rows -= row_count_this_iter; + } +} + +/* ---------------------------------------------------------------------- */ + +class GridViewLayoutBuilder { + uiBlock &block_; + + friend class GridViewBuilder; + + public: + GridViewLayoutBuilder(uiBlock &block); + + void build_from_view(const AbstractGridView &grid_view, const View2D &v2d) const; + + private: + void build_grid_tile(uiLayout &grid_layout, AbstractGridViewItem &item) const; + + uiLayout *current_layout() const; +}; + +GridViewLayoutBuilder::GridViewLayoutBuilder(uiBlock &block) : block_(block) +{ +} + +void GridViewLayoutBuilder::build_grid_tile(uiLayout &grid_layout, + AbstractGridViewItem &item) const +{ + uiLayout *overlap = uiLayoutOverlap(&grid_layout); + + item.add_grid_tile_button(block_); + item.build_grid_tile(*uiLayoutRow(overlap, false)); +} + +void GridViewLayoutBuilder::build_from_view(const AbstractGridView &grid_view, + const View2D &v2d) const +{ + uiLayout *prev_layout = current_layout(); + + uiLayout &layout = *uiLayoutColumn(current_layout(), false); + const GridViewStyle &style = grid_view.get_style(); + + const int cols_per_row = std::max(uiLayoutGetWidth(&layout) / style.tile_width, 1); + + BuildOnlyVisibleButtonsHelper build_visible_helper(v2d, grid_view, cols_per_row); + + build_visible_helper.fill_layout_before_visible(block_); + + /* Use `-cols_per_row` because the grid layout uses a multiple of the passed absolute value for + * the number of columns then, rather than distributing the number of items evenly over rows and + * stretching the items to fit (see #uiLayoutItemGridFlow.columns_len). */ + uiLayout *grid_layout = uiLayoutGridFlow(&layout, true, -cols_per_row, true, true, true); + + int item_idx = 0; + grid_view.foreach_item([&](AbstractGridViewItem &item) { + /* Skip if item isn't visible. */ + if (!build_visible_helper.is_item_visible(item_idx)) { + item_idx++; + return; + } + + build_grid_tile(*grid_layout, item); + item_idx++; + }); + + /* If there are not enough items to fill the layout, add padding items so the layout doesn't + * stretch over the entire width. */ + if (grid_view.get_item_count() < cols_per_row) { + for (int padding_item_idx = 0; padding_item_idx < (cols_per_row - grid_view.get_item_count()); + padding_item_idx++) { + uiItemS(grid_layout); + } + } + + UI_block_layout_set_current(&block_, prev_layout); + + build_visible_helper.fill_layout_after_visible(block_); +} + +uiLayout *GridViewLayoutBuilder::current_layout() const +{ + return block_.curlayout; +} + +/* ---------------------------------------------------------------------- */ + +GridViewBuilder::GridViewBuilder(uiBlock &block) : block_(block) +{ +} + +void GridViewBuilder::build_grid_view(AbstractGridView &grid_view, const View2D &v2d) +{ + grid_view.build_items(); + grid_view.update_from_old(block_); + grid_view.change_state_delayed(); + + GridViewLayoutBuilder builder(block_); + builder.build_from_view(grid_view, v2d); +} + +/* ---------------------------------------------------------------------- */ + +PreviewGridItem::PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id) + : AbstractGridViewItem(identifier), label(label), preview_icon_id(preview_icon_id) +{ +} + +void PreviewGridItem::build_grid_tile(uiLayout &layout) const +{ + const GridViewStyle &style = get_view().get_style(); + uiBlock *block = uiLayoutGetBlock(&layout); + + uiBut *but = uiDefBut(block, + UI_BTYPE_PREVIEW_TILE, + 0, + label.c_str(), + 0, + 0, + style.tile_width, + style.tile_height, + nullptr, + 0, + 0, + 0, + 0, + ""); + ui_def_but_icon(but, + preview_icon_id, + /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */ + UI_HAS_ICON | UI_BUT_ICON_PREVIEW); +} + +void PreviewGridItem::set_on_activate_fn(ActivateFn fn) +{ + activate_fn_ = fn; +} + +void PreviewGridItem::set_is_active_fn(IsActiveFn fn) +{ + is_active_fn_ = fn; +} + +void PreviewGridItem::on_activate() +{ + if (activate_fn_) { + activate_fn_(*this); + } +} + +std::optional<bool> PreviewGridItem::should_be_active() const +{ + if (is_active_fn_) { + return is_active_fn_(); + } + return std::nullopt; +} + +} // namespace blender::ui + +using namespace blender::ui; + +/* ---------------------------------------------------------------------- */ +/* C-API */ + +using namespace blender::ui; + +bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle) +{ + const AbstractGridViewItem &item = reinterpret_cast<const AbstractGridViewItem &>(*item_handle); + return item.is_active(); +} + +bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view_handle, + const wmNotifier *notifier) +{ + const AbstractGridView &view = *reinterpret_cast<const AbstractGridView *>(view_handle); + return view.listen(*notifier); +} + +bool UI_grid_view_item_matches(const uiGridViewItemHandle *a_handle, + const uiGridViewItemHandle *b_handle) +{ + const AbstractGridViewItem &a = reinterpret_cast<const AbstractGridViewItem &>(*a_handle); + const AbstractGridViewItem &b = reinterpret_cast<const AbstractGridViewItem &>(*b_handle); + return a.matches(b); +} diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index d6719f0aa9f..3f623566807 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -778,6 +778,15 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut) } } + if ((but->type == UI_BTYPE_GRID_TILE) && (oldbut->type == UI_BTYPE_GRID_TILE)) { + uiButGridTile *but_gridtile = (uiButGridTile *)but; + uiButGridTile *oldbut_gridtile = (uiButGridTile *)oldbut; + if (!but_gridtile->view_item || !oldbut_gridtile->view_item || + !UI_grid_view_item_matches(but_gridtile->view_item, oldbut_gridtile->view_item)) { + return false; + } + } + return true; } @@ -904,6 +913,12 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but) SWAP(uiTreeViewItemHandle *, treerow_newbut->tree_item, treerow_oldbut->tree_item); break; } + case UI_BTYPE_GRID_TILE: { + uiButGridTile *gridtile_oldbut = (uiButGridTile *)oldbut; + uiButGridTile *gridtile_newbut = (uiButGridTile *)but; + SWAP(uiGridViewItemHandle *, gridtile_newbut->view_item, gridtile_oldbut->view_item); + break; + } default: break; } @@ -927,9 +942,12 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but) BLI_strncpy(oldbut->strdata, but->strdata, sizeof(oldbut->strdata)); } - if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) { + if (but->dragpoin) { SWAP(void *, but->dragpoin, oldbut->dragpoin); } + if (but->imb) { + SWAP(ImBuf *, but->imb, oldbut->imb); + } /* NOTE: if layout hasn't been applied yet, it uses old button pointers... */ } @@ -993,9 +1011,9 @@ static bool ui_but_update_from_old_block(const bContext *C, else { int flag_copy = UI_BUT_DRAG_MULTI; - /* Stupid special case: The active button may be inside (as in, overlapped on top) a tree-row + /* Stupid special case: The active button may be inside (as in, overlapped on top) a view-item * button which we also want to keep highlighted then. */ - if (but->type == UI_BTYPE_TREEROW) { + if (ui_but_is_view_item(but)) { flag_copy |= UI_ACTIVE; } @@ -2236,6 +2254,15 @@ int ui_but_is_pushed_ex(uiBut *but, double *value) } break; } + case UI_BTYPE_GRID_TILE: { + uiButGridTile *grid_tile_but = (uiButGridTile *)but; + + is_push = -1; + if (grid_tile_but->view_item) { + is_push = UI_grid_view_item_is_active(grid_tile_but->view_item); + } + break; + } default: is_push = -1; break; @@ -3442,9 +3469,7 @@ static void ui_but_free(const bContext *C, uiBut *but) IMB_freeImBuf((struct ImBuf *)but->poin); } - if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - WM_drag_data_free(but->dragtype, but->dragpoin); - } + ui_but_drag_free(but); ui_but_extra_operator_icons_free(but); BLI_assert(UI_butstore_is_registered(but->block, but) == false); @@ -3994,6 +4019,10 @@ static void ui_but_alloc_info(const eButType type, alloc_size = sizeof(uiButHotkeyEvent); alloc_str = "uiButHotkeyEvent"; break; + case UI_BTYPE_GRID_TILE: + alloc_size = sizeof(uiButGridTile); + alloc_str = "uiButGridTile"; + break; default: alloc_size = sizeof(uiBut); alloc_str = "uiBut"; @@ -4968,6 +4997,33 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname) return match; } +#define PREVIEW_TILE_PAD (0.15f * UI_UNIT_X) + +int UI_preview_tile_size_x(void) +{ + const float pad = PREVIEW_TILE_PAD; + return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_X + 2.0f * pad); +} + +int UI_preview_tile_size_y(void) +{ + const uiStyle *style = UI_style_get(); + const float font_height = style->widget.points * UI_DPI_FAC; + const float pad = PREVIEW_TILE_PAD; + + return round_fl_to_int(UI_preview_tile_size_y_no_label() + font_height + + /* Add some extra padding to make things less tight vertically. */ + pad); +} + +int UI_preview_tile_size_y_no_label(void) +{ + const float pad = PREVIEW_TILE_PAD; + return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_Y + 2.0f * pad); +} + +#undef PREVIEW_TILE_PAD + static void ui_but_update_and_icon_set(uiBut *but, int icon) { if (icon) { @@ -5878,104 +5934,6 @@ int UI_but_return_value_get(uiBut *but) return but->retval; } -void UI_but_drag_set_id(uiBut *but, ID *id) -{ - but->dragtype = WM_DRAG_ID; - if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { - WM_drag_data_free(but->dragtype, but->dragpoin); - but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; - } - but->dragpoin = (void *)id; -} - -void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale) -{ - but->imb = imb; - but->imb_scale = scale; -} - -void UI_but_drag_set_asset(uiBut *but, - const AssetHandle *asset, - const char *path, - struct AssetMetaData *metadata, - int import_type, - int icon, - struct ImBuf *imb, - float scale) -{ - wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type); - - /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the - * #wmDropBox. - * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its - * copy callback. - * */ - asset_drag->evil_C = static_cast<bContext *>(but->block->evil_C); - - but->dragtype = WM_DRAG_ASSET; - ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ - if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { - WM_drag_data_free(but->dragtype, but->dragpoin); - } - but->dragpoin = asset_drag; - but->dragflag |= UI_BUT_DRAGPOIN_FREE; - UI_but_drag_attach_image(but, imb, scale); -} - -void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr) -{ - but->dragtype = WM_DRAG_RNA; - if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { - WM_drag_data_free(but->dragtype, but->dragpoin); - but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; - } - but->dragpoin = (void *)ptr; -} - -void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free) -{ - but->dragtype = WM_DRAG_PATH; - if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { - WM_drag_data_free(but->dragtype, but->dragpoin); - but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; - } - but->dragpoin = (void *)path; - if (use_free) { - but->dragflag |= UI_BUT_DRAGPOIN_FREE; - } -} - -void UI_but_drag_set_name(uiBut *but, const char *name) -{ - but->dragtype = WM_DRAG_NAME; - if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { - WM_drag_data_free(but->dragtype, but->dragpoin); - but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; - } - but->dragpoin = (void *)name; -} - -void UI_but_drag_set_value(uiBut *but) -{ - but->dragtype = WM_DRAG_VALUE; -} - -void UI_but_drag_set_image( - uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free) -{ - but->dragtype = WM_DRAG_PATH; - ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ - if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { - WM_drag_data_free(but->dragtype, but->dragpoin); - but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; - } - but->dragpoin = (void *)path; - if (use_free) { - but->dragflag |= UI_BUT_DRAGPOIN_FREE; - } - UI_but_drag_attach_image(but, imb, scale); -} - PointerRNA *UI_but_operator_ptr_get(uiBut *but) { if (but->optype && !but->opptr) { diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index e838ce37d8e..0e69b4bb358 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -293,7 +293,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) { - ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra); + ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra, true); } void ui_but_anim_copy_driver(bContext *C) diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc new file mode 100644 index 00000000000..4c68870b2c7 --- /dev/null +++ b/source/blender/editors/interface/interface_drag.cc @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edinterface + */ + +#include "UI_interface.h" + +#include "WM_api.h" + +#include "interface_intern.h" + +void UI_but_drag_set_id(uiBut *but, ID *id) +{ + but->dragtype = WM_DRAG_ID; + if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { + WM_drag_data_free(but->dragtype, but->dragpoin); + but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; + } + but->dragpoin = (void *)id; +} + +void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale) +{ + but->imb = imb; + but->imb_scale = scale; +} + +void UI_but_drag_set_asset(uiBut *but, + const AssetHandle *asset, + const char *path, + struct AssetMetaData *metadata, + int import_type, + int icon, + struct ImBuf *imb, + float scale) +{ + wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type); + + /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the + * #wmDropBox. + * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its + * copy callback. + * */ + asset_drag->evil_C = static_cast<bContext *>(but->block->evil_C); + + but->dragtype = WM_DRAG_ASSET; + ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ + if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { + WM_drag_data_free(but->dragtype, but->dragpoin); + } + but->dragpoin = asset_drag; + but->dragflag |= UI_BUT_DRAGPOIN_FREE; + UI_but_drag_attach_image(but, imb, scale); +} + +void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr) +{ + but->dragtype = WM_DRAG_RNA; + if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { + WM_drag_data_free(but->dragtype, but->dragpoin); + but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; + } + but->dragpoin = (void *)ptr; +} + +void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free) +{ + but->dragtype = WM_DRAG_PATH; + if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { + WM_drag_data_free(but->dragtype, but->dragpoin); + but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; + } + but->dragpoin = (void *)path; + if (use_free) { + but->dragflag |= UI_BUT_DRAGPOIN_FREE; + } +} + +void UI_but_drag_set_name(uiBut *but, const char *name) +{ + but->dragtype = WM_DRAG_NAME; + if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { + WM_drag_data_free(but->dragtype, but->dragpoin); + but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; + } + but->dragpoin = (void *)name; +} + +void UI_but_drag_set_value(uiBut *but) +{ + but->dragtype = WM_DRAG_VALUE; +} + +void UI_but_drag_set_image( + uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free) +{ + but->dragtype = WM_DRAG_PATH; + ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ + if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { + WM_drag_data_free(but->dragtype, but->dragpoin); + but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; + } + but->dragpoin = (void *)path; + if (use_free) { + but->dragflag |= UI_BUT_DRAGPOIN_FREE; + } + UI_but_drag_attach_image(but, imb, scale); +} + +void ui_but_drag_free(uiBut *but) +{ + if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) { + WM_drag_data_free(but->dragtype, but->dragpoin); + } +} + +bool ui_but_drag_is_draggable(const uiBut *but) +{ + return but->dragpoin != nullptr; +} + +void ui_but_drag_start(bContext *C, uiBut *but) +{ + wmDrag *drag = WM_event_start_drag(C, + but->icon, + but->dragtype, + but->dragpoin, + ui_but_value_get(but), + (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA : + WM_DRAG_NOP); + /* wmDrag has ownership over dragpoin now, stop messing with it. */ + but->dragpoin = NULL; + + if (but->imb) { + WM_event_drag_image(drag, but->imb, but->imb_scale); + } + + /* Special feature for assets: We add another drag item that supports multiple assets. It + * gets the assets from context. */ + if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) { + WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP); + } +} diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 18bad7949ee..d201820fbb6 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -130,7 +130,7 @@ void UI_draw_roundbox_4fv_ex(const rctf *rect, void UI_draw_roundbox_3ub_alpha( const rctf *rect, bool filled, float rad, const uchar col[3], uchar alpha) { - float colv[4] = { + const float colv[4] = { ((float)col[0]) / 255, ((float)col[1]) / 255, ((float)col[2]) / 255, @@ -142,7 +142,7 @@ void UI_draw_roundbox_3ub_alpha( void UI_draw_roundbox_3fv_alpha( const rctf *rect, bool filled, float rad, const float col[3], float alpha) { - float colv[4] = {col[0], col[1], col[2], alpha}; + const float colv[4] = {col[0], col[1], col[2], alpha}; UI_draw_roundbox_4fv_ex(rect, (filled) ? colv : NULL, NULL, 1.0f, colv, U.pixelsize, rad); } diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 895f8d0d840..c015a60de89 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -50,8 +50,6 @@ #include "RE_pipeline.h" -#include "RE_pipeline.h" - #include "interface_eyedropper_intern.h" typedef struct Eyedropper { @@ -329,7 +327,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]) ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceImage *sima = area->spacedata.first; - int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; + const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; if (ED_space_image_color_sample(sima, region, region_mval, r_col, NULL)) { return; @@ -340,7 +338,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]) ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceNode *snode = area->spacedata.first; - int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; + const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; if (ED_space_node_color_sample(bmain, snode, region, region_mval, r_col)) { return; @@ -351,7 +349,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]) ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceClip *sc = area->spacedata.first; - int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; + const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; if (ED_space_clip_color_sample(sc, region, region_mval, r_col)) { return; diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index aec8f56678a..01b958576b6 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -156,7 +156,7 @@ static void datadropper_id_sample_pt( CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); - /* grr, always draw else we leave stale text */ + /* Unfortunately it's necessary to always draw else we leave stale text. */ ED_region_tag_redraw(region); if (area->spacetype == SPACE_VIEW3D) { diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index 56bc1a6d956..3c6f127582a 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -171,7 +171,7 @@ static void depthdropper_depth_sample_pt(bContext *C, CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); - /* grr, always draw else we leave stale text */ + /* Unfortunately it's necessary to always draw otherwise we leave stale text. */ ED_region_tag_redraw(region); view3d_operator_needs_opengl(C); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a7dfff2edb4..7c00c4f1875 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1480,9 +1480,9 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat } } - /* edit buttons proportionally to eachother + /* Edit buttons proportionally to each other. * NOTE: if we mix buttons which are proportional and others which are not, - * this may work a bit strangely */ + * this may work a bit strangely. */ if ((but_active->rnaprop && (RNA_property_flag(but_active->rnaprop) & PROP_PROPORTIONAL)) || ELEM(but_active->unit_type, RNA_SUBTYPE_UNIT_VALUE(PROP_UNIT_LENGTH))) { if (data->origvalue != 0.0) { @@ -2135,25 +2135,7 @@ static bool ui_but_drag_init(bContext *C, } } else { - wmDrag *drag = WM_event_start_drag( - C, - but->icon, - but->dragtype, - but->dragpoin, - ui_but_value_get(but), - (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA : WM_DRAG_NOP); - /* wmDrag has ownership over dragpoin now, stop messing with it. */ - but->dragpoin = NULL; - - if (but->imb) { - WM_event_drag_image(drag, but->imb, but->imb_scale); - } - - /* Special feature for assets: We add another drag item that supports multiple assets. It - * gets the assets from context. */ - if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) { - WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP); - } + ui_but_drag_start(C, but); } return true; } @@ -2307,6 +2289,9 @@ static void ui_apply_but( case UI_BTYPE_ROW: ui_apply_but_ROW(C, block, but, data); break; + case UI_BTYPE_GRID_TILE: + ui_apply_but_ROW(C, block, but, data); + break; case UI_BTYPE_TREEROW: ui_apply_but_TREEROW(C, block, but, data); break; @@ -2963,6 +2948,9 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value) { + /* Caller should check. */ + BLI_assert((but->flag & UI_BUT_DISABLED) == 0); + button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); ui_textedit_string_set(but, but->active, value); @@ -3507,7 +3495,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT); #ifdef WITH_INPUT_IME - if (is_num_but == false && BLT_lang_is_ime_supported()) { + if (!is_num_but) { ui_textedit_ime_begin(win, but); } #endif @@ -3911,7 +3899,7 @@ static void ui_do_but_textedit( if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE) #ifdef WITH_INPUT_IME - && !is_ime_composing && (!WM_event_is_ime_switch(event) || !BLT_lang_is_ime_supported()) + && !is_ime_composing && !WM_event_is_ime_switch(event) #endif ) { char ascii = event->ascii; @@ -4825,12 +4813,53 @@ static int ui_do_but_TREEROW(bContext *C, return WM_UI_HANDLER_CONTINUE; } +static int ui_do_but_GRIDTILE(bContext *C, + uiBut *but, + uiHandleButtonData *data, + const wmEvent *event) +{ + BLI_assert(but->type == UI_BTYPE_GRID_TILE); + + if (data->state == BUTTON_STATE_HIGHLIGHT) { + if (event->type == LEFTMOUSE) { + switch (event->val) { + case KM_PRESS: + /* Extra icons have priority, don't mess with them. */ + if (ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) { + return WM_UI_HANDLER_BREAK; + } + button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); + data->dragstartx = event->xy[0]; + data->dragstarty = event->xy[1]; + return WM_UI_HANDLER_CONTINUE; + + case KM_CLICK: + button_activate_state(C, but, BUTTON_STATE_EXIT); + return WM_UI_HANDLER_BREAK; + + case KM_DBL_CLICK: + data->cancel = true; + // uiButGridTile *grid_tile_but = (uiButGridTile *)but; + // UI_tree_view_item_begin_rename(grid_tile_but->tree_item); + ED_region_tag_redraw(CTX_wm_region(C)); + return WM_UI_HANDLER_BREAK; + } + } + } + else if (data->state == BUTTON_STATE_WAIT_DRAG) { + /* Let "default" button handling take care of the drag logic. */ + return ui_do_but_EXIT(C, but, data, event); + } + + return WM_UI_HANDLER_CONTINUE; +} + static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { /* First handle click on icon-drag type button. */ - if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && but->dragpoin) { + if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && ui_but_drag_is_draggable(but)) { if (ui_but_contains_point_px_icon(but, data->region, event)) { /* tell the button to wait and keep checking further events to @@ -4853,7 +4882,8 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY) && event->val == KM_PRESS) { int ret = WM_UI_HANDLER_BREAK; /* XXX: (a bit ugly) Special case handling for file-browser drag button. */ - if (but->dragpoin && but->imb && ui_but_contains_point_px_icon(but, data->region, event)) { + if (ui_but_drag_is_draggable(but) && but->imb && + ui_but_contains_point_px_icon(but, data->region, event)) { ret = WM_UI_HANDLER_CONTINUE; } /* Same special case handling for UI lists. Return CONTINUE so that a tweak or CLICK event @@ -4865,6 +4895,10 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con ret = WM_UI_HANDLER_CONTINUE; } } + const uiBut *view_but = ui_view_item_find_mouse_over(data->region, event->xy); + if (view_but) { + ret = WM_UI_HANDLER_CONTINUE; + } button_activate_state(C, but, BUTTON_STATE_EXIT); return ret; } @@ -6007,7 +6041,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co if (data->state == BUTTON_STATE_HIGHLIGHT) { /* First handle click on icon-drag type button. */ - if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) { + if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && event->val == KM_PRESS) { if (ui_but_contains_point_px_icon(but, data->region, event)) { button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); data->dragstartx = event->xy[0]; @@ -6193,7 +6227,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co if (data->state == BUTTON_STATE_HIGHLIGHT) { /* First handle click on icon-drag type button. */ - if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) { + if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && event->val == KM_PRESS) { ui_palette_set_active(color_but); if (ui_but_contains_point_px_icon(but, data->region, event)) { button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); @@ -7408,8 +7442,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, const float zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&profile->view_rect); if (snap) { - float d[2] = {mx - data->dragstartx, data->dragstarty}; - + const float d[2] = {mx - data->dragstartx, data->dragstarty}; if (len_squared_v2(d) < (9.0f * U.dpi_fac)) { snap = false; } @@ -8020,6 +8053,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_ROW: retval = ui_do_but_TOG(C, but, data, event); break; + case UI_BTYPE_GRID_TILE: + retval = ui_do_but_GRIDTILE(C, but, data, event); + break; case UI_BTYPE_TREEROW: retval = ui_do_but_TREEROW(C, but, data, event); break; @@ -9477,7 +9513,7 @@ static bool ui_list_is_hovering_draggable_but(bContext *C, } } - return (hovered_but && hovered_but->dragpoin); + return (hovered_but && ui_but_drag_is_draggable(hovered_but)); } static int ui_list_handle_click_drag(bContext *C, @@ -9687,31 +9723,31 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi return retval; } -static int ui_handle_tree_hover(const wmEvent *event, const ARegion *region) +static int ui_handle_view_items_hover(const wmEvent *event, const ARegion *region) { - bool has_treerows = false; + bool has_view_item = false; LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { - /* Avoid unnecessary work: Tree-rows are assumed to be inside tree-views. */ + /* Avoid unnecessary work: view item buttons are assumed to be inside views. */ if (BLI_listbase_is_empty(&block->views)) { continue; } LISTBASE_FOREACH (uiBut *, but, &block->buttons) { - if (but->type == UI_BTYPE_TREEROW) { + if (ui_but_is_view_item(but)) { but->flag &= ~UI_ACTIVE; - has_treerows = true; + has_view_item = true; } } } - if (!has_treerows) { + if (!has_view_item) { /* Avoid unnecessary lookup. */ return WM_UI_HANDLER_CONTINUE; } - /* Always highlight the hovered tree-row, even if the mouse hovers another button inside of it. + /* Always highlight the hovered view item, even if the mouse hovers another button inside of it. */ - uiBut *hovered_row_but = ui_tree_row_find_mouse_over(region, event->xy); + uiBut *hovered_row_but = ui_view_item_find_mouse_over(region, event->xy); if (hovered_row_but) { hovered_row_but->flag |= UI_ACTIVE; } @@ -9719,6 +9755,21 @@ static int ui_handle_tree_hover(const wmEvent *event, const ARegion *region) return WM_UI_HANDLER_CONTINUE; } +static int ui_handle_view_item_event(bContext *C, + const wmEvent *event, + ARegion *region, + uiBut *view_but) +{ + BLI_assert(ui_but_is_view_item(view_but)); + if (event->type == LEFTMOUSE) { + /* Will free active button if there already is one. */ + ui_handle_button_activate(C, region, view_but, BUTTON_ACTIVATE_OVER); + return ui_do_button(C, view_but->block, view_but, event); + } + + return WM_UI_HANDLER_CONTINUE; +} + static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, uiBut *but) { uiHandleButtonData *data = but->active; @@ -11319,9 +11370,15 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use ui_blocks_set_tooltips(region, true); } - /* Always do this, to reliably update tree-row highlighting, even if the mouse hovers a button - * inside the row (it's an overlapping layout). */ - ui_handle_tree_hover(event, region); + /* Always do this, to reliably update view item highlighting, even if the mouse hovers a button + * nested in the item (it's an overlapping layout). */ + ui_handle_view_items_hover(event, region); + if (retval == WM_UI_HANDLER_CONTINUE) { + uiBut *view_item = ui_view_item_find_mouse_over(region, event->xy); + if (view_item) { + retval = ui_handle_view_item_event(C, event, region, view_item); + } + } /* delayed apply callbacks */ ui_apply_but_funcs_after(C); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 332b9b44b0a..c19e842aad8 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -546,6 +546,7 @@ static void init_brush_icons(void) INIT_BRUSH_ICON(ICON_BRUSH_MASK, mask); INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix); INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge); + INIT_BRUSH_ICON(ICON_BRUSH_PAINT_SELECT, paint_select); INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch); INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape); INIT_BRUSH_ICON(ICON_BRUSH_SMEAR, smear); @@ -584,6 +585,19 @@ static void init_brush_icons(void) INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard); INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke); + /* Curves sculpt. */ + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_ADD, curves_sculpt_add); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_COMB, curves_sculpt_comb); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_CUT, curves_sculpt_cut); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DELETE, curves_sculpt_delete); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DENSITY, curves_sculpt_density); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_GROW_SHRINK, curves_sculpt_grow_shrink); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PINCH, curves_sculpt_pinch); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PUFF, curves_sculpt_puff); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SLIDE, curves_sculpt_slide); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SMOOTH, curves_sculpt_smooth); + INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SNAKE_HOOK, curves_sculpt_snake_hook); + # undef INIT_BRUSH_ICON } @@ -2034,6 +2048,9 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) else if (ob->mode & OB_MODE_TEXTURE_PAINT) { paint_mode = PAINT_MODE_TEXTURE_3D; } + else if (ob->mode & OB_MODE_SCULPT_CURVES) { + paint_mode = PAINT_MODE_SCULPT_CURVES; + } } else if (space_type == SPACE_IMAGE) { if (area->spacetype == space_type) { diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c index 00c1bcb5f6e..6ad5fe805ab 100644 --- a/source/blender/editors/interface/interface_icons_event.c +++ b/source/blender/editors/interface/interface_icons_event.c @@ -145,10 +145,10 @@ void icon_draw_rect_input(float x, SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY)); icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f); } - else if (event_type == EVT_LEFTSHIFTKEY) { + else if (event_type == EVT_LEFTSHIFTKEY) { /* Right Shift has already been converted to left. */ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0}); } - else if (event_type == EVT_LEFTCTRLKEY) { + else if (event_type == EVT_LEFTCTRLKEY) { /* Right Shift has already been converted to left. */ if (platform == MACOS) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0}); } @@ -156,7 +156,7 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f); } } - else if (event_type == EVT_LEFTALTKEY) { + else if (event_type == EVT_LEFTALTKEY) { /* Right Alt has already been converted to left. */ if (platform == MACOS) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0}); } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 1b245ba9e6f..791e51b81a6 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -351,6 +351,13 @@ typedef struct uiButTreeRow { int indentation; } uiButTreeRow; +/** Derived struct for #UI_BTYPE_GRID_TILE. */ +typedef struct uiButGridTile { + uiBut but; + + uiGridViewItemHandle *view_item; +} uiButGridTile; + /** Derived struct for #UI_BTYPE_HSVCUBE. */ typedef struct uiButHSVCube { uiBut but; @@ -1321,6 +1328,12 @@ void ui_button_group_add_but(uiBlock *block, uiBut *but); void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but); void ui_block_free_button_groups(uiBlock *block); +/* interface_drag.cc */ + +void ui_but_drag_free(uiBut *but); +bool ui_but_drag_is_draggable(const uiBut *but); +void ui_but_drag_start(struct bContext *C, uiBut *but); + /* interface_align.c */ bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT; @@ -1359,6 +1372,7 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *but); bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT; bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT; bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT; +bool ui_but_is_view_item(const uiBut *but) ATTR_WARN_UNUSED_RESULT; /** * Can we mouse over the button or is it hidden/disabled/layout. * \note ctrl is kind of a hack currently, @@ -1390,6 +1404,8 @@ uiBut *ui_list_row_find_mouse_over(const struct ARegion *region, const int xy[2] uiBut *ui_list_row_find_from_index(const struct ARegion *region, int index, uiBut *listbox) ATTR_WARN_UNUSED_RESULT; +uiBut *ui_view_item_find_mouse_over(const struct ARegion *region, const int xy[2]) + ATTR_NONNULL(1, 2); uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2]) ATTR_NONNULL(1, 2); uiBut *ui_tree_row_find_active(const struct ARegion *region); @@ -1527,8 +1543,10 @@ void ui_interface_tag_script_reload_queries(void); /* interface_view.cc */ void ui_block_free_views(struct uiBlock *block); -uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block, - const uiTreeViewHandle *new_view); +uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(const uiBlock *new_block, + const uiTreeViewHandle *new_view); +uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block( + const uiBlock *new_block, const uiGridViewHandle *new_view_handle); uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block, const uiTreeViewItemHandle *new_item_handle); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index c066ced21cb..aafb56119ae 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1167,7 +1167,9 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot) /* identifiers */ ot->name = "Copy to Selected"; ot->idname = "UI_OT_copy_to_selected_button"; - ot->description = "Copy property from this object to selected objects or bones"; + ot->description = + "Copy the property's value from the active item to the same property of all selected items " + "if the same property exists"; /* callbacks */ ot->poll = copy_to_selected_button_poll; @@ -1940,6 +1942,24 @@ static void UI_OT_drop_color(wmOperatorType *ot) /** \name Drop Name Operator * \{ */ +static bool drop_name_poll(bContext *C) +{ + if (!ED_operator_regionactive(C)) { + return false; + } + + const uiBut *but = UI_but_active_drop_name_button(C); + if (!but) { + return false; + } + + if (but->flag & UI_BUT_DISABLED) { + return false; + } + + return true; +} + static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { uiBut *but = UI_but_active_drop_name_button(C); @@ -1959,7 +1979,7 @@ static void UI_OT_drop_name(wmOperatorType *ot) ot->idname = "UI_OT_drop_name"; ot->description = "Drop name to button"; - ot->poll = ED_operator_regionactive; + ot->poll = drop_name_poll; ot->invoke = drop_name_invoke; ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc index ea1fe3923e4..71cf60985df 100644 --- a/source/blender/editors/interface/interface_query.cc +++ b/source/blender/editors/interface/interface_query.cc @@ -58,18 +58,23 @@ bool ui_but_is_toggle(const uiBut *but) UI_BTYPE_TREEROW); } +bool ui_but_is_view_item(const uiBut *but) +{ + return ELEM(but->type, UI_BTYPE_TREEROW, UI_BTYPE_GRID_TILE); +} + bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip) { /* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */ if (but->type == UI_BTYPE_LABEL) { if (for_tooltip) { /* It's important labels are considered interactive for the purpose of showing tooltip. */ - if (but->dragpoin == nullptr && but->tip_func == nullptr) { + if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr) { return false; } } else { - if (but->dragpoin == nullptr) { + if (!ui_but_drag_is_draggable(but)) { return false; } } @@ -462,6 +467,16 @@ static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata)) return but->type == UI_BTYPE_TREEROW; } +static bool ui_but_is_view_item_fn(const uiBut *but, const void *UNUSED(customdata)) +{ + return ui_but_is_view_item(but); +} + +uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2]) +{ + return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_view_item_fn, nullptr); +} + uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2]) { return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_treerow, nullptr); diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc index 64de31dfe6a..81c0c29d09a 100644 --- a/source/blender/editors/interface/interface_region_search.cc +++ b/source/blender/editors/interface/interface_region_search.cc @@ -451,15 +451,16 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re /* reset vars */ data->items.totitem = 0; data->items.more = 0; - if (reset == false) { + if (!reset) { data->items.offset_i = data->items.offset; } else { data->items.offset_i = data->items.offset = 0; data->active = -1; - /* handle active */ - if (search_but->items_update_fn && search_but->item_active) { + /* On init, find and center active item. */ + const bool is_first_search = !search_but->but.changed; + if (is_first_search && search_but->items_update_fn && search_but->item_active) { data->items.active = search_but->item_active; ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); data->items.active = nullptr; diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index c7ebecb178b..82d4405e1b5 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -800,7 +800,7 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, .style = UI_TIP_STYLE_HEADER, .color_id = UI_TIP_LC_NORMAL, }); - field->text = BLI_sprintfN("%s", but_label.strinfo); + field->text = BLI_strdup(but_label.strinfo); } /* Tip */ diff --git a/source/blender/editors/interface/interface_style.cc b/source/blender/editors/interface/interface_style.cc index 291ede05730..904765f6dc4 100644 --- a/source/blender/editors/interface/interface_style.cc +++ b/source/blender/editors/interface/interface_style.cc @@ -382,19 +382,8 @@ void uiStyleInit(void) } CLAMP(U.dpi, 48, 144); - LISTBASE_FOREACH (uiFont *, font, &U.uifonts) { - BLF_unload_id(font->blf_id); - } - - if (blf_mono_font != -1) { - BLF_unload_id(blf_mono_font); - blf_mono_font = -1; - } - - if (blf_mono_font_render != -1) { - BLF_unload_id(blf_mono_font_render); - blf_mono_font_render = -1; - } + /* Needed so that custom fonts are always first. */ + BLF_unload_all(); uiFont *font_first = static_cast<uiFont *>(U.uifonts.first); @@ -498,6 +487,9 @@ void uiStyleInit(void) const bool unique = true; blf_mono_font_render = BLF_load_mono_default(unique); } + + /* Load the fallback fonts last. */ + BLF_load_font_stack(); } void UI_fontstyle_set(const uiFontStyle *fs) diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc index dc8f568d025..4e587bd5338 100644 --- a/source/blender/editors/interface/interface_template_attribute_search.cc +++ b/source/blender/editors/interface/interface_template_attribute_search.cc @@ -24,14 +24,14 @@ using blender::nodes::geometry_nodes_eval_log::GeometryAttributeInfo; namespace blender::ui { -static StringRef attribute_data_type_string(const CustomDataType type) +static StringRef attribute_data_type_string(const eCustomDataType type) { const char *name = nullptr; RNA_enum_name_from_value(rna_enum_attribute_type_items, type, &name); return StringRef(IFACE_(name)); } -static StringRef attribute_domain_string(const AttributeDomain domain) +static StringRef attribute_domain_string(const eAttrDomain domain) { const char *name = nullptr; RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name); @@ -91,6 +91,9 @@ void attribute_search_add_items(StringRefNull str, if (item->name == "normal" && item->domain == ATTR_DOMAIN_FACE) { continue; } + if (!bke::allow_procedural_attribute_access(item->name)) { + continue; + } BLI_string_search_add(search, item->name.c_str(), (void *)item, 0); } diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index 68a699c652a..e0b6bbb34c4 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -945,13 +945,8 @@ static void ui_template_list_layout_draw(bContext *C, const bool show_names = (flags & UI_TEMPLATE_LIST_NO_NAMES) == 0; - /* TODO ED_fileselect_init_layout(). Share somehow? */ - float size_x = (96.0f / 20.0f) * UI_UNIT_X; - float size_y = (96.0f / 20.0f) * UI_UNIT_Y; - - if (!show_names) { - size_y -= UI_UNIT_Y; - } + const int size_x = UI_preview_tile_size_x(); + const int size_y = show_names ? UI_preview_tile_size_y() : UI_preview_tile_size_y_no_label(); const int cols_per_row = MAX2((uiLayoutGetWidth(box) - V2D_SCROLL_WIDTH) / size_x, 1); uiLayout *grid = uiLayoutGridFlow(row, true, cols_per_row, true, true, true); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a02e8a3ac49..05ae5299e58 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1536,8 +1536,8 @@ static void template_ID_tabs(const bContext *C, 0.0f, ""); UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template), id); + UI_but_drag_set_id(&tab->but, id); tab->but.custom_data = (void *)id; - tab->but.dragpoin = id; tab->menu = mt; UI_but_drawflag_enable(&tab->but, but_align); diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc index 85e1dbe73a5..699ac0c2b53 100644 --- a/source/blender/editors/interface/interface_view.cc +++ b/source/blender/editors/interface/interface_view.cc @@ -10,15 +10,22 @@ */ #include <memory> +#include <type_traits> #include <variant> #include "DNA_screen_types.h" +#include "BKE_screen.h" + #include "BLI_listbase.h" +#include "ED_screen.h" + #include "interface_intern.h" #include "UI_interface.hh" + +#include "UI_grid_view.hh" #include "UI_tree_view.hh" using namespace blender; @@ -30,29 +37,51 @@ using namespace blender::ui; */ struct ViewLink : public Link { using TreeViewPtr = std::unique_ptr<AbstractTreeView>; + using GridViewPtr = std::unique_ptr<AbstractGridView>; std::string idname; /* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */ - std::variant<TreeViewPtr> view; + std::variant<TreeViewPtr, GridViewPtr> view; }; +template<class T> constexpr void check_if_valid_view_type() +{ + static_assert(std::is_same_v<T, AbstractTreeView> || std::is_same_v<T, AbstractGridView>, + "Unsupported view type"); +} + template<class T> T *get_view_from_link(ViewLink &link) { auto *t_uptr = std::get_if<std::unique_ptr<T>>(&link.view); return t_uptr ? t_uptr->get() : nullptr; } -AbstractTreeView *UI_block_add_view(uiBlock &block, - StringRef idname, - std::unique_ptr<AbstractTreeView> tree_view) +template<class T> +static T *ui_block_add_view_impl(uiBlock &block, StringRef idname, std::unique_ptr<T> view) { + check_if_valid_view_type<T>(); + ViewLink *view_link = MEM_new<ViewLink>(__func__); BLI_addtail(&block.views, view_link); - view_link->view = std::move(tree_view); + view_link->view = std::move(view); view_link->idname = idname; - return get_view_from_link<AbstractTreeView>(*view_link); + return get_view_from_link<T>(*view_link); +} + +AbstractGridView *UI_block_add_view(uiBlock &block, + StringRef idname, + std::unique_ptr<AbstractGridView> tree_view) +{ + return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(tree_view)); +} + +AbstractTreeView *UI_block_add_view(uiBlock &block, + StringRef idname, + std::unique_ptr<AbstractTreeView> tree_view) +{ + return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view)); } void ui_block_free_views(uiBlock *block) @@ -62,6 +91,26 @@ void ui_block_free_views(uiBlock *block) } } +void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) +{ + ARegion *region = listener_params->region; + + LISTBASE_FOREACH (ViewLink *, view_link, &block->views) { + if (AbstractGridView *grid_view = get_view_from_link<AbstractGridView>(*view_link)) { + if (UI_grid_view_listen_should_redraw(reinterpret_cast<uiGridViewHandle *>(grid_view), + listener_params->notifier)) { + ED_region_tag_redraw(region); + } + } + else if (AbstractTreeView *tree_view = get_view_from_link<AbstractTreeView>(*view_link)) { + if (UI_tree_view_listen_should_redraw(reinterpret_cast<uiTreeViewHandle *>(tree_view), + listener_params->notifier)) { + ED_region_tag_redraw(region); + } + } + } +} + uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2]) { uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy); @@ -82,11 +131,13 @@ uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const ARegion *region) return tree_row_but->tree_item; } -static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractTreeView &view) +template<class T> static StringRef ui_block_view_find_idname(const uiBlock &block, const T &view) { + check_if_valid_view_type<T>(); + /* First get the idname the of the view we're looking for. */ LISTBASE_FOREACH (ViewLink *, view_link, &block.views) { - if (get_view_from_link<AbstractTreeView>(*view_link) == &view) { + if (get_view_from_link<T>(*view_link) == &view) { return view_link->idname; } } @@ -94,9 +145,11 @@ static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractT return {}; } -static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock &new_block, - const AbstractTreeView &new_view) +template<class T> +static T *ui_block_view_find_matching_in_old_block(const uiBlock &new_block, const T &new_view) { + check_if_valid_view_type<T>(); + uiBlock *old_block = new_block.oldblock; if (!old_block) { return nullptr; @@ -109,15 +162,15 @@ static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) { if (old_view_link->idname == idname) { - return get_view_from_link<AbstractTreeView>(*old_view_link); + return get_view_from_link<T>(*old_view_link); } } return nullptr; } -uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block, - const uiTreeViewHandle *new_view_handle) +uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block( + const uiBlock *new_block, const uiTreeViewHandle *new_view_handle) { BLI_assert(new_block && new_view_handle); const AbstractTreeView &new_view = reinterpret_cast<const AbstractTreeView &>(*new_view_handle); @@ -126,6 +179,16 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl return reinterpret_cast<uiTreeViewHandle *>(old_view); } +uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block( + const uiBlock *new_block, const uiGridViewHandle *new_view_handle) +{ + BLI_assert(new_block && new_view_handle); + const AbstractGridView &new_view = reinterpret_cast<const AbstractGridView &>(*new_view_handle); + + AbstractGridView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view); + return reinterpret_cast<uiGridViewHandle *>(old_view); +} + uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block, const uiTreeViewItemHandle *new_item_handle) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 3777ff31b26..e2df2d77817 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -105,6 +105,7 @@ typedef enum { UI_WTYPE_PROGRESSBAR, UI_WTYPE_NODESOCKET, UI_WTYPE_TREEROW, + UI_WTYPE_GRID_TILE, } uiWidgetTypeEnum; /** @@ -1419,7 +1420,7 @@ static void widget_draw_icon( const bool has_theme = UI_icon_get_theme_color(icon, color); /* to indicate draggable */ - if (but->dragpoin && (but->flag & UI_ACTIVE)) { + if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) { UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme); } else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) { @@ -3706,6 +3707,16 @@ static void widget_treerow(uiBut *but, widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom); } +static void widget_gridtile(uiWidgetColors *wcol, + rcti *rect, + const uiWidgetStateInfo *state, + int roundboxalign, + const float zoom) +{ + /* TODO Reuse tree-row drawing. */ + widget_treerow_exec(wcol, rect, state, roundboxalign, 0, zoom); +} + static void widget_nodesocket(uiBut *but, uiWidgetColors *wcol, rcti *rect, @@ -4598,9 +4609,15 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) break; case UI_WTYPE_TREEROW: + wt.wcol_theme = &btheme->tui.wcol_view_item; wt.custom = widget_treerow; break; + case UI_WTYPE_GRID_TILE: + wt.wcol_theme = &btheme->tui.wcol_view_item; + wt.draw = widget_gridtile; + break; + case UI_WTYPE_NODESOCKET: wt.custom = widget_nodesocket; break; @@ -4937,6 +4954,11 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu fstyle = &style->widgetlabel; break; + case UI_BTYPE_GRID_TILE: + wt = widget_type(UI_WTYPE_GRID_TILE); + fstyle = &style->widgetlabel; + break; + case UI_BTYPE_SCROLL: wt = widget_type(UI_WTYPE_SCROLL); break; diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc index bf756fb5838..f86d1c4d8bc 100644 --- a/source/blender/editors/interface/tree_view.cc +++ b/source/blender/editors/interface/tree_view.cc @@ -68,6 +68,12 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con foreach_item_recursive(iter_fn, options); } +bool AbstractTreeView::listen(const wmNotifier &) const +{ + /* Nothing by default. */ + return false; +} + bool AbstractTreeView::is_renaming() const { return rename_buffer_ != nullptr; @@ -82,7 +88,7 @@ void AbstractTreeView::update_from_old(uiBlock &new_block) return; } - uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block( + uiTreeViewHandle *old_view_handle = ui_block_tree_view_find_matching_in_old_block( &new_block, reinterpret_cast<uiTreeViewHandle *>(this)); if (old_view_handle == nullptr) { is_reconstructed_ = true; @@ -805,6 +811,13 @@ class TreeViewItemAPIWrapper { using namespace blender::ui; +bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view_handle, + const wmNotifier *notifier) +{ + const AbstractTreeView &view = *reinterpret_cast<const AbstractTreeView *>(view_handle); + return view.listen(*notifier); +} + bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle) { const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle); diff --git a/source/blender/editors/interface/view2d_ops.cc b/source/blender/editors/interface/view2d_ops.cc index a4477c5271c..ec15c4ffc9f 100644 --- a/source/blender/editors/interface/view2d_ops.cc +++ b/source/blender/editors/interface/view2d_ops.cc @@ -960,8 +960,8 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op) const double time = PIL_check_seconds_timer(); const float time_step = (float)(time - vzd->timer_lastdraw); - dx *= time_step * 0.5f; - dy *= time_step * 0.5f; + dx *= time_step * 5.0f; + dy *= time_step * 5.0f; vzd->timer_lastdraw = time; } diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index ef093a01ff8..a716c00d5d9 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -13,6 +13,7 @@ set(INC ../../io/gpencil ../../io/usd ../../io/wavefront_obj + ../../io/stl ../../makesdna ../../makesrna ../../windowmanager @@ -33,6 +34,7 @@ set(SRC io_obj.c io_ops.c io_usd.c + io_stl_ops.c io_alembic.h io_cache.h @@ -41,12 +43,12 @@ set(SRC io_obj.h io_ops.h io_usd.h + io_stl_ops.h ) set(LIB bf_blenkernel bf_blenlib - bf_wavefront_obj ) if(WITH_OPENCOLLADA) @@ -56,6 +58,27 @@ if(WITH_OPENCOLLADA) add_definitions(-DWITH_COLLADA) endif() +if(WITH_IO_WAVEFRONT_OBJ) + list(APPEND LIB + bf_wavefront_obj + ) + add_definitions(-DWITH_IO_WAVEFRONT_OBJ) +endif() + +if(WITH_IO_STL) + list(APPEND LIB + bf_stl + ) + add_definitions(-DWITH_IO_STL) +endif() + +if(WITH_IO_GPENCIL) + list(APPEND LIB + bf_gpencil + ) + add_definitions(-DWITH_IO_GPENCIL) +endif() + if(WITH_ALEMBIC) list(APPEND LIB bf_alembic @@ -78,6 +101,4 @@ if(WITH_HARU) add_definitions(-DWITH_HARU) endif() -list(APPEND LIB bf_gpencil) - blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 87923d9fdf8..0e8e0f83597 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -282,7 +282,7 @@ void WM_OT_alembic_export(wmOperatorType *ot) ot->poll = WM_operator_winactive; ot->ui = wm_alembic_export_draw; ot->check = wm_alembic_export_check; - ot->flag |= OPTYPE_PRESET; + ot->flag = OPTYPE_PRESET; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC, diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index dc62212bf53..c491e7a5815 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -468,7 +468,7 @@ void WM_OT_collada_export(wmOperatorType *ot) ot->poll = WM_operator_winactive; ot->check = wm_collada_export_check; - ot->flag |= OPTYPE_PRESET; + ot->flag = OPTYPE_PRESET; ot->ui = wm_collada_export_draw; @@ -786,7 +786,7 @@ void WM_OT_collada_import(wmOperatorType *ot) ot->exec = wm_collada_import_exec; ot->poll = WM_operator_winactive; - // ot->flag |= OPTYPE_PRESET; + // ot->flag = OPTYPE_PRESET; ot->ui = wm_collada_import_draw; diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c index 7ac05fcca3e..6e5ae9f3cba 100644 --- a/source/blender/editors/io/io_gpencil_export.c +++ b/source/blender/editors/io/io_gpencil_export.c @@ -5,36 +5,38 @@ * \ingroup editor/io */ -#include "BLI_path_util.h" -#include "BLI_string.h" +#ifdef WITH_IO_GPENCIL -#include "DNA_gpencil_types.h" -#include "DNA_space_types.h" +# include "BLI_path_util.h" +# include "BLI_string.h" -#include "BKE_gpencil.h" -#include "BKE_main.h" -#include "BKE_report.h" -#include "BKE_screen.h" +# include "DNA_gpencil_types.h" +# include "DNA_space_types.h" -#include "BLT_translation.h" +# include "BKE_gpencil.h" +# include "BKE_main.h" +# include "BKE_report.h" +# include "BKE_screen.h" -#include "RNA_access.h" -#include "RNA_define.h" +# include "BLT_translation.h" -#include "UI_interface.h" -#include "UI_resources.h" +# include "RNA_access.h" +# include "RNA_define.h" -#include "WM_api.h" -#include "WM_types.h" +# include "UI_interface.h" +# include "UI_resources.h" -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" +# include "WM_api.h" +# include "WM_types.h" -#include "io_gpencil.h" +# include "DEG_depsgraph.h" +# include "DEG_depsgraph_query.h" -#include "gpencil_io.h" +# include "io_gpencil.h" -#if defined(WITH_PUGIXML) || defined(WITH_HARU) +# include "gpencil_io.h" + +# if defined(WITH_PUGIXML) || defined(WITH_HARU) /* Definition of enum elements to export. */ /* Common props for exporting. */ static void gpencil_export_common_props_definition(wmOperatorType *ot) @@ -87,10 +89,10 @@ static void set_export_filepath(bContext *C, wmOperator *op, const char *extensi RNA_string_set(op->ptr, "filepath", filepath); } } -#endif +# endif /* <-------- SVG single frame export. --------> */ -#ifdef WITH_PUGIXML +# ifdef WITH_PUGIXML static bool wm_gpencil_export_svg_common_check(bContext *UNUSED(C), wmOperator *op) { char filepath[FILE_MAX]; @@ -241,10 +243,10 @@ void WM_OT_gpencil_export_svg(wmOperatorType *ot) "Clip Camera", "Clip drawings to camera size when export in camera view"); } -#endif +# endif /* <-------- PDF single frame export. --------> */ -#ifdef WITH_HARU +# ifdef WITH_HARU static bool wm_gpencil_export_pdf_common_check(bContext *UNUSED(C), wmOperator *op) { @@ -406,4 +408,6 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot) "Frames", "Which frames to include in the export"); } -#endif +# endif /* WITH_HARU */ + +#endif /* WITH_IO_GPENCIL */ diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c index 8bed32ad6c3..45f5441616f 100644 --- a/source/blender/editors/io/io_gpencil_import.c +++ b/source/blender/editors/io/io_gpencil_import.c @@ -5,34 +5,36 @@ * \ingroup editor/io */ -#include "BLI_path_util.h" +#ifdef WITH_IO_GPENCIL -#include "DNA_gpencil_types.h" -#include "DNA_space_types.h" +# include "BLI_path_util.h" -#include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_report.h" +# include "DNA_gpencil_types.h" +# include "DNA_space_types.h" -#include "BLT_translation.h" +# include "BKE_context.h" +# include "BKE_gpencil.h" +# include "BKE_report.h" -#include "RNA_access.h" -#include "RNA_define.h" +# include "BLT_translation.h" -#include "UI_interface.h" -#include "UI_resources.h" +# include "RNA_access.h" +# include "RNA_define.h" -#include "WM_api.h" -#include "WM_types.h" +# include "UI_interface.h" +# include "UI_resources.h" -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" +# include "WM_api.h" +# include "WM_types.h" -#include "ED_gpencil.h" +# include "DEG_depsgraph.h" +# include "DEG_depsgraph_query.h" -#include "io_gpencil.h" +# include "ED_gpencil.h" -#include "gpencil_io.h" +# include "io_gpencil.h" + +# include "gpencil_io.h" /* <-------- SVG single frame import. --------> */ static bool wm_gpencil_import_svg_common_check(bContext *UNUSED(C), wmOperator *op) @@ -174,3 +176,5 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot) 0.001f, 100.0f); } + +#endif /* WITH_IO_GPENCIL */ diff --git a/source/blender/editors/io/io_gpencil_utils.c b/source/blender/editors/io/io_gpencil_utils.c index fa5fcd79b96..9a88daef1a1 100644 --- a/source/blender/editors/io/io_gpencil_utils.c +++ b/source/blender/editors/io/io_gpencil_utils.c @@ -5,14 +5,16 @@ * \ingroup editor/io */ -#include "DNA_space_types.h" +#ifdef WITH_IO_GPENCIL -#include "BKE_context.h" -#include "BKE_screen.h" +# include "DNA_space_types.h" -#include "WM_api.h" +# include "BKE_context.h" +# include "BKE_screen.h" -#include "io_gpencil.h" +# include "WM_api.h" + +# include "io_gpencil.h" ARegion *get_invoke_region(bContext *C) { @@ -46,3 +48,5 @@ View3D *get_invoke_view3d(bContext *C) return NULL; } + +#endif /* WITH_IO_GPENCIL */ diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index f1cd7607771..53fa4788d0e 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -4,54 +4,39 @@ * \ingroup editor/io */ -#include "DNA_space_types.h" +#ifdef WITH_IO_WAVEFRONT_OBJ -#include "BKE_context.h" -#include "BKE_main.h" -#include "BKE_report.h" +# include "DNA_space_types.h" -#include "BLI_path_util.h" -#include "BLI_string.h" -#include "BLI_utildefines.h" +# include "BKE_context.h" +# include "BKE_main.h" +# include "BKE_report.h" -#include "BLT_translation.h" +# include "BLI_path_util.h" +# include "BLI_string.h" +# include "BLI_utildefines.h" -#include "ED_outliner.h" +# include "BLT_translation.h" -#include "MEM_guardedalloc.h" +# include "ED_outliner.h" -#include "RNA_access.h" -#include "RNA_define.h" +# include "MEM_guardedalloc.h" -#include "UI_interface.h" -#include "UI_resources.h" +# include "RNA_access.h" +# include "RNA_define.h" -#include "WM_api.h" -#include "WM_types.h" +# include "UI_interface.h" +# include "UI_resources.h" -#include "DEG_depsgraph.h" +# include "WM_api.h" +# include "WM_types.h" -#include "IO_path_util_types.h" -#include "IO_wavefront_obj.h" -#include "io_obj.h" +# include "DEG_depsgraph.h" -static const EnumPropertyItem io_obj_transform_axis_forward[] = { - {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"}, - {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"}, - {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"}, - {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"}, - {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"}, - {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z", "Negative Z axis"}, - {0, NULL, 0, NULL, NULL}}; - -static const EnumPropertyItem io_obj_transform_axis_up[] = { - {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"}, - {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y", "Positive Y axis"}, - {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"}, - {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"}, - {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"}, - {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"}, - {0, NULL, 0, NULL, NULL}}; +# include "IO_orientation.h" +# include "IO_path_util_types.h" +# include "IO_wavefront_obj.h" +# include "io_obj.h" static const EnumPropertyItem io_obj_export_evaluation_mode[] = { {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"}, @@ -115,6 +100,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op) export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects"); export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv"); export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals"); + export_params.export_colors = RNA_boolean_get(op->ptr, "export_colors"); export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials"); export_params.path_mode = RNA_enum_get(op->ptr, "path_mode"); export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh"); @@ -175,6 +161,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export")); uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE); uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE); + uiItemR(sub, imfptr, "export_colors", 0, IFACE_("Colors"), ICON_NONE); uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE); uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE); uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE); @@ -261,7 +248,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot) ot->ui = wm_obj_export_draw; ot->check = wm_obj_export_check; - ot->flag |= OPTYPE_PRESET; + ot->flag = OPTYPE_PRESET; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, @@ -296,13 +283,9 @@ void WM_OT_obj_export(struct wmOperatorType *ot) INT_MIN, INT_MAX); /* Object transform options. */ - RNA_def_enum(ot->srna, - "forward_axis", - io_obj_transform_axis_forward, - OBJ_AXIS_NEGATIVE_Z_FORWARD, - "Forward Axis", - ""); - RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", ""); + RNA_def_enum( + ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", ""); + RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", ""); RNA_def_float(ot->srna, "scaling_factor", 1.0f, @@ -334,6 +317,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot) "Export Normals", "Export per-face normals if the face is flat-shaded, per-face-per-loop " "normals if smooth-shaded"); + RNA_def_boolean(ot->srna, "export_colors", false, "Export Colors", "Export per-vertex colors"); RNA_def_boolean(ot->srna, "export_materials", true, @@ -408,6 +392,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op) import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size"); import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); import_params.up_axis = RNA_enum_get(op->ptr, "up_axis"); + import_params.import_vertex_groups = RNA_boolean_get(op->ptr, "import_vertex_groups"); import_params.validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes"); OBJ_import(C, &import_params); @@ -438,6 +423,7 @@ static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr) box = uiLayoutBox(layout); uiItemL(box, IFACE_("Options"), ICON_EXPORT); col = uiLayoutColumn(box, false); + uiItemR(col, imfptr, "import_vertex_groups", 0, NULL, ICON_NONE); uiItemR(col, imfptr, "validate_meshes", 0, NULL, ICON_NONE); } @@ -456,6 +442,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot) ot->name = "Import Wavefront OBJ"; ot->description = "Load a Wavefront OBJ scene"; ot->idname = "WM_OT_obj_import"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ot->invoke = wm_obj_import_invoke; ot->exec = wm_obj_import_exec; @@ -479,13 +466,14 @@ void WM_OT_obj_import(struct wmOperatorType *ot) "Resize the objects to keep bounding box under this value. Value 0 disables clamping", 0.0f, 1000.0f); - RNA_def_enum(ot->srna, - "forward_axis", - io_obj_transform_axis_forward, - OBJ_AXIS_NEGATIVE_Z_FORWARD, - "Forward Axis", - ""); - RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", ""); + RNA_def_enum( + ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", ""); + RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", ""); + RNA_def_boolean(ot->srna, + "import_vertex_groups", + false, + "Vertex Groups", + "Import OBJ groups as vertex groups"); RNA_def_boolean(ot->srna, "validate_meshes", false, @@ -496,3 +484,5 @@ void WM_OT_obj_import(struct wmOperatorType *ot) prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", ""); RNA_def_property_flag(prop, PROP_HIDDEN); } + +#endif /* WITH_IO_WAVEFRONT_OBJ */ diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index 094f89d1540..0340d0598d5 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -24,6 +24,7 @@ #include "io_cache.h" #include "io_gpencil.h" #include "io_obj.h" +#include "io_stl_ops.h" void ED_operatortypes_io(void) { @@ -41,14 +42,14 @@ void ED_operatortypes_io(void) WM_operatortype_append(WM_OT_usd_export); #endif +#ifdef WITH_IO_GPENCIL WM_operatortype_append(WM_OT_gpencil_import_svg); - -#ifdef WITH_PUGIXML +# ifdef WITH_PUGIXML WM_operatortype_append(WM_OT_gpencil_export_svg); -#endif - -#ifdef WITH_HARU +# endif +# ifdef WITH_HARU WM_operatortype_append(WM_OT_gpencil_export_pdf); +# endif #endif WM_operatortype_append(CACHEFILE_OT_open); @@ -58,6 +59,12 @@ void ED_operatortypes_io(void) WM_operatortype_append(CACHEFILE_OT_layer_remove); WM_operatortype_append(CACHEFILE_OT_layer_move); +#ifdef WITH_IO_WAVEFRONT_OBJ WM_operatortype_append(WM_OT_obj_export); WM_operatortype_append(WM_OT_obj_import); +#endif + +#ifdef WITH_IO_STL + WM_operatortype_append(WM_OT_stl_import); +#endif } diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c new file mode 100644 index 00000000000..7db32cd6f18 --- /dev/null +++ b/source/blender/editors/io/io_stl_ops.c @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup editor/io + */ + +#ifdef WITH_IO_STL + +# include "BKE_context.h" +# include "BKE_report.h" + +# include "WM_api.h" +# include "WM_types.h" + +# include "DNA_space_types.h" + +# include "ED_outliner.h" + +# include "RNA_access.h" +# include "RNA_define.h" + +# include "IO_stl.h" +# include "io_stl_ops.h" + +static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + return WM_operator_filesel(C, op, event); +} + +static int wm_stl_import_execute(bContext *C, wmOperator *op) +{ + struct STLImportParams params; + params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); + params.up_axis = RNA_enum_get(op->ptr, "up_axis"); + params.use_facet_normal = RNA_boolean_get(op->ptr, "use_facet_normal"); + params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit"); + params.global_scale = RNA_float_get(op->ptr, "global_scale"); + params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate"); + + int files_len = RNA_collection_length(op->ptr, "files"); + + if (files_len) { + PointerRNA fileptr; + PropertyRNA *prop; + char dir_only[FILE_MAX], file_only[FILE_MAX]; + + RNA_string_get(op->ptr, "directory", dir_only); + prop = RNA_struct_find_property(op->ptr, "files"); + for (int i = 0; i < files_len; i++) { + RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); + RNA_string_get(&fileptr, "name", file_only); + BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only); + STL_import(C, ¶ms); + } + } + else if (RNA_struct_property_is_set(op->ptr, "filepath")) { + RNA_string_get(op->ptr, "filepath", params.filepath); + STL_import(C, ¶ms); + } + else { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + Scene *scene = CTX_data_scene(C); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + ED_outliner_select_sync_from_object_tag(C); + + return OPERATOR_FINISHED; +} + +static bool wm_stl_import_check(bContext *UNUSED(C), wmOperator *op) +{ + const int num_axes = 3; + /* Both forward and up axes cannot be the same (or same except opposite sign). */ + if (RNA_enum_get(op->ptr, "forward_axis") % num_axes == + (RNA_enum_get(op->ptr, "up_axis") % num_axes)) { + RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % num_axes + 1); + return true; + } + return false; +} + +void WM_OT_stl_import(struct wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Import STL"; + ot->description = "Import an STL file as an object"; + ot->idname = "WM_OT_stl_import"; + + ot->invoke = wm_stl_import_invoke; + ot->exec = wm_stl_import_execute; + ot->poll = WM_operator_winactive; + ot->check = wm_stl_import_check; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY | + WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f); + RNA_def_boolean(ot->srna, + "use_scene_unit", + false, + "Scene Unit", + "Apply current scene's unit (as defined by unit scale) to imported data"); + RNA_def_boolean(ot->srna, + "use_facet_normal", + false, + "Facet Normals", + "Use (import) facet normals (note that this will still give flat shading)"); + RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", ""); + RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", ""); + RNA_def_boolean(ot->srna, + "use_mesh_validate", + false, + "Validate Mesh", + "Validate and correct imported mesh (slow)"); + + /* Only show .stl files by default. */ + prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); +} + +#endif /* WITH_IO_STL */ diff --git a/source/blender/editors/io/io_stl_ops.h b/source/blender/editors/io/io_stl_ops.h new file mode 100644 index 00000000000..8f548f75985 --- /dev/null +++ b/source/blender/editors/io/io_stl_ops.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup editor/io + */ + +#pragma once + +struct wmOperatorType; + +void WM_OT_stl_export(struct wmOperatorType *ot); +void WM_OT_stl_import(struct wmOperatorType *ot); diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index 609230eefea..a59cdf60243 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -57,6 +57,20 @@ const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = { + {USD_MTL_NAME_COLLISION_MAKE_UNIQUE, + "MAKE_UNIQUE", + 0, + "Make Unique", + "Import each USD material as a unique Blender material"}, + {USD_MTL_NAME_COLLISION_REFERENCE_EXISTING, + "REFERENCE_EXISTING", + 0, + "Reference Existing", + "If a material with the same name already exists, reference that instead of importing"}, + {0, NULL, 0, NULL, NULL}, +}; + /* Stored in the wmOperator's customdata field to indicate it should run as a background job. * This is set when the operator is invoked, and not set when it is only executed. */ enum { AS_BACKGROUND_JOB = 1 }; @@ -216,7 +230,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot) ot->ui = wm_usd_export_draw; ot->check = wm_usd_export_check; - ot->flag = OPTYPE_REGISTER; /* No UNDO possible. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_PRESET; /* No UNDO possible. */ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_USD, @@ -371,6 +385,9 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op) const float light_intensity_scale = RNA_float_get(op->ptr, "light_intensity_scale"); + const eUSDMtlNameCollisionMode mtl_name_collision_mode = RNA_enum_get(op->ptr, + "mtl_name_collision_mode"); + /* TODO(makowalski): Add support for sequences. */ const bool is_sequence = false; int offset = 0; @@ -409,7 +426,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op) .use_instancing = use_instancing, .import_usd_preview = import_usd_preview, .set_material_blend = set_material_blend, - .light_intensity_scale = light_intensity_scale}; + .light_intensity_scale = light_intensity_scale, + .mtl_name_collision_mode = mtl_name_collision_mode}; const bool ok = USD_import(C, filename, ¶ms, as_background_job); @@ -452,6 +470,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op) uiItemR(col, ptr, "relative_path", 0, NULL, ICON_NONE); uiItemR(col, ptr, "create_collection", 0, NULL, ICON_NONE); uiItemR(box, ptr, "light_intensity_scale", 0, NULL, ICON_NONE); + uiItemR(box, ptr, "mtl_name_collision_mode", 0, NULL, ICON_NONE); box = uiLayoutBox(layout); col = uiLayoutColumnWithHeading(box, true, IFACE_("Experimental")); @@ -575,6 +594,14 @@ void WM_OT_usd_import(struct wmOperatorType *ot) "Scale for the intensity of imported lights", 0.0001f, 1000.0f); + + RNA_def_enum( + ot->srna, + "mtl_name_collision_mode", + rna_enum_usd_mtl_name_collision_mode_items, + USD_MTL_NAME_COLLISION_MAKE_UNIQUE, + "Material Name Collision", + "Behavior when the name of an imported material conflicts with an existing material"); } #endif /* WITH_USD */ diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index d10c420e28c..37c1815fca3 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -31,7 +31,9 @@ #include "mask_intern.h" /* own include */ -/******************** add vertex *********************/ +/* -------------------------------------------------------------------- */ +/** \name Add Vertex + * \{ */ static void setup_vertex_point(Mask *mask, MaskSpline *spline, @@ -160,7 +162,11 @@ static void setup_vertex_point(Mask *mask, ED_mask_select_flush_all(mask); } -/* **** add extrude vertex **** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Extrude Vertex + * \{ */ static void finSelectedSplinePoint(MaskLayer *mask_layer, MaskSpline **spline, @@ -206,7 +212,11 @@ static void finSelectedSplinePoint(MaskLayer *mask_layer, } } -/* **** add subdivide vertex **** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Subdivide Vertex + * \{ */ static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index) { @@ -390,7 +400,7 @@ static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *mask_layer, MaskSplinePoint *new_point = NULL, *ref_point = NULL; if (!mask_layer) { - /* if there's no mask layer currently operationg on, create new one */ + /* If there's no mask layer currently operating on, create new one. */ mask_layer = BKE_mask_layer_new(mask, ""); mask->masklay_act = mask->masklay_tot - 1; } @@ -492,6 +502,12 @@ static int add_vertex_handle_cyclic( return OPERATOR_PASS_THROUGH; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Vertex Operator + * \{ */ + static int add_vertex_exec(bContext *C, wmOperator *op) { MaskViewLockState lock_state; @@ -567,7 +583,7 @@ void MASK_OT_add_vertex(wmOperatorType *ot) /* api callbacks */ ot->exec = add_vertex_exec; ot->invoke = add_vertex_invoke; - ot->poll = ED_operator_mask; + ot->poll = ED_maskedit_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -585,7 +601,11 @@ void MASK_OT_add_vertex(wmOperatorType *ot) 1.0f); } -/******************** add feather vertex *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Feather Vertex Operator + * \{ */ static int add_feather_vertex_exec(bContext *C, wmOperator *op) { @@ -677,7 +697,11 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot) 1.0f); } -/******************** common primitive functions *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Common Primitive Functions + * \{ */ static BezTriple *points_to_bezier(const float (*points)[2], const int num_points, @@ -812,7 +836,11 @@ static void define_primitive_add_properties(wmOperatorType *ot) FLT_MAX); } -/******************** primitive add circle *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Primitive Add Circle Operator + * \{ */ static int primitive_circle_add_exec(bContext *C, wmOperator *op) { @@ -834,7 +862,7 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot) /* api callbacks */ ot->exec = primitive_circle_add_exec; ot->invoke = primitive_add_invoke; - ot->poll = ED_operator_mask; + ot->poll = ED_maskedit_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -843,7 +871,11 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot) define_primitive_add_properties(ot); } -/******************** primitive add suqare *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Primitive Add Suqare Operator + * \{ */ static int primitive_square_add_exec(bContext *C, wmOperator *op) { @@ -865,7 +897,7 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot) /* api callbacks */ ot->exec = primitive_square_add_exec; ot->invoke = primitive_add_invoke; - ot->poll = ED_operator_mask; + ot->poll = ED_maskedit_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -873,3 +905,5 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot) /* properties */ define_primitive_add_properties(ot); } + +/** \} */ diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index aab4007854f..a18419ad422 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -663,6 +663,7 @@ void ED_mask_draw_region( const char draw_flag, const char draw_type, const eMaskOverlayMode overlay_mode, + const float blend_factor, /* convert directly into aspect corrected vars */ const int width_i, const int height_i, @@ -721,12 +722,14 @@ void ED_mask_draw_region( } if (draw_flag & MASK_DRAWFLAG_OVERLAY) { - const float red[4] = {1.0f, 0.0f, 0.0f, 0.0f}; + float buf_col[4] = {1.0f, 0.0f, 0.0f, 0.0f}; float *buffer = mask_rasterize(mask_eval, width, height); if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) { /* More blending types could be supported in the future. */ - GPU_blend(GPU_BLEND_MULTIPLY); + GPU_blend(GPU_BLEND_ALPHA); + buf_col[0] = -1.0f; + buf_col[3] = 1.0f; } GPU_matrix_push(); @@ -737,10 +740,18 @@ void ED_mask_draw_region( } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); - immDrawPixelsTexTiled( - &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, buf_col); + if (overlay_mode == MASK_OVERLAY_COMBINED) { + const float blend_col[4] = {0.0f, 0.0f, 0.0f, blend_factor}; + + immDrawPixelsTexTiled( + &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, blend_col); + } + else { + immDrawPixelsTexTiled( + &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL); + } GPU_matrix_pop(); if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) { @@ -765,7 +776,9 @@ void ED_mask_draw_region( } /* draw! */ - draw_mask_layers(C, mask_eval, draw_flag, draw_type, width, height); + if (draw_flag & MASK_DRAWFLAG_SPLINE) { + draw_mask_layers(C, mask_eval, draw_flag, draw_type, width, height); + } if (do_draw_cb) { ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index b2d49bcc642..915f90a1537 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -42,6 +42,22 @@ bool ED_maskedit_poll(bContext *C) return false; } +bool ED_maskedit_visible_splines_poll(bContext *C) +{ + ScrArea *area = CTX_wm_area(C); + if (area) { + switch (area->spacetype) { + case SPACE_CLIP: + return ED_space_clip_maskedit_visible_splines_poll(C); + case SPACE_SEQ: + return ED_space_sequencer_maskedit_poll(C); + case SPACE_IMAGE: + return ED_space_image_maskedit_visible_splines_poll(C); + } + } + return false; +} + bool ED_maskedit_mask_poll(bContext *C) { ScrArea *area = CTX_wm_area(C); @@ -58,6 +74,22 @@ bool ED_maskedit_mask_poll(bContext *C) return false; } +bool ED_maskedit_mask_visible_splines_poll(bContext *C) +{ + const ScrArea *area = CTX_wm_area(C); + if (area) { + switch (area->spacetype) { + case SPACE_CLIP: + return ED_space_clip_maskedit_mask_visible_splines_poll(C); + case SPACE_SEQ: + return ED_space_sequencer_maskedit_mask_poll(C); + case SPACE_IMAGE: + return ED_space_image_maskedit_mask_visible_splines_poll(C); + } + } + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index c620d781c7f..2e99b45f215 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -86,9 +86,6 @@ void ED_mask_select_flush_all(struct Mask *mask); /* mask_editor.c */ -bool ED_maskedit_poll(struct bContext *C); -bool ED_maskedit_mask_poll(struct bContext *C); - /* Generalized solution for preserving editor viewport when making changes while lock-to-selection * is enabled. * Any mask operator can use this API, without worrying that some editors do not have an idea of diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 3c0e7ee399c..14976d860f6 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -113,7 +113,7 @@ void MASK_OT_new(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_new_exec; - ot->poll = ED_operator_mask; + ot->poll = ED_maskedit_poll; /* properties */ RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask"); @@ -146,7 +146,7 @@ void MASK_OT_layer_new(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_layer_new_exec; - ot->poll = ED_maskedit_poll; + ot->poll = ED_maskedit_mask_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -181,7 +181,7 @@ void MASK_OT_layer_remove(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_layer_remove_exec; - ot->poll = ED_maskedit_poll; + ot->poll = ED_maskedit_mask_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -907,7 +907,7 @@ void MASK_OT_slide_point(wmOperatorType *ot) /* api callbacks */ ot->invoke = slide_point_invoke; ot->modal = slide_point_modal; - ot->poll = ED_operator_mask; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1297,7 +1297,7 @@ void MASK_OT_slide_spline_curvature(wmOperatorType *ot) /* api callbacks */ ot->invoke = slide_spline_curvature_invoke; ot->modal = slide_spline_curvature_modal; - ot->poll = ED_operator_mask; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1336,7 +1336,7 @@ void MASK_OT_cyclic_toggle(wmOperatorType *ot) /* api callbacks */ ot->exec = cyclic_toggle_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1493,7 +1493,7 @@ void MASK_OT_delete(wmOperatorType *ot) /* api callbacks */ ot->invoke = WM_operator_confirm; ot->exec = delete_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1551,7 +1551,7 @@ void MASK_OT_switch_direction(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_switch_direction_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1613,7 +1613,7 @@ void MASK_OT_normals_make_consistent(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_normals_make_consistent_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1693,7 +1693,7 @@ void MASK_OT_handle_type_set(wmOperatorType *ot) /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = set_handle_type_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1849,7 +1849,7 @@ void MASK_OT_feather_weight_clear(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_feather_weight_clear_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2043,7 +2043,7 @@ void MASK_OT_duplicate(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_duplicate_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2084,7 +2084,7 @@ void MASK_OT_copy_splines(wmOperatorType *ot) static bool paste_splines_poll(bContext *C) { - if (ED_maskedit_mask_poll(C)) { + if (ED_maskedit_mask_visible_splines_poll(C)) { return BKE_mask_clipboard_is_empty() == false; } diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c index 89524a7b9e2..02e1524e23e 100644 --- a/source/blender/editors/mask/mask_query.c +++ b/source/blender/editors/mask/mask_query.c @@ -615,7 +615,7 @@ bool ED_mask_selected_minmax(const bContext *C, /* Use evaluated mask to take animation into account. * The animation of splies is not "flushed" back to original, so need to explicitly - * sue evaluated datablock here. */ + * use evaluated datablock here. */ Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask->id); INIT_MINMAX2(min, max); diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c index 9d8b84de66b..1f175ce51fc 100644 --- a/source/blender/editors/mask/mask_relationships.c +++ b/source/blender/editors/mask/mask_relationships.c @@ -21,6 +21,7 @@ #include "WM_types.h" #include "ED_clip.h" /* frame remapping functions */ +#include "ED_mask.h" #include "ED_screen.h" #include "mask_intern.h" /* own include */ @@ -61,7 +62,7 @@ void MASK_OT_parent_clear(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_parent_clear_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index 7c0b6fb0a93..4bd80208b9e 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -222,7 +222,7 @@ void MASK_OT_select_all(wmOperatorType *ot) /* api callbacks */ ot->exec = select_all_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -364,12 +364,9 @@ static int select_exec(bContext *C, wmOperator *op) return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; } if (deselect_all) { - /* For clip editor tracks, leave deselect all to clip editor. */ - if (!ED_clip_can_select(C)) { - ED_mask_deselect_all(C); - ED_mask_view_lock_state_restore_no_jump(C, &lock_state); - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; - } + ED_mask_deselect_all(C); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; } return OPERATOR_PASS_THROUGH; @@ -401,7 +398,7 @@ void MASK_OT_select(wmOperatorType *ot) /* api callbacks */ ot->exec = select_exec; ot->invoke = select_invoke; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; ot->get_name = ED_select_pick_get_name; /* flags */ @@ -507,7 +504,7 @@ void MASK_OT_select_box(wmOperatorType *ot) ot->invoke = WM_gesture_box_invoke; ot->exec = box_select_exec; ot->modal = WM_gesture_box_modal; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_UNDO; @@ -630,7 +627,7 @@ void MASK_OT_select_lasso(wmOperatorType *ot) ot->invoke = WM_gesture_lasso_invoke; ot->modal = WM_gesture_lasso_modal; ot->exec = clip_lasso_select_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; ot->cancel = WM_gesture_lasso_cancel; /* flags */ @@ -748,7 +745,7 @@ void MASK_OT_select_circle(wmOperatorType *ot) ot->invoke = WM_gesture_circle_invoke; ot->modal = WM_gesture_circle_modal; ot->exec = circle_select_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; ot->get_name = ED_select_circle_get_name; /* flags */ @@ -812,7 +809,7 @@ void MASK_OT_select_linked_pick(wmOperatorType *ot) /* api callbacks */ ot->invoke = mask_select_linked_pick_invoke; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -867,7 +864,7 @@ void MASK_OT_select_linked(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_select_linked_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -966,7 +963,7 @@ void MASK_OT_select_more(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_select_more_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -986,7 +983,7 @@ void MASK_OT_select_less(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_select_less_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c index dd54d84a90b..55145f27012 100644 --- a/source/blender/editors/mask/mask_shapekey.c +++ b/source/blender/editors/mask/mask_shapekey.c @@ -67,7 +67,7 @@ void MASK_OT_shape_key_insert(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_shape_key_insert_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -113,7 +113,7 @@ void MASK_OT_shape_key_clear(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_shape_key_clear_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -197,7 +197,7 @@ void MASK_OT_shape_key_feather_reset(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_shape_key_feather_reset_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -356,7 +356,7 @@ void MASK_OT_shape_key_rekey(wmOperatorType *ot) /* api callbacks */ ot->exec = mask_shape_key_rekey_exec; - ot->poll = ED_maskedit_mask_poll; + ot->poll = ED_maskedit_mask_visible_splines_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index cb5d48d1023..69fe69fe117 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -158,7 +158,7 @@ void paintface_reveal(bContext *C, Object *ob, const bool select) paintface_flush_flags(C, ob, SELECT | ME_HIDE); } -/* Set tface seams based on edge data, uses hash table to find seam edges. */ +/* Set object-mode face selection seams based on edge data, uses hash table to find seam edges. */ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bool select) { diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 969d5b5912c..e7891450bd6 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -669,7 +669,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) short etype = event->type; short eval = event->val; - /* When activated from toolbar, need to convert leftmouse release to confirm */ + /* When activated from toolbar, need to convert left-mouse release to confirm. */ if (ELEM(etype, LEFTMOUSE, opdata->launch_event) && (eval == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm")) { etype = EVT_MODAL_MAP; diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 5b3487b0a33..5680865ae67 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1355,13 +1355,19 @@ static void knife_bvh_raycast_cb(void *userdata, #endif if (isect && dist < hit->dist) { + madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist); + + /* Discard clipped points. */ + if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) && + ED_view3d_clipping_test(kcd->vc.rv3d, hit->co, false)) { + return; + } + hit->dist = dist; hit->index = index; copy_v3_v3(hit->no, ltri[0]->f->no); - madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist); - kcd->bvh.looptris = em->looptris; copy_v2_v2(kcd->bvh.uv, uv); kcd->bvh.base_index = b; @@ -4672,6 +4678,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEMOVE: /* Mouse moved somewhere to select another loop. */ if (kcd->mode != MODE_PANNING) { knifetool_update_mval_i(kcd, event->mval); + knife_update_header(C, op, kcd); if (kcd->is_drag_hold) { if (kcd->totlinehit >= 2) { @@ -4754,6 +4761,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) /* We don't really need to update mval, * but this happens to be the best way to refresh at the moment. */ knifetool_update_mval_i(kcd, event->mval); + knife_update_header(C, op, kcd); } /* Keep going until the user confirms. */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index feecefdb7ea..1febc429edc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3092,8 +3092,8 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op) BMOperator bmop; - Mesh *me = BKE_object_get_original_mesh(ob); - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); + const Mesh *me = BKE_object_get_original_mesh(ob); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) { continue; @@ -3144,8 +3144,8 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op) continue; } - Mesh *me = BKE_object_get_original_mesh(obedit); - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); + const Mesh *me = BKE_object_get_original_mesh(obedit); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) { continue; diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index ecc5f8f8ef5..d75c92f963f 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -72,7 +72,7 @@ static CLG_LogRef LOG = {"ed.undo.mesh"}; /* Single linked list of layers stored per type */ typedef struct BArrayCustomData { struct BArrayCustomData *next; - CustomDataType type; + eCustomDataType type; int states_len; /* number of layers for each type */ BArrayState *states[0]; } BArrayCustomData; @@ -149,7 +149,7 @@ static void um_arraystore_cd_compact(struct CustomData *cdata, const BArrayCustomData *bcd_reference_current = bcd_reference; BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL; for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) { - const CustomDataType type = cdata->layers[layer_start].type; + const eCustomDataType type = cdata->layers[layer_start].type; /* Perform a full copy on dynamic layers. * diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index c7c7e5cf2f8..04030583f5c 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1641,21 +1641,22 @@ void EDBM_project_snap_verts( float mval[2], co_proj[3]; if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - if (ED_transform_snap_object_project_view3d(snap_context, - depsgraph, - region, - CTX_wm_view3d(C), - SCE_SNAP_MODE_FACE, - &(const struct SnapObjectParams){ - .snap_select = SNAP_NOT_ACTIVE, - .edit_mode_type = SNAP_GEOM_FINAL, - .use_occlusion_test = true, - }, - mval, - NULL, - NULL, - co_proj, - NULL)) { + if (ED_transform_snap_object_project_view3d( + snap_context, + depsgraph, + region, + CTX_wm_view3d(C), + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_target_select = SCE_SNAP_TARGET_NOT_ACTIVE, + .edit_mode_type = SNAP_GEOM_FINAL, + .use_occlusion_test = true, + }, + mval, + NULL, + NULL, + co_proj, + NULL)) { mul_v3_m4v3(eve->co, obedit->imat, co_proj); } } diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 422aaa03120..041a1383b28 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -621,9 +621,16 @@ Object *ED_object_add_type_with_obdata(bContext *C, else { ob = BKE_object_add(bmain, view_layer, type, name); } - BASACT(view_layer)->local_view_bits = local_view_bits; - /* editor level activate, notifiers */ - ED_object_base_activate(C, view_layer->basact); + + Base *ob_base_act = BASACT(view_layer); + /* While not getting a valid base is not a good thing, it can happen in convoluted corner cases, + * better not crash on it in releases. */ + BLI_assert(ob_base_act != nullptr); + if (ob_base_act != nullptr) { + ob_base_act->local_view_bits = local_view_bits; + /* editor level activate, notifiers */ + ED_object_base_activate(C, ob_base_act); + } /* more editor stuff */ ED_object_base_init_transform_on_add(ob, loc, rot); @@ -2079,6 +2086,12 @@ static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op) Curves *curves_id = static_cast<Curves *>(object->data); curves_id->surface = surface_ob; id_us_plus(&surface_ob->id); + + Mesh *surface_mesh = static_cast<Mesh *>(surface_ob->data); + const char *uv_name = CustomData_get_active_layer_name(&surface_mesh->ldata, CD_MLOOPUV); + if (uv_name != nullptr) { + curves_id->surface_uv_map = BLI_strdup(uv_name); + } } return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 1483c24ac70..effbde41c38 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -220,22 +220,22 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); Mesh *me = (Mesh *)ob->data; MultiresModifierData tmp_mmd = *mmd; - DerivedMesh *cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + *lvl = mmd->lvl; if (mmd->lvl == 0) { - dm = CDDM_copy(cddm); - } - else { - tmp_mmd.lvl = mmd->lvl; - tmp_mmd.sculptlvl = mmd->lvl; - dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); + DerivedMesh *cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + return cddm; } - cddm->release(cddm); + DerivedMesh *cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + tmp_mmd.lvl = mmd->lvl; + tmp_mmd.sculptlvl = mmd->lvl; + dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); - *lvl = mmd->lvl; + cddm->release(cddm); return dm; } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 114b2ce8102..58daf753679 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -21,6 +21,8 @@ #include "BLI_path_util.h" #include "BLI_string.h" +#include "BKE_attribute.h" +#include "BKE_callbacks.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" @@ -446,14 +448,11 @@ static bool bake_object_check(ViewLayer *view_layer, } if (target == R_BAKE_TARGET_VERTEX_COLORS) { - const MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); - const bool mcol_valid = (mcol != NULL); - const MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR); - if (mloopcol == NULL && !mcol_valid) { + if (BKE_id_attributes_active_color_get(&me->id) == NULL) { BKE_reportf(reports, RPT_ERROR, - "No vertex colors layer found in the object \"%s\"", - ob->id.name + 2); + "Mesh does not have an active color attribute \"%s\"", + me->id.name + 2); return false; } } @@ -937,17 +936,13 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr, static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, ReportList *reports) { if (ob->type != OB_MESH) { - BKE_report( - reports, RPT_ERROR, "Vertex color baking not support with object types other than mesh"); + BKE_report(reports, RPT_ERROR, "Color attribute baking is only supported for mesh objects"); return false; } Mesh *me = ob->data; - const MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); - const bool mcol_valid = (mcol != NULL); - const MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR); - if (mloopcol == NULL && !mcol_valid) { - BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to"); + if (BKE_id_attributes_active_color_get(&me->id) == NULL) { + BKE_report(reports, RPT_ERROR, "No active color attribute to bake to"); return false; } @@ -996,10 +991,10 @@ static int find_original_loop(const Mesh *me_orig, return ORIGINDEX_NONE; } -static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets, - Object *ob, - Mesh *me_eval, - BakePixel *pixel_array) +static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets, + Object *ob, + Mesh *me_eval, + BakePixel *pixel_array) { Mesh *me = ob->data; const int pixels_num = targets->pixels_num; @@ -1094,19 +1089,42 @@ static void bake_result_add_to_rgba(float rgba[4], const float *result, const in } } +static void convert_float_color_to_byte_color(const MPropCol *float_colors, + const int num, + const bool is_noncolor, + MLoopCol *byte_colors) +{ + if (is_noncolor) { + for (int i = 0; i < num; i++) { + unit_float_to_uchar_clamp_v4(&byte_colors->r, float_colors[i].color); + } + } + else { + for (int i = 0; i < num; i++) { + linearrgb_to_srgb_uchar4(&byte_colors[i].r, float_colors[i].color); + } + } +} + static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob) { Mesh *me = ob->data; - MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); - const bool mcol_valid = (mcol != NULL); - MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR); + CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id); + BLI_assert(active_color_layer != NULL); + const eAttrDomain domain = BKE_id_attribute_domain(&me->id, active_color_layer); + const int channels_num = targets->channels_num; + const bool is_noncolor = targets->is_noncolor; const float *result = targets->result; - if (mcol_valid) { + if (domain == ATTR_DOMAIN_POINT) { const int totvert = me->totvert; const int totloop = me->totloop; + MPropCol *mcol = active_color_layer->type == CD_PROP_COLOR ? + active_color_layer->data : + MEM_malloc_arrayN(totvert, sizeof(MPropCol), __func__); + /* Accumulate float vertex colors in scene linear color space. */ int *num_loops_for_vertex = MEM_callocN(sizeof(int) * me->totvert, "num_loops_for_vertex"); memset(mcol, 0, sizeof(MPropCol) * me->totvert); @@ -1125,25 +1143,35 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob) } } + if (mcol != active_color_layer->data) { + convert_float_color_to_byte_color(mcol, totvert, is_noncolor, active_color_layer->data); + MEM_freeN(mcol); + } + MEM_SAFE_FREE(num_loops_for_vertex); } - else { - /* Byte loop colors in sRGB colors space. */ - MLoop *mloop = me->mloop; - const int totloop = me->totloop; - const bool is_noncolor = targets->is_noncolor; - - for (int i = 0; i < totloop; i++, mloop++, mloopcol++) { - float rgba[4]; - zero_v4(rgba); - bake_result_add_to_rgba(rgba, &result[i * channels_num], channels_num); - - if (is_noncolor) { - unit_float_to_uchar_clamp_v4(&mloopcol->r, rgba); + else if (domain == ATTR_DOMAIN_CORNER) { + switch (active_color_layer->type) { + case CD_PROP_COLOR: { + MPropCol *colors = active_color_layer->data; + for (int i = 0; i < me->totloop; i++) { + zero_v4(colors[i].color); + bake_result_add_to_rgba(colors[i].color, &result[i * channels_num], channels_num); + } + break; } - else { - linearrgb_to_srgb_uchar4(&mloopcol->r, rgba); + case CD_PROP_BYTE_COLOR: { + MLoopCol *colors = active_color_layer->data; + for (int i = 0; i < me->totloop; i++) { + MPropCol color; + zero_v4(color.color); + bake_result_add_to_rgba(color.color, &result[i * channels_num], channels_num); + convert_float_color_to_byte_color(&color, 1, is_noncolor, &colors[i]); + } + break; } + default: + BLI_assert_unreachable(); } } @@ -1197,7 +1225,7 @@ static void bake_targets_populate_pixels(const BakeAPIRender *bkr, BakePixel *pixel_array) { if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) { - bake_targets_populate_pixels_vertex_colors(targets, ob, me_eval, pixel_array); + bake_targets_populate_pixels_color_attributes(targets, ob, me_eval, pixel_array); } else { RE_bake_pixels_populate(me_eval, pixel_array, targets->pixels_num, targets, bkr->uv_layer); @@ -1535,7 +1563,7 @@ static int bake(const BakeAPIRender *bkr, ob_low_eval->obmat); } else { - /* from multiresolution */ + /* From multi-resolution. */ Mesh *me_nores = NULL; ModifierData *md = NULL; int mode; @@ -1806,6 +1834,17 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa RE_SetReports(bkr->render, NULL); } +static void bake_job_complete(void *bkv) +{ + BakeAPIRender *bkr = (BakeAPIRender *)bkv; + BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_COMPLETE); +} +static void bake_job_canceled(void *bkv) +{ + BakeAPIRender *bkr = (BakeAPIRender *)bkv; + BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_CANCEL); +} + static void bake_freejob(void *bkv) { BakeAPIRender *bkr = (BakeAPIRender *)bkv; @@ -1941,6 +1980,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) /* init bake render */ bake_init_api_data(op, C, bkr); + BKE_callback_exec_id(CTX_data_main(C), &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_PRE); re = bkr->render; /* setup new render */ @@ -1958,7 +1998,8 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) /* TODO: only draw bake image, can we enforce this. */ WM_jobs_timer( wm_job, 0.5, (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) ? NC_GEOM | ND_DATA : NC_IMAGE, 0); - WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL); + WM_jobs_callbacks_ex( + wm_job, bake_startjob, NULL, NULL, NULL, bake_job_complete, bake_job_canceled); G.is_break = false; G.is_rendering = true; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index d982d86fe77..bf3b71178e8 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -245,13 +245,11 @@ static void set_constraint_nth_target(bConstraint *con, const char subtarget[], int index) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; int num_targets, i; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); + if (BKE_constraint_targets_get(con, &targets)) { num_targets = BLI_listbase_count(&targets); if (index < 0) { @@ -274,9 +272,7 @@ static void set_constraint_nth_target(bConstraint *con, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } } @@ -289,7 +285,6 @@ static void set_constraint_nth_target(bConstraint *con, static void test_constraint( Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; bool check_targets = true; @@ -465,14 +460,7 @@ static void test_constraint( } /* Check targets for constraints */ - if (check_targets && cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - /* constraints with empty target list that actually require targets */ - if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { - con->flag |= CONSTRAINT_DISABLE; - } - + if (check_targets && BKE_constraint_targets_get(con, &targets)) { /* disable and clear constraints targets that are incorrect */ for (ct = targets.first; ct; ct = ct->next) { /* general validity checks (for those constraints that need this) */ @@ -543,8 +531,12 @@ static void test_constraint( } /* free any temporary targets */ - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); + BKE_constraint_targets_flush(con, &targets, 0); + } + else if (check_targets) { + /* constraints with empty target list that actually require targets */ + if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { + con->flag |= CONSTRAINT_DISABLE; } } } diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index dfe858e5bd9..4837b538bf6 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[] = { - {0, "", 0, "Vertex Data", ""}, + RNA_ENUM_ITEM_HEADING("Vertex Data", NULL), {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, @@ -60,7 +60,8 @@ static const EnumPropertyItem DT_layer_items[] = { {DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"}, #endif {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"}, - {0, "", 0, "Edge Data", ""}, + + RNA_ENUM_ITEM_HEADING("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"}, @@ -70,11 +71,13 @@ static const EnumPropertyItem DT_layer_items[] = { 0, "Freestyle Mark", "Transfer Freestyle edge mark"}, - {0, "", 0, "Face Corner Data", ""}, + + RNA_ENUM_ITEM_HEADING("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"}, - {0, "", 0, "Face Data", ""}, + + RNA_ENUM_ITEM_HEADING("Face Data", NULL), {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"}, {DT_TYPE_FREESTYLE_FACE, "FREESTYLE_FACE", @@ -85,14 +88,14 @@ static const EnumPropertyItem DT_layer_items[] = { }; static void dt_add_vcol_layers(CustomData *cdata, - CustomDataMask mask, + eCustomDataMask mask, EnumPropertyItem **r_item, int *r_totitem) { int types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR}; for (int i = 0; i < 2; i++) { - CustomDataType type = types[i]; + eCustomDataType type = types[i]; if (!(mask & CD_TYPE_AS_MASK(type))) { continue; diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index fdf2cae026d..0055cdf9ea1 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -458,7 +458,7 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base return false; } - bool mode_transfered = false; + bool mode_transferred = false; ED_undo_group_begin(C); @@ -480,11 +480,11 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); WM_toolsystem_update_from_context_view3d(C); - mode_transfered = true; + mode_transferred = true; } ED_undo_group_end(C); - return mode_transfered; + return mode_transferred; } static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -493,8 +493,8 @@ static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEven const eObjectMode src_mode = (eObjectMode)ob_src->mode; Base *base_dst = ED_view3d_give_base_under_cursor(C, event->mval); - const bool mode_transfered = object_transfer_mode_to_base(C, op, base_dst); - if (!mode_transfered) { + const bool mode_transferred = object_transfer_mode_to_base(C, op, base_dst); + if (!mode_transferred) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index 963e92942bb..202c6d96a47 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -515,12 +515,12 @@ void ED_object_modifier_copy_to_object(bContext *C, DEG_relations_tag_update(bmain); } -bool ED_object_modifier_convert(ReportList *UNUSED(reports), - Main *bmain, - Depsgraph *depsgraph, - ViewLayer *view_layer, - Object *ob, - ModifierData *md) +bool ED_object_modifier_convert_psys_to_mesh(ReportList *UNUSED(reports), + Main *bmain, + Depsgraph *depsgraph, + ViewLayer *view_layer, + Object *ob, + ModifierData *md) { int cvert = 0; @@ -1468,7 +1468,7 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo return OPERATOR_CANCELLED; } - if (do_merge_customdata && + if (ob->type == OB_MESH && do_merge_customdata && (mti->type & (eModifierTypeType_Constructive | eModifierTypeType_Nonconstructive))) { BKE_mesh_merge_customdata_for_apply_modifier((Mesh *)ob->data); } @@ -1531,12 +1531,12 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot) edit_modifier_properties(ot); edit_modifier_report_property(ot); - RNA_def_boolean( - ot->srna, - "merge_customdata", - true, - "Merge UV's", - "Merge UV coordinates that share a vertex to account for imprecision in some modifiers"); + RNA_def_boolean(ot->srna, + "merge_customdata", + true, + "Merge UV's", + "For mesh objects, merge UV coordinates that share a vertex to account for " + "imprecision in some modifiers"); PropertyRNA *prop = RNA_def_boolean(ot->srna, "single_user", false, @@ -1608,7 +1608,7 @@ void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot) /** \} */ /* ------------------------------------------------------------------- */ -/** \name Convert Modifier Operator +/** \name Convert Particle System Modifier to Mesh Operator * \{ */ static int modifier_convert_exec(bContext *C, wmOperator *op) @@ -1618,18 +1618,12 @@ static int modifier_convert_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = ED_object_active_context(C); ModifierData *md = edit_modifier_property_get(op, ob, 0); - const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); - const bool do_merge_customdata = RNA_boolean_get(op->ptr, "merge_customdata"); - if (!md || !ED_object_modifier_convert(op->reports, bmain, depsgraph, view_layer, ob, md)) { + if (!md || !ED_object_modifier_convert_psys_to_mesh( + op->reports, bmain, depsgraph, view_layer, ob, md)) { return OPERATOR_CANCELLED; } - if (do_merge_customdata && - (mti->type & (eModifierTypeType_Constructive | eModifierTypeType_Nonconstructive))) { - BKE_mesh_merge_customdata_for_apply_modifier((Mesh *)ob->data); - } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); @@ -1646,7 +1640,7 @@ static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *U void OBJECT_OT_modifier_convert(wmOperatorType *ot) { - ot->name = "Convert Modifier"; + ot->name = "Convert Particles to Mesh"; ot->description = "Convert particles to a mesh object"; ot->idname = "OBJECT_OT_modifier_convert"; @@ -1657,13 +1651,6 @@ void OBJECT_OT_modifier_convert(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; edit_modifier_properties(ot); - - RNA_def_boolean( - ot->srna, - "merge_customdata", - true, - "Merge UV's", - "Merge UV coordinates that share a vertex to account for imprecision in some modifiers"); } /** \} */ diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 1067c2d6a95..8a0d380ff2f 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -281,7 +281,7 @@ void ED_operatormacros_object(void) ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move", "Duplicate Objects", - "Duplicate selected objects and move them", + "Duplicate the selected objects and move them", OPTYPE_UNDO | OPTYPE_REGISTER); if (ot) { WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); @@ -289,11 +289,11 @@ void ED_operatormacros_object(void) RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false); } - /* grr, should be able to pass options on... */ - ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move_linked", - "Duplicate Linked", - "Duplicate selected objects and move them", - OPTYPE_UNDO | OPTYPE_REGISTER); + ot = WM_operatortype_append_macro( + "OBJECT_OT_duplicate_move_linked", + "Duplicate Linked", + "Duplicate the selected objects, but not their object data, and move them", + OPTYPE_UNDO | OPTYPE_REGISTER); if (ot) { otmacro = WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); RNA_boolean_set(otmacro->ptr, "linked", true); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index abbde3b5b3a..f55ffdf0fcd 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1653,7 +1653,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) "Link Instance Collection", "Replace assigned Collection Instance"}, {MAKE_LINKS_FONTS, "FONTS", 0, "Link Fonts to Text", "Replace Text object Fonts"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Copy Modifiers", "Replace Modifiers"}, {MAKE_LINKS_SHADERFX, "EFFECTS", @@ -2290,27 +2290,19 @@ static int make_override_library_exec(bContext *C, wmOperator *op) user_overrides_from_selected_objects = false; } else if (!make_override_library_object_overridable_check(bmain, obact)) { - const int i = RNA_property_enum_get(op->ptr, op->type->prop); - const uint collection_session_uuid = *((uint *)&i); + const int i = RNA_property_int_get(op->ptr, op->type->prop); + const uint collection_session_uuid = *((const uint *)&i); if (collection_session_uuid == MAIN_ID_SESSION_UUID_UNSET) { BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, - "Active object '%s' is not overridable", + "Could not find an overridable root hierarchy for object '%s'", obact->id.name + 2); return OPERATOR_CANCELLED; } - Collection *collection = BLI_listbase_bytes_find(&bmain->collections, &collection_session_uuid, sizeof(collection_session_uuid), offsetof(ID, session_uuid)); - if (!ID_IS_OVERRIDABLE_LIBRARY(collection)) { - BKE_reportf(op->reports, - RPT_ERROR_INVALID_INPUT, - "Could not find an overridable collection containing object '%s'", - obact->id.name + 2); - return OPERATOR_CANCELLED; - } id_root = &collection->id; user_overrides_from_selected_objects = true; } @@ -2372,10 +2364,36 @@ static int make_override_library_exec(bContext *C, wmOperator *op) BLI_gset_free(user_overrides_objects_uids, NULL); } - /* Remove the instance empty from this scene, the items now have an overridden collection - * instead. */ - if (success && is_override_instancing_object) { - ED_object_base_free_and_unlink(bmain, scene, obact); + if (success) { + if (is_override_instancing_object) { + /* Remove the instance empty from this scene, the items now have an overridden collection + * instead. */ + ED_object_base_free_and_unlink(bmain, scene, obact); + } + else { + /* Remove the found root ID from the view layer. */ + switch (GS(id_root->name)) { + case ID_GR: { + Collection *collection_root = (Collection *)id_root; + LISTBASE_FOREACH_MUTABLE ( + CollectionParent *, collection_parent, &collection_root->parents) { + if (ID_IS_LINKED(collection_parent->collection) || + !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) { + continue; + } + BKE_collection_child_remove(bmain, collection_parent->collection, collection_root); + } + break; + } + case ID_OB: { + /* TODO: Not sure how well we can handle this case, when we don't have the collections as + * reference containers... */ + break; + } + default: + break; + } + } } DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); @@ -2385,10 +2403,11 @@ static int make_override_library_exec(bContext *C, wmOperator *op) } /* Set the object to override. */ -static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Object *obact = ED_object_active_context(C); /* Sanity checks. */ @@ -2402,16 +2421,37 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve return make_override_library_exec(C, op); } - if (ID_IS_LINKED(obact)) { - /* Show menu with list of directly linked collections containing the active object. */ - WM_enum_search_invoke(C, op, event); + if (!ID_IS_LINKED(obact)) { + BKE_report(op->reports, RPT_ERROR, "Cannot make library override from a local object"); return OPERATOR_CANCELLED; } - /* Error.. cannot continue. */ - BKE_report(op->reports, - RPT_ERROR, - "Can only make library override for a referenced object or collection"); + int potential_root_collections_num = 0; + uint collection_session_uuid = MAIN_ID_SESSION_UUID_UNSET; + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + /* Only check for directly linked collections. */ + if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0 || + !BKE_view_layer_has_collection(view_layer, collection)) { + continue; + } + if (BKE_collection_has_object_recursive(collection, obact)) { + if (potential_root_collections_num == 0) { + collection_session_uuid = collection->id.session_uuid; + } + potential_root_collections_num++; + } + } + + if (potential_root_collections_num <= 1) { + RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_session_uuid)); + return make_override_library_exec(C, op); + } + + BKE_reportf(op->reports, + RPT_ERROR, + "Too many potential root collections (%d) for the override hierarchy, " + "please use the Outliner instead", + potential_root_collections_num); return OPERATOR_CANCELLED; } @@ -2426,37 +2466,6 @@ static bool make_override_library_poll(bContext *C) !ID_IS_OVERRIDE_LIBRARY(obact)))); } -static const EnumPropertyItem *make_override_collections_of_linked_object_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem item_tmp = {0}, *item = NULL; - int totitem = 0; - - Object *object = ED_object_active_context(C); - Main *bmain = CTX_data_main(C); - - if (!object || !ID_IS_LINKED(object)) { - return DummyRNA_DEFAULT_items; - } - - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - /* Only check for directly linked collections. */ - if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0) { - continue; - } - if (BKE_collection_has_object_recursive(collection, object)) { - item_tmp.identifier = item_tmp.name = collection->id.name + 2; - item_tmp.value = *((int *)&collection->id.session_uuid); - RNA_enum_item_add(&item, &totitem, &item_tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} - void OBJECT_OT_make_override_library(wmOperatorType *ot) { /* identifiers */ @@ -2474,15 +2483,17 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot) /* properties */ PropertyRNA *prop; - prop = RNA_def_enum(ot->srna, - "collection", - DummyRNA_DEFAULT_items, - MAIN_ID_SESSION_UUID_UNSET, - "Override Collection", - "Name of directly linked collection containing the selected object, to make " - "an override from"); - RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + prop = RNA_def_int(ot->srna, + "collection", + MAIN_ID_SESSION_UUID_UNSET, + INT_MIN, + INT_MAX, + "Override Collection", + "Session UUID of the directly linked collection containing the selected " + "object, to make an override from", + INT_MIN, + INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); ot->prop = prop; prop = RNA_def_boolean(ot->srna, diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index ba2efa6e517..8a7138b25ac 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -344,7 +344,7 @@ static void voxel_size_edit_draw(const bContext *C, ARegion *UNUSED(ar), void *a BKE_unit_value_as_string(str, VOXEL_SIZE_EDIT_MAX_STR_LEN, (double)(cd->voxel_size * unit->scale_length), - 4, + -3, B_UNIT_LENGTH, unit, true); @@ -415,15 +415,15 @@ static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *eve } if (event->modifier & KM_CTRL) { - /* Linear mode, enables jumping to any voxel size. */ - d = d * 0.0005f; - } - else { /* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel * sizes. */ /* When the voxel size is slower, it needs more precision. */ d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f; } + else { + /* Linear mode, enables jumping to any voxel size. */ + d = d * 0.0005f; + } if (cd->slow_mode) { cd->voxel_size = cd->slow_voxel_size + d * 0.05f; } @@ -592,7 +592,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev ED_region_tag_redraw(region); const char *status_str = TIP_( - "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel"); + "Move the mouse to change the voxel size. CTRL: Relative Scale, SHIFT: Precision Mode, " + "ENTER/LMB: Confirm Size, ESC/RMB: Cancel"); ED_workspace_status_text(C, status_str); return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 492ece0b40e..9ad36cacc7d 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -4266,7 +4266,6 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) Mesh *me = ob->data; BMEditMesh *em = me->edit_mesh; - float weight_act; int i; if (em) { @@ -4278,18 +4277,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) if (dvert_act == NULL) { return; } - weight_act = BKE_defvert_find_weight(dvert_act, def_nr); 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); - MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr); - if (dw) { - dw->weight = weight_act; + MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - if (me->symmetry & ME_SYMMETRY_X) { - ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); - } + BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr); + + if (me->symmetry & ME_SYMMETRY_X) { + ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); } } } @@ -4306,17 +4302,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) if (dvert_act == NULL) { return; } - weight_act = BKE_defvert_find_weight(dvert_act, def_nr); dv = me->dvert; for (i = 0; i < me->totvert; i++, dv++) { if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) { - MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr); - if (dw) { - dw->weight = weight_act; - if (me->symmetry & ME_SYMMETRY_X) { - ED_mesh_defvert_mirror_update_ob(ob, -1, i); - } + + BKE_defvert_copy_index(dv, def_nr, dvert_act, def_nr); + + if (me->symmetry & ME_SYMMETRY_X) { + ED_mesh_defvert_mirror_update_ob(ob, -1, i); } } } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index ad815f0d998..f58baa0e25c 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -145,6 +145,10 @@ void ED_region_do_listen(wmRegionListenerParams *params) region->type->listener(params); } + LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { + UI_block_views_listen(block, params); + } + LISTBASE_FOREACH (uiList *, list, ®ion->ui_lists) { if (list->type && list->type->listener) { list->type->listener(list, params); @@ -3454,9 +3458,9 @@ ScrArea *ED_area_find_under_cursor(const bContext *C, int spacetype, const int x if (!area) { /* Check all windows except the active one. */ int scr_pos[2]; - wmWindow *r_win = WM_window_find_under_cursor(win, xy, scr_pos); - if (r_win && r_win != win) { - win = r_win; + wmWindow *win_other = WM_window_find_under_cursor(win, xy, scr_pos); + if (win_other && win_other != win) { + win = win_other; screen = WM_window_get_active_screen(win); area = BKE_screen_find_area_xy(screen, spacetype, scr_pos); } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 43c19670a41..08c8c863729 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -626,8 +626,8 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) screen_geom_vertices_scale(win, screen); ED_screen_areas_iter (win, screen, area) { - /* set spacetype and region callbacks, calls init() */ - /* sets subwindows for regions, adds handlers */ + /* Set space-type and region callbacks, calls init() */ + /* Sets sub-windows for regions, adds handlers. */ ED_area_init(wm, win, area); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a922e5aaaee..212fb846b43 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -659,32 +659,6 @@ bool ED_operator_editmball(bContext *C) return false; } -bool ED_operator_mask(bContext *C) -{ - ScrArea *area = CTX_wm_area(C); - if (area && area->spacedata.first) { - switch (area->spacetype) { - case SPACE_CLIP: { - SpaceClip *screen = area->spacedata.first; - return ED_space_clip_check_show_maskedit(screen); - } - case SPACE_SEQ: { - SpaceSeq *sseq = area->spacedata.first; - Scene *scene = CTX_data_scene(C); - return ED_space_sequencer_check_show_maskedit(sseq, scene); - } - case SPACE_IMAGE: { - SpaceImage *sima = area->spacedata.first; - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); - return ED_space_image_check_show_maskedit(sima, obedit); - } - } - } - - return false; -} - bool ED_operator_camera_poll(bContext *C) { struct Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; @@ -1477,7 +1451,7 @@ static int area_close_exec(bContext *C, wmOperator *op) bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); - /* This operator is scriptable, so the area passed could be invalid. */ + /* This operator is script-able, so the area passed could be invalid. */ if (BLI_findindex(&screen->areabase, area) == -1) { BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen"); return OPERATOR_CANCELLED; @@ -2490,6 +2464,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; case EVT_LEFTCTRLKEY: + case EVT_RIGHTCTRLKEY: sd->do_snap = event->val == KM_PRESS; update_factor = true; break; @@ -2722,7 +2697,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event rmd->region->sizey = rmd->region->winy; } - /* now copy to regionmovedata */ + /* Now copy to region-move-data. */ if (ELEM(rmd->edge, AE_LEFT_TO_TOPRIGHT, AE_RIGHT_TO_TOPLEFT)) { rmd->origval = rmd->region->sizex; } diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index d3bf28798c4..34247b4ef75 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -10,6 +10,7 @@ set(INC ../../depsgraph ../../draw ../../functions + ../../geometry ../../gpu ../../imbuf ../../makesdna @@ -33,6 +34,8 @@ set(SRC curves_sculpt_delete.cc curves_sculpt_grow_shrink.cc curves_sculpt_ops.cc + curves_sculpt_selection.cc + curves_sculpt_selection_paint.cc curves_sculpt_snake_hook.cc paint_canvas.cc paint_cursor.c @@ -49,13 +52,12 @@ set(SRC paint_stroke.c paint_utils.c paint_vertex.cc - paint_vertex_color_ops.c - paint_vertex_color_utils.c + paint_vertex_color_ops.cc paint_vertex_proj.c paint_vertex_weight_ops.c paint_vertex_weight_utils.c sculpt.c - sculpt_automasking.c + sculpt_automasking.cc sculpt_boundary.c sculpt_brush_types.c sculpt_cloth.c diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc index d7f4b71d2d0..bac03de77e7 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc @@ -19,11 +19,12 @@ #include "BKE_context.h" #include "BKE_curves.hh" #include "BKE_curves_utils.hh" +#include "BKE_geometry_set.hh" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" +#include "BKE_mesh_sample.hh" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_spline.hh" #include "DNA_brush_enums.h" #include "DNA_brush_types.h" @@ -37,10 +38,12 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "GEO_add_curves_on_mesh.hh" + #include "WM_api.h" /** - * The code below uses a prefix naming convention to indicate the coordinate space: + * The code below uses a suffix naming convention to indicate the coordinate space: * cu: Local space of the curves object that is being edited. * su: Local space of the surface object. * wo: World space. @@ -69,26 +72,13 @@ class AddOperation : public CurvesSculptStrokeOperation { void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override; }; -static void initialize_straight_curve_positions(const float3 &p1, - const float3 &p2, - MutableSpan<float3> r_positions) -{ - const float step = 1.0f / (float)(r_positions.size() - 1); - for (const int i : r_positions.index_range()) { - r_positions[i] = math::interpolate(p1, p2, i * step); - } -} - /** * Utility class that actually executes the update when the stroke is updated. That's useful * because it avoids passing a very large number of parameters between functions. */ struct AddOperationExecutor { AddOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; + CurvesSculptCommonContext ctx_; Object *object_ = nullptr; Curves *curves_id_ = nullptr; @@ -97,60 +87,34 @@ struct AddOperationExecutor { Object *surface_ob_ = nullptr; Mesh *surface_ = nullptr; Span<MLoopTri> surface_looptris_; - Span<float3> corner_normals_su_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; const BrushCurvesSculptSettings *brush_settings_ = nullptr; + int add_amount_; + bool use_front_face_; float brush_radius_re_; float2 brush_pos_re_; - bool use_front_face_; - bool interpolate_length_; - bool interpolate_shape_; - bool interpolate_point_count_; - bool use_interpolation_; - float new_curve_length_; - int add_amount_; - int constant_points_per_curve_; - - /** Various matrices to convert between coordinate spaces. */ - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; - float4x4 world_to_surface_mat_; - float4x4 surface_to_world_mat_; - float4x4 surface_to_curves_mat_; - float4x4 surface_to_curves_normal_mat_; + CurvesSculptTransforms transforms_; BVHTreeFromMesh surface_bvh_; - int tot_old_curves_; - int tot_old_points_; - struct AddedPoints { Vector<float3> positions_cu; Vector<float3> bary_coords; Vector<int> looptri_indices; }; - struct NeighborInfo { - /* Curve index of the neighbor. */ - int index; - /* The weights of all neighbors of a new curve add up to 1. */ - float weight; - }; - static constexpr int max_neighbors = 5; - using NeighborsVector = Vector<NeighborInfo, max_neighbors>; + AddOperationExecutor(const bContext &C) : ctx_(C) + { + } void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension) { self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); @@ -159,43 +123,21 @@ struct AddOperationExecutor { return; } - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); surface_ob_ = curves_id_->surface; surface_ = static_cast<Mesh *>(surface_ob_->data); - surface_to_world_mat_ = surface_ob_->obmat; - world_to_surface_mat_ = surface_to_world_mat_.inverted(); - surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_; - surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed(); - - if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) { - BKE_mesh_calc_normals_split(surface_); - } - corner_normals_su_ = { - reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)), - surface_->totloop}; - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); brush_settings_ = brush_->curves_sculpt_settings; - brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension); + brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension); brush_pos_re_ = stroke_extension.mouse_position; use_front_face_ = brush_->flag & BRUSH_FRONTFACE; const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>( brush_->falloff_shape); add_amount_ = std::max(0, brush_settings_->add_amount); - constant_points_per_curve_ = std::max(2, brush_settings_->points_per_curve); - interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH; - interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE; - interpolate_point_count_ = brush_settings_->flag & - BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT; - use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_; - new_curve_length_ = brush_settings_->curve_length; - - tot_old_curves_ = curves_->curves_num(); - tot_old_points_ = curves_->points_num(); if (add_amount_ == 0) { return; @@ -231,42 +173,56 @@ struct AddOperationExecutor { return; } - Array<NeighborsVector> neighbors_per_curve; - if (use_interpolation_) { - this->ensure_curve_roots_kdtree(); - neighbors_per_curve = this->find_curve_neighbors(added_points); + /* Find UV map. */ + VArray_Span<float2> surface_uv_map; + if (curves_id_->surface_uv_map != nullptr) { + MeshComponent surface_component; + surface_component.replace(surface_, GeometryOwnershipType::ReadOnly); + surface_uv_map = surface_component + .attribute_try_get_for_read(curves_id_->surface_uv_map, + ATTR_DOMAIN_CORNER) + .typed<float2>(); } - /* Resize to add the new curves, building the offsets in the array owned by the curves. */ - const int tot_added_curves = added_points.bary_coords.size(); - curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves); - if (interpolate_point_count_) { - this->initialize_curve_offsets_with_interpolation(neighbors_per_curve); - } - else { - this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_); + /* Find normals. */ + if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) { + BKE_mesh_calc_normals_split(surface_); } + const Span<float3> corner_normals_su = { + reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)), + surface_->totloop}; - /* Resize to add the correct point count calculated as part of building the offsets. */ - curves_->resize(curves_->offsets().last(), curves_->curves_num()); - - this->initialize_attributes(added_points, neighbors_per_curve); + geometry::AddCurvesOnMeshInputs add_inputs; + add_inputs.root_positions_cu = added_points.positions_cu; + add_inputs.bary_coords = added_points.bary_coords; + add_inputs.looptri_indices = added_points.looptri_indices; + add_inputs.interpolate_length = brush_settings_->flag & + BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH; + add_inputs.interpolate_shape = brush_settings_->flag & + BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE; + add_inputs.interpolate_point_count = brush_settings_->flag & + BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT; + add_inputs.fallback_curve_length = brush_settings_->curve_length; + add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve); + add_inputs.surface = surface_; + add_inputs.surface_bvh = &surface_bvh_; + add_inputs.surface_looptris = surface_looptris_; + add_inputs.surface_uv_map = surface_uv_map; + add_inputs.corner_normals_su = corner_normals_su; + add_inputs.curves_to_surface_mat = transforms_.curves_to_surface; + add_inputs.surface_to_curves_normal_mat = transforms_.surface_to_curves_normal; + + if (add_inputs.interpolate_length || add_inputs.interpolate_shape || + add_inputs.interpolate_point_count) { + this->ensure_curve_roots_kdtree(); + add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_; + } - curves_->update_curve_types(); + geometry::add_curves_on_mesh(*curves_, add_inputs); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); - } - - float3 get_bary_coords(const Mesh &mesh, const MLoopTri &looptri, const float3 position) const - { - const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co; - const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co; - const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co; - float3 bary_coords; - interp_weights_tri_v3(bary_coords, v0, v1, v2, position); - return bary_coords; + ED_region_tag_redraw(ctx_.region); } /** @@ -276,16 +232,16 @@ struct AddOperationExecutor { { float3 ray_start_wo, ray_end_wo; ED_view3d_win_to_segment_clipped( - depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true); - const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo; - const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo; + ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true); + const float3 ray_start_cu = transforms_.world_to_curves * ray_start_wo; + const float3 ray_end_cu = transforms_.world_to_curves * ray_end_wo; const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); for (const float4x4 &brush_transform : symmetry_brush_transforms) { - this->sample_in_center( - r_added_points, brush_transform * ray_start_su, brush_transform * ray_end_su); + const float4x4 transform = transforms_.curves_to_surface * brush_transform; + this->sample_in_center(r_added_points, transform * ray_start_cu, transform * ray_end_cu); } } @@ -312,10 +268,10 @@ struct AddOperationExecutor { const int looptri_index = ray_hit.index; const float3 brush_pos_su = ray_hit.co; - const float3 bary_coords = this->get_bary_coords( + const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle( *surface_, surface_looptris_[looptri_index], brush_pos_su); - const float3 brush_pos_cu = surface_to_curves_mat_ * brush_pos_su; + const float3 brush_pos_cu = transforms_.surface_to_curves * brush_pos_su; r_added_points.positions_cu.append(brush_pos_cu); r_added_points.bary_coords.append(bary_coords); @@ -339,57 +295,37 @@ struct AddOperationExecutor { const float4x4 &brush_transform) { const int old_amount = r_added_points.bary_coords.size(); - const int max_iterations = std::max(100'000, add_amount_ * 10); + const int max_iterations = 100; int current_iteration = 0; while (r_added_points.bary_coords.size() < old_amount + add_amount_) { if (current_iteration++ >= max_iterations) { break; } - - const float r = brush_radius_re_ * std::sqrt(rng.get_float()); - const float angle = rng.get_float() * 2.0f * M_PI; - const float2 pos_re = brush_pos_re_ + r * float2(std::cos(angle), std::sin(angle)); - - float3 ray_start_wo, ray_end_wo; - ED_view3d_win_to_segment_clipped( - depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true); - const float3 ray_start_su = brush_transform * (world_to_surface_mat_ * ray_start_wo); - const float3 ray_end_su = brush_transform * (world_to_surface_mat_ * ray_end_wo); - const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su); - - BVHTreeRayHit ray_hit; - ray_hit.dist = FLT_MAX; - ray_hit.index = -1; - BLI_bvhtree_ray_cast(surface_bvh_.tree, - ray_start_su, - ray_direction_su, - 0.0f, - &ray_hit, - surface_bvh_.raycast_callback, - &surface_bvh_); - - if (ray_hit.index == -1) { - continue; - } - - if (use_front_face_) { - const float3 normal_su = ray_hit.no; - if (math::dot(ray_direction_su, normal_su) >= 0.0f) { - continue; - } + const int missing_amount = add_amount_ + old_amount - r_added_points.bary_coords.size(); + const int new_points = bke::mesh_surface_sample::sample_surface_points_projected( + rng, + *surface_, + surface_bvh_, + brush_pos_re_, + brush_radius_re_, + [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) { + float3 start_wo, end_wo; + ED_view3d_win_to_segment_clipped( + ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true); + const float3 start_cu = brush_transform * (transforms_.world_to_curves * start_wo); + const float3 end_cu = brush_transform * (transforms_.world_to_curves * end_wo); + r_start_su = transforms_.curves_to_surface * start_cu; + r_end_su = transforms_.curves_to_surface * end_cu; + }, + use_front_face_, + add_amount_, + missing_amount, + r_added_points.bary_coords, + r_added_points.looptri_indices, + r_added_points.positions_cu); + for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) { + pos = transforms_.surface_to_curves * pos; } - - const int looptri_index = ray_hit.index; - const float3 pos_su = ray_hit.co; - - const float3 bary_coords = this->get_bary_coords( - *surface_, surface_looptris_[looptri_index], pos_su); - - const float3 pos_cu = surface_to_curves_mat_ * pos_su; - - r_added_points.positions_cu.append(pos_cu); - r_added_points.bary_coords.append(bary_coords); - r_added_points.looptri_indices.append(looptri_index); } } @@ -398,66 +334,47 @@ struct AddOperationExecutor { */ void sample_spherical_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points) { - /* Find ray that starts in the center of the brush. */ - float3 brush_ray_start_wo, brush_ray_end_wo; - ED_view3d_win_to_segment_clipped( - depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true); - const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo; - const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo; - - /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius - * in 3D. */ - float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo; - ED_view3d_win_to_segment_clipped(depsgraph_, - region_, - v3d_, - brush_pos_re_ + float2(brush_radius_re_, 0), - brush_radius_ray_start_wo, - brush_radius_ray_end_wo, + const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + transforms_, + surface_bvh_, + brush_pos_re_, + brush_radius_re_); + if (!brush_3d.has_value()) { + return; + } + + float3 view_ray_start_wo, view_ray_end_wo; + ED_view3d_win_to_segment_clipped(ctx_.depsgraph, + ctx_.region, + ctx_.v3d, + brush_pos_re_, + view_ray_start_wo, + view_ray_end_wo, true); - const float3 brush_radius_ray_start_su = world_to_surface_mat_ * brush_radius_ray_start_wo; - const float3 brush_radius_ray_end_su = world_to_surface_mat_ * brush_radius_ray_end_wo; + const float3 view_direction_su = math::normalize( + transforms_.world_to_surface * view_ray_end_wo - + transforms_.world_to_surface * view_ray_start_wo); const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); for (const float4x4 &brush_transform : symmetry_brush_transforms) { - this->sample_spherical(rng, - r_added_points, - brush_transform * brush_ray_start_su, - brush_transform * brush_ray_end_su, - brush_transform * brush_radius_ray_start_su, - brush_transform * brush_radius_ray_end_su); + const float4x4 transform = transforms_.curves_to_surface * brush_transform; + const float3 brush_pos_su = transform * brush_3d->position_cu; + const float brush_radius_su = transform_brush_radius( + transform, brush_3d->position_cu, brush_3d->radius_cu); + this->sample_spherical( + rng, r_added_points, brush_pos_su, brush_radius_su, view_direction_su); } } void sample_spherical(RandomNumberGenerator &rng, AddedPoints &r_added_points, - const float3 &brush_ray_start_su, - const float3 &brush_ray_end_su, - const float3 &brush_radius_ray_start_su, - const float3 &brush_radius_ray_end_su) + const float3 &brush_pos_su, + const float brush_radius_su, + const float3 &view_direction_su) { - const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su); - - BVHTreeRayHit ray_hit; - ray_hit.dist = FLT_MAX; - ray_hit.index = -1; - BLI_bvhtree_ray_cast(surface_bvh_.tree, - brush_ray_start_su, - brush_ray_direction_su, - 0.0f, - &ray_hit, - surface_bvh_.raycast_callback, - &surface_bvh_); - - if (ray_hit.index == -1) { - return; - } - - /* Compute brush radius. */ - const float3 brush_pos_su = ray_hit.co; - const float brush_radius_su = dist_to_line_v3( - brush_pos_su, brush_radius_ray_start_su, brush_radius_ray_end_su); const float brush_radius_sq_su = pow2f(brush_radius_su); /* Find surface triangles within brush radius. */ @@ -474,7 +391,7 @@ struct AddOperationExecutor { const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co; float3 normal_su; normal_tri_v3(normal_su, v0_su, v1_su, v2_su); - if (math::dot(normal_su, brush_ray_direction_su) >= 0.0f) { + if (math::dot(normal_su, view_direction_su) >= 0.0f) { return; } looptri_indices.append(index); @@ -496,9 +413,6 @@ struct AddOperationExecutor { const float brush_plane_area_su = M_PI * brush_radius_sq_su; const float approximate_density_su = add_amount_ / brush_plane_area_su; - /* Used for switching between two triangle sampling strategies. */ - const float area_threshold = brush_plane_area_su; - /* Usually one or two iterations should be enough. */ const int max_iterations = 5; int current_iteration = 0; @@ -508,78 +422,18 @@ struct AddOperationExecutor { if (current_iteration++ >= max_iterations) { break; } - - for (const int looptri_index : looptri_indices) { - const MLoopTri &looptri = surface_looptris_[looptri_index]; - - const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co; - const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co; - const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co; - - const float looptri_area_su = area_tri_v3(v0_su, v1_su, v2_su); - - if (looptri_area_su < area_threshold) { - /* The triangle is small compared to the brush radius. Sample by generating random - * barycentric coordinates. */ - const int amount = rng.round_probabilistic(approximate_density_su * looptri_area_su); - for ([[maybe_unused]] const int i : IndexRange(amount)) { - const float3 bary_coord = rng.get_barycentric_coordinates(); - const float3 point_pos_su = attribute_math::mix3(bary_coord, v0_su, v1_su, v2_su); - const float distance_to_brush_sq_su = math::distance_squared(point_pos_su, - brush_pos_su); - if (distance_to_brush_sq_su > brush_radius_sq_su) { - continue; - } - - r_added_points.bary_coords.append(bary_coord); - r_added_points.looptri_indices.append(looptri_index); - r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su); - } - } - else { - /* The triangle is large compared to the brush radius. Sample by generating random points - * on the triangle plane within the brush radius. */ - float3 normal_su; - normal_tri_v3(normal_su, v0_su, v1_su, v2_su); - - float3 brush_pos_proj_su = brush_pos_su; - project_v3_plane(brush_pos_proj_su, normal_su, v0_su); - - const float proj_distance_sq_su = math::distance_squared(brush_pos_proj_su, - brush_pos_su); - const float brush_radius_factor_sq = 1.0f - - std::min(1.0f, - proj_distance_sq_su / brush_radius_sq_su); - const float radius_proj_sq_su = brush_radius_sq_su * brush_radius_factor_sq; - const float radius_proj_su = std::sqrt(radius_proj_sq_su); - const float circle_area_su = M_PI * radius_proj_su; - - const int amount = rng.round_probabilistic(approximate_density_su * circle_area_su); - - const float3 axis_1_su = math::normalize(v1_su - v0_su) * radius_proj_su; - const float3 axis_2_su = math::normalize(math::cross( - axis_1_su, math::cross(axis_1_su, v2_su - v0_su))) * - radius_proj_su; - - for ([[maybe_unused]] const int i : IndexRange(amount)) { - const float r = std::sqrt(rng.get_float()); - const float angle = rng.get_float() * 2.0f * M_PI; - const float x = r * std::cos(angle); - const float y = r * std::sin(angle); - const float3 point_pos_su = brush_pos_proj_su + axis_1_su * x + axis_2_su * y; - if (!isect_point_tri_prism_v3(point_pos_su, v0_su, v1_su, v2_su)) { - /* Sampled point is not in the triangle. */ - continue; - } - - float3 bary_coord; - interp_weights_tri_v3(bary_coord, v0_su, v1_su, v2_su, point_pos_su); - - r_added_points.bary_coords.append(bary_coord); - r_added_points.looptri_indices.append(looptri_index); - r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su); - } - } + const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical( + rng, + *surface_, + looptri_indices, + brush_pos_su, + brush_radius_su, + approximate_density_su, + r_added_points.bary_coords, + r_added_points.looptri_indices, + r_added_points.positions_cu); + for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) { + pos = transforms_.surface_to_curves * pos; } } @@ -604,269 +458,11 @@ struct AddOperationExecutor { BLI_kdtree_3d_balance(self_->curve_roots_kdtree_); } } - - void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve) - { - MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_); - - attribute_math::DefaultMixer<int> mixer{new_offsets}; - threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) { - for (const int i : curves_range) { - if (neighbors_per_curve[i].is_empty()) { - mixer.mix_in(i, constant_points_per_curve_, 1.0f); - } - else { - for (const NeighborInfo &neighbor : neighbors_per_curve[i]) { - const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size(); - mixer.mix_in(i, neighbor_points_num, neighbor.weight); - } - } - } - }); - mixer.finalize(); - - bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_); - } - - void initialize_curve_offsets_without_interpolation(const int points_per_curve) - { - MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_); - int offset = tot_old_points_; - for (const int i : new_offsets.index_range()) { - new_offsets[i] = offset; - offset += points_per_curve; - } - } - - void initialize_attributes(const AddedPoints &added_points, - const Span<NeighborsVector> neighbors_per_curve) - { - Array<float> new_lengths_cu(added_points.bary_coords.size()); - if (interpolate_length_) { - this->interpolate_lengths(neighbors_per_curve, new_lengths_cu); - } - else { - new_lengths_cu.fill(new_curve_length_); - } - - Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points); - this->initialize_surface_attachment(added_points); - - if (interpolate_shape_) { - this->initialize_position_with_interpolation( - added_points, neighbors_per_curve, new_normals_su, new_lengths_cu); - } - else { - this->initialize_position_without_interpolation( - added_points, new_lengths_cu, new_normals_su); - } - } - - Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points) - { - const int tot_added_curves = added_points.bary_coords.size(); - Array<NeighborsVector> neighbors_per_curve(tot_added_curves); - threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) { - for (const int i : range) { - const float3 root_cu = added_points.positions_cu[i]; - std::array<KDTreeNearest_3d, max_neighbors> nearest_n; - const int found_neighbors = BLI_kdtree_3d_find_nearest_n( - self_->curve_roots_kdtree_, root_cu, nearest_n.data(), max_neighbors); - float tot_weight = 0.0f; - for (const int neighbor_i : IndexRange(found_neighbors)) { - KDTreeNearest_3d &nearest = nearest_n[neighbor_i]; - const float weight = 1.0f / std::max(nearest.dist, 0.00001f); - tot_weight += weight; - neighbors_per_curve[i].append({nearest.index, weight}); - } - /* Normalize weights. */ - for (NeighborInfo &neighbor : neighbors_per_curve[i]) { - neighbor.weight /= tot_weight; - } - } - }); - return neighbors_per_curve; - } - - void interpolate_lengths(const Span<NeighborsVector> neighbors_per_curve, - MutableSpan<float> r_lengths) - { - const Span<float3> positions_cu = curves_->positions(); - - threading::parallel_for(r_lengths.index_range(), 128, [&](const IndexRange range) { - for (const int added_curve_i : range) { - const Span<NeighborInfo> neighbors = neighbors_per_curve[added_curve_i]; - float length_sum = 0.0f; - for (const NeighborInfo &neighbor : neighbors) { - const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index); - float neighbor_length = 0.0f; - for (const int segment_i : neighbor_points.drop_back(1)) { - const float3 &p1 = positions_cu[segment_i]; - const float3 &p2 = positions_cu[segment_i + 1]; - neighbor_length += math::distance(p1, p2); - } - length_sum += neighbor.weight * neighbor_length; - } - const float length = neighbors.is_empty() ? new_curve_length_ : length_sum; - r_lengths[added_curve_i] = length; - } - }); - } - - float3 compute_point_normal_su(const int looptri_index, const float3 &bary_coord) - { - const MLoopTri &looptri = surface_looptris_[looptri_index]; - const int l0 = looptri.tri[0]; - const int l1 = looptri.tri[1]; - const int l2 = looptri.tri[2]; - - const float3 &l0_normal_su = corner_normals_su_[l0]; - const float3 &l1_normal_su = corner_normals_su_[l1]; - const float3 &l2_normal_su = corner_normals_su_[l2]; - - const float3 normal_su = math::normalize( - attribute_math::mix3(bary_coord, l0_normal_su, l1_normal_su, l2_normal_su)); - return normal_su; - } - - Array<float3> compute_normals_for_added_curves_su(const AddedPoints &added_points) - { - Array<float3> normals_su(added_points.bary_coords.size()); - threading::parallel_for(normals_su.index_range(), 256, [&](const IndexRange range) { - for (const int i : range) { - const int looptri_index = added_points.looptri_indices[i]; - const float3 &bary_coord = added_points.bary_coords[i]; - normals_su[i] = this->compute_point_normal_su(looptri_index, bary_coord); - } - }); - return normals_su; - } - - void initialize_surface_attachment(const AddedPoints &added_points) - { - MutableSpan<int> surface_triangle_indices = curves_->surface_triangle_indices_for_write(); - MutableSpan<float2> surface_triangle_coords = curves_->surface_triangle_coords_for_write(); - threading::parallel_for( - added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) { - for (const int i : range) { - const int curve_i = tot_old_curves_ + i; - surface_triangle_indices[curve_i] = added_points.looptri_indices[i]; - surface_triangle_coords[curve_i] = float2(added_points.bary_coords[i]); - } - }); - } - - /** - * Initialize new curves so that they are just a straight line in the normal direction. - */ - void initialize_position_without_interpolation(const AddedPoints &added_points, - const Span<float> lengths_cu, - const MutableSpan<float3> normals_su) - { - MutableSpan<float3> positions_cu = curves_->positions_for_write(); - - threading::parallel_for( - added_points.bary_coords.index_range(), 256, [&](const IndexRange range) { - for (const int i : range) { - const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i); - const float3 &root_cu = added_points.positions_cu[i]; - const float length = lengths_cu[i]; - const float3 &normal_su = normals_su[i]; - const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su); - const float3 tip_cu = root_cu + length * normal_cu; - - initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points)); - } - }); - } - - /** - * Use neighboring curves to determine the shape. - */ - void initialize_position_with_interpolation(const AddedPoints &added_points, - const Span<NeighborsVector> neighbors_per_curve, - const Span<float3> new_normals_su, - const Span<float> new_lengths_cu) - { - MutableSpan<float3> positions_cu = curves_->positions_for_write(); - const VArray_Span<int> surface_triangle_indices{curves_->surface_triangle_indices()}; - const Span<float2> surface_triangle_coords = curves_->surface_triangle_coords(); - - threading::parallel_for( - added_points.bary_coords.index_range(), 256, [&](const IndexRange range) { - for (const int i : range) { - const Span<NeighborInfo> neighbors = neighbors_per_curve[i]; - const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i); - - const float length_cu = new_lengths_cu[i]; - const float3 &normal_su = new_normals_su[i]; - const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su); - - const float3 &root_cu = added_points.positions_cu[i]; - - if (neighbors.is_empty()) { - /* If there are no neighbors, just make a straight line. */ - const float3 tip_cu = root_cu + length_cu * normal_cu; - initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points)); - continue; - } - - positions_cu.slice(points).fill(root_cu); - - for (const NeighborInfo &neighbor : neighbors) { - const int neighbor_curve_i = neighbor.index; - const int neighbor_looptri_index = surface_triangle_indices[neighbor_curve_i]; - - float3 neighbor_bary_coord{surface_triangle_coords[neighbor_curve_i]}; - neighbor_bary_coord.z = 1.0f - neighbor_bary_coord.x - neighbor_bary_coord.y; - - const float3 neighbor_normal_su = this->compute_point_normal_su( - neighbor_looptri_index, neighbor_bary_coord); - const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat_ * - neighbor_normal_su); - - /* The rotation matrix used to transform relative coordinates of the neighbor curve - * to the new curve. */ - float normal_rotation_cu[3][3]; - rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu); - - const IndexRange neighbor_points = curves_->points_for_curve(neighbor_curve_i); - const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]]; - - /* Use a temporary #PolySpline, because that's the easiest way to resample an - * existing curve right now. Resampling is necessary if the length of the new curve - * does not match the length of the neighbors or the number of handle points is - * different. */ - PolySpline neighbor_spline; - neighbor_spline.resize(neighbor_points.size()); - neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points)); - neighbor_spline.mark_cache_invalid(); - - const float neighbor_length_cu = neighbor_spline.length(); - const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu); - - const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor; - for (const int j : IndexRange(points.size())) { - const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor( - j * resample_factor); - const float index_factor = lookup.evaluated_index + lookup.factor; - float3 p; - neighbor_spline.sample_with_index_factors<float3>( - neighbor_spline.positions(), {&index_factor, 1}, {&p, 1}); - const float3 relative_coord = p - neighbor_root_cu; - float3 rotated_relative_coord = relative_coord; - mul_m3_v3(normal_rotation_cu, rotated_relative_coord); - positions_cu[points[j]] += neighbor.weight * rotated_relative_coord; - } - } - } - }); - } }; void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - AddOperationExecutor executor; + AddOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc index 92ce6ba3153..1c785fa6452 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc @@ -4,6 +4,7 @@ #include "curves_sculpt_intern.hh" +#include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_curves.hh" @@ -12,7 +13,11 @@ #include "UI_interface.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + #include "BLI_enumerable_thread_specific.hh" +#include "BLI_length_parameterize.hh" #include "BLI_task.hh" /** @@ -249,6 +254,55 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, return brush_3d; } +std::optional<CurvesBrush3D> sample_curves_surface_3d_brush( + const Depsgraph &depsgraph, + const ARegion ®ion, + const View3D &v3d, + const CurvesSculptTransforms &transforms, + const BVHTreeFromMesh &surface_bvh, + const float2 &brush_pos_re, + const float brush_radius_re) +{ + float3 brush_ray_start_wo, brush_ray_end_wo; + ED_view3d_win_to_segment_clipped( + &depsgraph, ®ion, &v3d, brush_pos_re, brush_ray_start_wo, brush_ray_end_wo, true); + const float3 brush_ray_start_su = transforms.world_to_surface * brush_ray_start_wo; + const float3 brush_ray_end_su = transforms.world_to_surface * brush_ray_end_wo; + + const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su); + + BVHTreeRayHit ray_hit; + ray_hit.dist = FLT_MAX; + ray_hit.index = -1; + BLI_bvhtree_ray_cast(surface_bvh.tree, + brush_ray_start_su, + brush_ray_direction_su, + 0.0f, + &ray_hit, + surface_bvh.raycast_callback, + const_cast<void *>(static_cast<const void *>(&surface_bvh))); + if (ray_hit.index == -1) { + return std::nullopt; + } + + float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo; + ED_view3d_win_to_segment_clipped(&depsgraph, + ®ion, + &v3d, + brush_pos_re + float2(brush_radius_re, 0), + brush_radius_ray_start_wo, + brush_radius_ray_end_wo, + true); + const float3 brush_radius_ray_start_cu = transforms.world_to_curves * brush_radius_ray_start_wo; + const float3 brush_radius_ray_end_cu = transforms.world_to_curves * brush_radius_ray_end_wo; + + const float3 brush_pos_su = ray_hit.co; + const float3 brush_pos_cu = transforms.surface_to_curves * brush_pos_su; + const float brush_radius_cu = dist_to_line_v3( + brush_pos_cu, brush_radius_ray_start_cu, brush_radius_ray_end_cu); + return CurvesBrush3D{brush_pos_cu, brush_radius_cu}; +} + Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry) { Vector<float4x4> matrices; @@ -277,4 +331,68 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr return matrices; } +float transform_brush_radius(const float4x4 &transform, + const float3 &brush_position, + const float old_radius) +{ + const float3 offset_position = brush_position + float3(old_radius, 0.0f, 0.0f); + const float3 new_position = transform * brush_position; + const float3 new_offset_position = transform * offset_position; + return math::distance(new_position, new_offset_position); +} + +void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position) +{ + /* Find the accumulated length of each point in the original curve, + * treating it as a poly curve for performance reasons and simplicity. */ + Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false)); + length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths); + const float orig_total_length = orig_lengths.last(); + + /* Find the factor by which the new curve is shorter or longer than the original. */ + const float new_last_segment_length = math::distance(positions.last(1), new_last_position); + const float new_total_length = orig_lengths.last(1) + new_last_segment_length; + const float length_factor = safe_divide(new_total_length, orig_total_length); + + /* Calculate the lengths to sample the original curve with by scaling the original lengths. */ + Array<float> new_lengths(positions.size() - 1); + new_lengths.first() = 0.0f; + for (const int i : new_lengths.index_range().drop_front(1)) { + new_lengths[i] = orig_lengths[i - 1] * length_factor; + } + + Array<int> indices(positions.size() - 1); + Array<float> factors(positions.size() - 1); + length_parameterize::create_samples_from_sorted_lengths( + orig_lengths, new_lengths, false, indices, factors); + + Array<float3> new_positions(positions.size() - 1); + length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions); + positions.drop_back(1).copy_from(new_positions); + positions.last() = new_last_position; +} + +CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C) +{ + this->depsgraph = CTX_data_depsgraph_pointer(&C); + this->scene = CTX_data_scene(&C); + this->region = CTX_wm_region(&C); + this->v3d = CTX_wm_view3d(&C); + this->rv3d = CTX_wm_region_view3d(&C); +} + +CurvesSculptTransforms::CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob) +{ + this->curves_to_world = curves_ob.obmat; + this->world_to_curves = this->curves_to_world.inverted(); + + if (surface_ob != nullptr) { + this->surface_to_world = surface_ob->obmat; + this->world_to_surface = this->surface_to_world.inverted(); + this->surface_to_curves = this->world_to_curves * this->surface_to_world; + this->curves_to_surface = this->world_to_surface * this->curves_to_world; + this->surface_to_curves_normal = this->surface_to_curves.inverted().transposed(); + } +} + } // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc index 1fcab2290e8..541bf9d8253 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc @@ -78,11 +78,7 @@ class CombOperation : public CurvesSculptStrokeOperation { */ struct CombOperationExecutor { CombOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -96,21 +92,19 @@ struct CombOperationExecutor { Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; - const Object *surface_ob_ = nullptr; - const Mesh *surface_ = nullptr; - Span<MLoopTri> surface_looptris_; + VArray<float> point_factors_; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; float2 brush_pos_prev_re_; float2 brush_pos_re_; float2 brush_pos_diff_re_; - float brush_pos_diff_length_re_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; - float4x4 surface_to_world_mat_; - float4x4 world_to_surface_mat_; + CurvesSculptTransforms transforms_; - BVHTreeFromMesh surface_bvh_; + CombOperationExecutor(const bContext &C) : ctx_(C) + { + } void execute(CombOperation &self, const bContext &C, const StrokeExtension &stroke_extension) { @@ -118,21 +112,13 @@ struct CombOperationExecutor { BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; }); - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); - - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape); @@ -142,26 +128,14 @@ struct CombOperationExecutor { return; } + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); + + point_factors_ = get_point_selection(*curves_id_); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + brush_pos_prev_re_ = self_->brush_pos_last_re_; brush_pos_re_ = stroke_extension.mouse_position; brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_; - brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_); - - surface_ob_ = curves_id_->surface; - if (surface_ob_ != nullptr) { - surface_ = static_cast<const Mesh *>(surface_ob_->data); - surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_), - BKE_mesh_runtime_looptri_len(surface_)}; - surface_to_world_mat_ = surface_ob_->obmat; - world_to_surface_mat_ = surface_to_world_mat_.inverted(); - BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2); - } - - BLI_SCOPED_DEFER([&]() { - if (surface_ob_ != nullptr) { - free_bvhtree_from_mesh(&surface_bvh_); - } - }); if (stroke_extension.is_first) { if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { @@ -189,7 +163,7 @@ struct CombOperationExecutor { curves_->tag_positions_changed(); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } /** @@ -212,14 +186,14 @@ struct CombOperationExecutor { MutableSpan<float3> positions_cu = curves_->positions_for_write(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_sq_re = pow2f(brush_radius_re); - threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) { + threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) { Vector<int> &local_changed_curves = r_changed_curves.local(); - for (const int curve_i : curves_range) { + for (const int curve_i : curve_selection_.slice(range)) { bool curve_changed = false; const IndexRange points = curves_->points_for_curve(curve_i); for (const int point_i : points.drop_front(1)) { @@ -227,7 +201,7 @@ struct CombOperationExecutor { /* Find the position of the point in screen space. */ float2 old_pos_re; - ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values); const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2( old_pos_re, brush_pos_prev_re_, brush_pos_re_); @@ -241,15 +215,19 @@ struct CombOperationExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, distance_to_brush_re, brush_radius_re); /* Combine the falloff and brush strength. */ - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * point_factors_[point_i]; - /* Offset the old point position in screen space and transform it back into 3D space. */ + /* Offset the old point position in screen space and transform it back into 3D space. + */ const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight; float3 new_position_wo; - ED_view3d_win_to_3d( - v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo); + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * old_pos_cu, + new_position_re, + new_position_wo); const float3 new_position_cu = brush_transform * - (world_to_curves_mat_ * new_position_wo); + (transforms_.world_to_curves * new_position_wo); positions_cu[point_i] = new_position_cu; curve_changed = true; @@ -267,21 +245,21 @@ struct CombOperationExecutor { void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves) { float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); float3 brush_start_wo, brush_end_wo; - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_prev_re_, brush_start_wo); - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_end_wo); - const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo; - const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo; + const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo; + const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo; const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; @@ -304,9 +282,9 @@ struct CombOperationExecutor { const float brush_radius_sq_cu = pow2f(brush_radius_cu); const float3 brush_diff_cu = brush_end_cu - brush_start_cu; - threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) { + threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) { Vector<int> &local_changed_curves = r_changed_curves.local(); - for (const int curve_i : curves_range) { + for (const int curve_i : curve_selection_.slice(range)) { bool curve_changed = false; const IndexRange points = curves_->points_for_curve(curve_i); for (const int point_i : points.drop_front(1)) { @@ -326,7 +304,7 @@ struct CombOperationExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, distance_to_brush_cu, brush_radius_cu); /* Combine the falloff and brush strength. */ - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * point_factors_[point_i]; /* Update the point position. */ positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu; @@ -344,8 +322,13 @@ struct CombOperationExecutor { */ void initialize_spherical_brush_reference_point() { - std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_); + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); if (brush_3d.has_value()) { self_->brush_3d_ = *brush_3d; } @@ -399,7 +382,7 @@ struct CombOperationExecutor { void CombOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - CombOperationExecutor executor; + CombOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc index 323e99df099..eab7dabcd22 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc @@ -60,16 +60,15 @@ class DeleteOperation : public CurvesSculptStrokeOperation { struct DeleteOperationExecutor { DeleteOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; Object *object_ = nullptr; Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; + const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; float brush_radius_base_re_; @@ -77,32 +76,31 @@ struct DeleteOperationExecutor { float2 brush_pos_re_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + CurvesSculptTransforms transforms_; - void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension) + DeleteOperationExecutor(const bContext &C) : ctx_(C) { + } + void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension) + { self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + selected_curve_indices_.clear(); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); brush_pos_re_ = stroke_extension.mouse_position; - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>( brush_->falloff_shape); @@ -134,7 +132,7 @@ struct DeleteOperationExecutor { DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } void delete_projected_with_symmetry(MutableSpan<bool> curves_to_delete) @@ -151,20 +149,20 @@ struct DeleteOperationExecutor { const float4x4 brush_transform_inv = brush_transform.inverted(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); Span<float3> positions_cu = curves_->positions(); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_sq_re = pow2f(brush_radius_re); - threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) { - for (const int curve_i : curve_range) { + threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) { + for (const int curve_i : curve_selection_.slice(range)) { const IndexRange points = curves_->points_for_curve(curve_i); if (points.size() == 1) { const float3 pos_cu = brush_transform_inv * positions_cu[points.first()]; float2 pos_re; - ED_view3d_project_float_v2_m4(region_, pos_cu, pos_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values); if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) { curves_to_delete[curve_i] = true; @@ -177,8 +175,8 @@ struct DeleteOperationExecutor { const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1]; float2 pos1_re, pos2_re; - ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values); - ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values); const float dist_sq_re = dist_squared_to_line_segment_v2( brush_pos_re_, pos1_re, pos2_re); @@ -194,15 +192,15 @@ struct DeleteOperationExecutor { void delete_spherical_with_symmetry(MutableSpan<bool> curves_to_delete) { float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); float3 brush_wo; - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_wo); - const float3 brush_cu = world_to_curves_mat_ * brush_wo; + const float3 brush_cu = transforms_.world_to_curves * brush_wo; const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); @@ -219,8 +217,8 @@ struct DeleteOperationExecutor { const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; const float brush_radius_sq_cu = pow2f(brush_radius_cu); - threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) { - for (const int curve_i : curve_range) { + threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) { + for (const int curve_i : curve_selection_.slice(range)) { const IndexRange points = curves_->points_for_curve(curve_i); if (points.size() == 1) { @@ -249,8 +247,13 @@ struct DeleteOperationExecutor { void initialize_spherical_brush_reference_point() { - std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_); + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); if (brush_3d.has_value()) { self_->brush_3d_ = *brush_3d; } @@ -260,7 +263,7 @@ struct DeleteOperationExecutor { void DeleteOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - DeleteOperationExecutor executor; + DeleteOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc index 25eb8041f4c..cf893f09fc6 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc @@ -151,50 +151,10 @@ class ExtrapolateCurvesEffect : public CurvesEffect { const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point); const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu; - this->move_last_point_and_resample(positions_cu, curve_points, new_last_pos_cu); + move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu); } }); } - - void move_last_point_and_resample(MutableSpan<float3> positions, - const IndexRange curve_points, - const float3 &new_last_point_position) const - { - Vector<float> old_lengths; - old_lengths.append(0.0f); - /* Used to (1) normalize the segment sizes over time and (2) support making zero-length - * segments */ - const float extra_length = 0.001f; - for (const int segment_i : IndexRange(curve_points.size() - 1)) { - const float3 &p1 = positions[curve_points[segment_i]]; - const float3 &p2 = positions[curve_points[segment_i] + 1]; - const float length = math::distance(p1, p2); - old_lengths.append(old_lengths.last() + length + extra_length); - } - Vector<float> point_factors; - for (float &old_length : old_lengths) { - point_factors.append(old_length / old_lengths.last()); - } - - PolySpline new_spline; - new_spline.resize(curve_points.size()); - MutableSpan<float3> new_spline_positions = new_spline.positions(); - for (const int i : IndexRange(curve_points.size() - 1)) { - new_spline_positions[i] = positions[curve_points[i]]; - } - new_spline_positions.last() = new_last_point_position; - new_spline.mark_cache_invalid(); - - for (const int i : IndexRange(curve_points.size())) { - const float factor = point_factors[i]; - const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor); - const float index_factor = lookup.evaluated_index + lookup.factor; - float3 p; - new_spline.sample_with_index_factors<float3>( - new_spline_positions, {&index_factor, 1}, {&p, 1}); - positions[curve_points[i]] = p; - } - } }; /** @@ -270,16 +230,16 @@ class CurvesEffectOperation : public CurvesSculptStrokeOperation { */ struct CurvesEffectOperationExecutor { CurvesEffectOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; Object *object_ = nullptr; Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; + VArray<float> curve_selection_factors_; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; + const Brush *brush_ = nullptr; float brush_radius_base_re_; float brush_radius_factor_; @@ -287,8 +247,7 @@ struct CurvesEffectOperationExecutor { eBrushFalloffShape falloff_shape_; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + CurvesSculptTransforms transforms_; float2 brush_pos_start_re_; float2 brush_pos_end_re_; @@ -298,6 +257,10 @@ struct CurvesEffectOperationExecutor { Vector<float> move_distances_cu; }; + CurvesEffectOperationExecutor(const bContext &C) : ctx_(C) + { + } + void execute(CurvesEffectOperation &self, const bContext &C, const StrokeExtension &stroke_extension) @@ -305,12 +268,7 @@ struct CurvesEffectOperationExecutor { BLI_SCOPED_DEFER([&]() { self.last_mouse_position_ = stroke_extension.mouse_position; }); self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); @@ -318,18 +276,20 @@ struct CurvesEffectOperationExecutor { return; } - const CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt; + curve_selection_factors_ = get_curves_selection(*curves_id_); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + + const CurvesSculpt &curves_sculpt = *ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape); - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); brush_pos_start_re_ = self.last_mouse_position_; brush_pos_end_re_ = stroke_extension.mouse_position; @@ -337,10 +297,10 @@ struct CurvesEffectOperationExecutor { if (stroke_extension.is_first) { if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { if (std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, - *region_, - *v3d_, - *rv3d_, + *ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, *object_, stroke_extension.mouse_position, brush_radius_base_re_)) { @@ -369,7 +329,7 @@ struct CurvesEffectOperationExecutor { curves_->tag_positions_changed(); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } void gather_influences_projected( @@ -378,7 +338,7 @@ struct CurvesEffectOperationExecutor { const Span<float3> positions_cu = curves_->positions(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); @@ -396,6 +356,8 @@ struct CurvesEffectOperationExecutor { for (const int curve_i : curves_range) { const IndexRange points = curves_->points_for_curve(curve_i); + const float curve_selection_factor = curve_selection_factors_[curve_i]; + float max_move_distance_cu = 0.0f; for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) { for (const int segment_i : points.drop_back(1)) { @@ -403,8 +365,8 @@ struct CurvesEffectOperationExecutor { const float3 p2_cu = brush_transform_inv * positions_cu[segment_i + 1]; float2 p1_re, p2_re; - ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values); - ED_view3d_project_float_v2_m4(region_, p2_cu, p2_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.values); float2 closest_on_brush_re; float2 closest_on_segment_re; @@ -426,24 +388,24 @@ struct CurvesEffectOperationExecutor { const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re); const float radius_falloff = BKE_brush_curve_strength( brush_, dist_to_brush_re, brush_radius_re); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_selection_factor; const float3 closest_on_segment_cu = math::interpolate( p1_cu, p2_cu, lambda_on_segment); float3 brush_start_pos_wo, brush_end_pos_wo; - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * closest_on_segment_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * closest_on_segment_cu, brush_pos_start_re_, brush_start_pos_wo); - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * closest_on_segment_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * closest_on_segment_cu, brush_pos_end_re_, brush_end_pos_wo); - const float3 brush_start_pos_cu = world_to_curves_mat_ * brush_start_pos_wo; - const float3 brush_end_pos_cu = world_to_curves_mat_ * brush_end_pos_wo; + const float3 brush_start_pos_cu = transforms_.world_to_curves * brush_start_pos_wo; + const float3 brush_end_pos_cu = transforms_.world_to_curves * brush_end_pos_wo; const float move_distance_cu = weight * math::distance(brush_start_pos_cu, brush_end_pos_cu); @@ -464,18 +426,18 @@ struct CurvesEffectOperationExecutor { const Span<float3> positions_cu = curves_->positions(); float3 brush_pos_start_wo, brush_pos_end_wo; - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_start_re_, brush_pos_start_wo); - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_end_re_, brush_pos_end_wo); - const float3 brush_pos_start_cu = world_to_curves_mat_ * brush_pos_start_wo; - const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo; + const float3 brush_pos_start_cu = transforms_.world_to_curves * brush_pos_start_wo; + const float3 brush_pos_end_cu = transforms_.world_to_curves * brush_pos_end_wo; const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu; const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu); const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; @@ -491,6 +453,9 @@ struct CurvesEffectOperationExecutor { const IndexRange points = curves_->points_for_curve(curve_i); float max_move_distance_cu = 0.0f; + + const float curve_selection_factor = curve_selection_factors_[curve_i]; + for (const float4x4 &brush_transform : symmetry_brush_transforms) { const float3 brush_pos_start_transformed_cu = brush_transform * brush_pos_start_cu; const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu; @@ -517,7 +482,7 @@ struct CurvesEffectOperationExecutor { const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu); const float radius_falloff = BKE_brush_curve_strength( brush_, dist_to_brush_cu, brush_radius_cu); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_selection_factor; const float move_distance_cu = weight * brush_pos_diff_length_cu; max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu); @@ -535,7 +500,7 @@ struct CurvesEffectOperationExecutor { void CurvesEffectOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - CurvesEffectOperationExecutor executor; + CurvesEffectOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh index 842de234761..ad3871bee45 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh @@ -8,7 +8,10 @@ #include "paint_intern.h" #include "BLI_math_vector.hh" +#include "BLI_vector.hh" +#include "BLI_virtual_array.hh" +#include "BKE_attribute.h" #include "BKE_curves.hh" struct ARegion; @@ -18,6 +21,7 @@ struct View3D; struct Object; struct Brush; struct Scene; +struct BVHTreeFromMesh; namespace blender::ed::sculpt_paint { @@ -55,6 +59,15 @@ std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation(); std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation(); std::unique_ptr<CurvesSculptStrokeOperation> new_grow_shrink_operation( const BrushStrokeMode brush_mode, const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation( + const BrushStrokeMode brush_mode, const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_pinch_operation(const BrushStrokeMode brush_mode, + const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation(); +std::unique_ptr<CurvesSculptStrokeOperation> new_puff_operation(); +std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation( + const BrushStrokeMode brush_mode, const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_slide_operation(); struct CurvesBrush3D { float3 position_cu; @@ -74,4 +87,59 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, Vector<float4x4> get_symmetry_brush_transforms(eCurvesSymmetryType symmetry); +/** + * Get the floating point selection on the curve domain, averaged from points if necessary. + */ +VArray<float> get_curves_selection(const Curves &curves_id); + +/** + * Get the floating point selection on the curve domain, copied from curves if necessary. + */ +VArray<float> get_point_selection(const Curves &curves_id); + +/** + * Find curves that have any point selected (a selection factor greater than zero), + * or curves that have their own selection factor greater than zero. + */ +IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices); + +void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position); + +class CurvesSculptCommonContext { + public: + const Depsgraph *depsgraph = nullptr; + const Scene *scene = nullptr; + ARegion *region = nullptr; + const View3D *v3d = nullptr; + const RegionView3D *rv3d = nullptr; + + CurvesSculptCommonContext(const bContext &C); +}; + +struct CurvesSculptTransforms { + float4x4 curves_to_world; + float4x4 curves_to_surface; + float4x4 world_to_curves; + float4x4 world_to_surface; + float4x4 surface_to_world; + float4x4 surface_to_curves; + float4x4 surface_to_curves_normal; + + CurvesSculptTransforms() = default; + CurvesSculptTransforms(const Object &curves_ob, const Object *surface_ob); +}; + +std::optional<CurvesBrush3D> sample_curves_surface_3d_brush( + const Depsgraph &depsgraph, + const ARegion ®ion, + const View3D &v3d, + const CurvesSculptTransforms &transforms, + const BVHTreeFromMesh &surface_bvh, + const float2 &brush_pos_re, + const float brush_radius_re); + +float transform_brush_radius(const float4x4 &transform, + const float3 &brush_position, + const float old_radius); + } // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc index 15d0f73592d..5d6ffa67005 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc @@ -18,6 +18,7 @@ #include "WM_toolsystem.h" #include "ED_curves_sculpt.h" +#include "ED_image.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -49,7 +50,7 @@ bool CURVES_SCULPT_mode_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + const Object *ob = CTX_data_active_object(C); return ob && ob->mode & OB_MODE_SCULPT_CURVES; } @@ -109,9 +110,9 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte { const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode")); - Scene &scene = *CTX_data_scene(&C); - CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt; - Brush &brush = *BKE_paint_brush(&curves_sculpt.paint); + const Scene &scene = *CTX_data_scene(&C); + const CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt; + const Brush &brush = *BKE_paint_brush_for_read(&curves_sculpt.paint); switch (brush.curves_sculpt_tool) { case CURVES_SCULPT_TOOL_COMB: return new_comb_operation(); @@ -123,6 +124,8 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte return new_add_operation(C, op.reports); case CURVES_SCULPT_TOOL_GROW_SHRINK: return new_grow_shrink_operation(mode, C); + case CURVES_SCULPT_TOOL_SELECTION_PAINT: + return new_selection_paint_operation(mode, C); } BLI_assert_unreachable(); return {}; @@ -180,8 +183,8 @@ static void stroke_done(const bContext *C, PaintStroke *stroke) static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *brush = BKE_paint_brush(paint); + const Paint *paint = BKE_paint_get_active_from_context(C); + const Brush *brush = BKE_paint_brush_for_read(paint); if (brush == nullptr) { return OPERATOR_CANCELLED; } @@ -250,7 +253,7 @@ static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot) static bool curves_sculptmode_toggle_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + const Object *ob = CTX_data_active_object(C); if (ob == nullptr) { return false; } @@ -269,7 +272,7 @@ static void curves_sculptmode_enter(bContext *C) ob->mode = OB_MODE_SCULPT_CURVES; - paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d); + ED_paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d); /* Update for mode change. */ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc new file mode 100644 index 00000000000..f620fed5761 --- /dev/null +++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_index_mask_ops.hh" + +#include "BKE_curves.hh" + +#include "curves_sculpt_intern.hh" + +namespace blender::ed::sculpt_paint { + +static VArray<float> get_curves_selection(const CurvesGeometry &curves, const eAttrDomain domain) +{ + switch (domain) { + case ATTR_DOMAIN_CURVE: + return curves.selection_curve_float(); + case ATTR_DOMAIN_POINT: + return curves.adapt_domain( + curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + default: + BLI_assert_unreachable(); + return {}; + } +} + +VArray<float> get_curves_selection(const Curves &curves_id) +{ + if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) { + return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).curves_num()); + } + return get_curves_selection(CurvesGeometry::wrap(curves_id.geometry), + eAttrDomain(curves_id.selection_domain)); +} + +static VArray<float> get_point_selection(const CurvesGeometry &curves, const eAttrDomain domain) +{ + switch (domain) { + case ATTR_DOMAIN_CURVE: + return curves.adapt_domain( + curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); + case ATTR_DOMAIN_POINT: + return curves.selection_point_float(); + default: + BLI_assert_unreachable(); + return {}; + } +} + +VArray<float> get_point_selection(const Curves &curves_id) +{ + if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) { + return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).points_num()); + } + return get_point_selection(CurvesGeometry::wrap(curves_id.geometry), + eAttrDomain(curves_id.selection_domain)); +} + +static IndexMask retrieve_selected_curves(const CurvesGeometry &curves, + const eAttrDomain domain, + Vector<int64_t> &r_indices) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: { + const VArray<float> selection = curves.selection_point_float(); + if (selection.is_single()) { + return selection.get_internal_single() == 0.0f ? IndexMask(0) : + IndexMask(curves.curves_num()); + } + return index_mask_ops::find_indices_based_on_predicate( + curves.curves_range(), 512, r_indices, [&](const int curve_i) { + for (const int i : curves.points_for_curve(curve_i)) { + if (selection[i] > 0.0f) { + return true; + } + } + return false; + }); + } + case ATTR_DOMAIN_CURVE: { + const VArray<float> selection = curves.selection_curve_float(); + if (selection.is_single()) { + return selection.get_internal_single() == 0.0f ? IndexMask(0) : + IndexMask(curves.curves_num()); + } + return index_mask_ops::find_indices_based_on_predicate( + curves.curves_range(), 2048, r_indices, [&](const int i) { + return selection[i] > 0.0f; + }); + } + default: + BLI_assert_unreachable(); + return {}; + } +} + +IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices) +{ + if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) { + return CurvesGeometry::wrap(curves_id.geometry).curves_range(); + } + return retrieve_selected_curves(CurvesGeometry::wrap(curves_id.geometry), + eAttrDomain(curves_id.selection_domain), + r_indices); +} + +} // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc new file mode 100644 index 00000000000..b40aebcaaf1 --- /dev/null +++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc @@ -0,0 +1,394 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <algorithm> +#include <numeric> + +#include "BLI_memory_utils.hh" +#include "BLI_task.hh" + +#include "DNA_brush_types.h" + +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_curves.hh" + +#include "DEG_depsgraph.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "WM_api.h" + +#include "curves_sculpt_intern.hh" + +/** + * The code below uses a suffix naming convention to indicate the coordinate space: + * cu: Local space of the curves object that is being edited. + * wo: World space. + * re: 2D coordinates within the region. + */ + +namespace blender::ed::sculpt_paint { + +using bke::CurvesGeometry; + +class SelectionPaintOperation : public CurvesSculptStrokeOperation { + private: + bool use_select_; + bool clear_selection_; + + CurvesBrush3D brush_3d_; + + friend struct SelectionPaintOperationExecutor; + + public: + SelectionPaintOperation(const bool use_select, const bool clear_selection) + : use_select_(use_select), clear_selection_(clear_selection) + { + } + void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override; +}; + +struct SelectionPaintOperationExecutor { + SelectionPaintOperation *self_ = nullptr; + CurvesSculptCommonContext ctx_; + + Object *object_ = nullptr; + Curves *curves_id_ = nullptr; + CurvesGeometry *curves_ = nullptr; + + const Brush *brush_ = nullptr; + float brush_radius_base_re_; + float brush_radius_factor_; + float brush_strength_; + + float selection_goal_; + + float2 brush_pos_re_; + + CurvesSculptTransforms transforms_; + + SelectionPaintOperationExecutor(const bContext &C) : ctx_(C) + { + } + + void execute(SelectionPaintOperation &self, + const bContext &C, + const StrokeExtension &stroke_extension) + { + self_ = &self; + object_ = CTX_data_active_object(&C); + + curves_id_ = static_cast<Curves *>(object_->data); + curves_ = &CurvesGeometry::wrap(curves_id_->geometry); + curves_id_->flag |= CV_SCULPT_SELECTION_ENABLED; + if (curves_->curves_num() == 0) { + return; + } + + brush_ = BKE_paint_brush_for_read(&ctx_.scene->toolsettings->curves_sculpt->paint); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); + brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); + brush_strength_ = BKE_brush_alpha_get(ctx_.scene, brush_); + + brush_pos_re_ = stroke_extension.mouse_position; + + if (self.clear_selection_) { + if (stroke_extension.is_first) { + if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) { + curves_->selection_point_float_for_write().fill(0.0f); + } + else if (curves_id_->selection_domain == ATTR_DOMAIN_CURVE) { + curves_->selection_curve_float_for_write().fill(0.0f); + } + } + } + + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); + + const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>( + brush_->falloff_shape); + + selection_goal_ = self_->use_select_ ? 1.0f : 0.0f; + + if (stroke_extension.is_first) { + if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + this->initialize_spherical_brush_reference_point(); + } + } + + if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) { + MutableSpan<float> selection = curves_->selection_point_float_for_write(); + if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + this->paint_point_selection_projected_with_symmetry(selection); + } + else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + this->paint_point_selection_spherical_with_symmetry(selection); + } + } + else { + MutableSpan<float> selection = curves_->selection_curve_float_for_write(); + if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + this->paint_curve_selection_projected_with_symmetry(selection); + } + else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + this->paint_curve_selection_spherical_with_symmetry(selection); + } + } + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because + * selection is handled as a generic attribute for now. */ + DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); + ED_region_tag_redraw(ctx_.region); + } + + void paint_point_selection_projected_with_symmetry(MutableSpan<float> selection) + { + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_point_selection_projected(brush_transform, selection); + } + } + + void paint_point_selection_projected(const float4x4 &brush_transform, + MutableSpan<float> selection) + { + const float4x4 brush_transform_inv = brush_transform.inverted(); + + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + Span<float3> positions_cu = curves_->positions(); + + const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; + const float brush_radius_sq_re = pow2f(brush_radius_re); + + threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) { + for (const int point_i : point_range) { + const float3 pos_cu = brush_transform_inv * positions_cu[point_i]; + + /* Find the position of the point in screen space. */ + float2 pos_re; + ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values); + + const float distance_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_); + if (distance_to_brush_sq_re > brush_radius_sq_re) { + /* Ignore the point because it's too far away. */ + continue; + } + + const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re); + /* A falloff that is based on how far away the point is from the stroke. */ + const float radius_falloff = BKE_brush_curve_strength( + brush_, distance_to_brush_re, brush_radius_re); + /* Combine the falloff and brush strength. */ + const float weight = brush_strength_ * radius_falloff; + + selection[point_i] = math::interpolate(selection[point_i], selection_goal_, weight); + } + }); + } + + void paint_point_selection_spherical_with_symmetry(MutableSpan<float> selection) + { + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + float3 brush_wo; + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, + brush_pos_re_, + brush_wo); + const float3 brush_cu = transforms_.world_to_curves * brush_wo; + + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_point_selection_spherical(selection, brush_transform * brush_cu); + } + } + + void paint_point_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu) + { + Span<float3> positions_cu = curves_->positions(); + + const float brush_radius_cu = self_->brush_3d_.radius_cu; + const float brush_radius_sq_cu = pow2f(brush_radius_cu); + + threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) { + for (const int i : point_range) { + const float3 pos_old_cu = positions_cu[i]; + + /* Compute distance to the brush. */ + const float distance_to_brush_sq_cu = math::distance_squared(pos_old_cu, brush_cu); + if (distance_to_brush_sq_cu > brush_radius_sq_cu) { + /* Ignore the point because it's too far away. */ + continue; + } + + const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu); + + /* A falloff that is based on how far away the point is from the stroke. */ + const float radius_falloff = BKE_brush_curve_strength( + brush_, distance_to_brush_cu, brush_radius_cu); + /* Combine the falloff and brush strength. */ + const float weight = brush_strength_ * radius_falloff; + + selection[i] = math::interpolate(selection[i], selection_goal_, weight); + } + }); + } + + void paint_curve_selection_projected_with_symmetry(MutableSpan<float> selection) + { + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_curve_selection_projected(brush_transform, selection); + } + } + + void paint_curve_selection_projected(const float4x4 &brush_transform, + MutableSpan<float> selection) + { + const Span<float3> positions_cu = curves_->positions(); + const float4x4 brush_transform_inv = brush_transform.inverted(); + + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; + const float brush_radius_sq_re = pow2f(brush_radius_re); + + threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) { + for (const int curve_i : curves_range) { + const float max_weight = threading::parallel_reduce( + curves_->points_for_curve(curve_i).drop_back(1), + 1024, + 0.0f, + [&](const IndexRange segment_range, const float init) { + float max_weight = init; + for (const int segment_i : segment_range) { + const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i]; + const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1]; + + float2 pos1_re; + float2 pos2_re; + ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values); + + const float distance_sq_re = dist_squared_to_line_segment_v2( + brush_pos_re_, pos1_re, pos2_re); + if (distance_sq_re > brush_radius_sq_re) { + continue; + } + const float radius_falloff = BKE_brush_curve_strength( + brush_, std::sqrt(distance_sq_re), brush_radius_re); + const float weight = brush_strength_ * radius_falloff; + max_weight = std::max(max_weight, weight); + } + return max_weight; + }, + [](float a, float b) { return std::max(a, b); }); + selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight); + } + }); + } + + void paint_curve_selection_spherical_with_symmetry(MutableSpan<float> selection) + { + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + float3 brush_wo; + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, + brush_pos_re_, + brush_wo); + const float3 brush_cu = transforms_.world_to_curves * brush_wo; + + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_curve_selection_spherical(selection, brush_transform * brush_cu); + } + } + + void paint_curve_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu) + { + const Span<float3> positions_cu = curves_->positions(); + + const float brush_radius_cu = self_->brush_3d_.radius_cu; + const float brush_radius_sq_cu = pow2f(brush_radius_cu); + + threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) { + for (const int curve_i : curves_range) { + const float max_weight = threading::parallel_reduce( + curves_->points_for_curve(curve_i).drop_back(1), + 1024, + 0.0f, + [&](const IndexRange segment_range, const float init) { + float max_weight = init; + for (const int segment_i : segment_range) { + const float3 &pos1_cu = positions_cu[segment_i]; + const float3 &pos2_cu = positions_cu[segment_i + 1]; + + const float distance_sq_cu = dist_squared_to_line_segment_v3( + brush_cu, pos1_cu, pos2_cu); + if (distance_sq_cu > brush_radius_sq_cu) { + continue; + } + const float radius_falloff = BKE_brush_curve_strength( + brush_, std::sqrt(distance_sq_cu), brush_radius_cu); + const float weight = brush_strength_ * radius_falloff; + max_weight = std::max(max_weight, weight); + } + return max_weight; + }, + [](float a, float b) { return std::max(a, b); }); + selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight); + } + }); + } + + void initialize_spherical_brush_reference_point() + { + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); + if (brush_3d.has_value()) { + self_->brush_3d_ = *brush_3d; + } + } +}; + +void SelectionPaintOperation::on_stroke_extended(const bContext &C, + const StrokeExtension &stroke_extension) +{ + SelectionPaintOperationExecutor executor{C}; + executor.execute(*this, C, stroke_extension); +} + +std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation( + const BrushStrokeMode brush_mode, const bContext &C) +{ + Scene &scene = *CTX_data_scene(&C); + Brush &brush = *BKE_paint_brush(&scene.toolsettings->curves_sculpt->paint); + const bool use_select = ELEM(brush_mode, BRUSH_STROKE_INVERT) == + ((brush.flag & BRUSH_DIR_IN) != 0); + const bool clear_selection = use_select && brush_mode != BRUSH_STROKE_SMOOTH; + + return std::make_unique<SelectionPaintOperation>(use_select, clear_selection); +} + +} // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc index bcdeaaeabf2..b63e5a7756b 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc @@ -23,7 +23,6 @@ #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_paint.h" -#include "BKE_spline.hh" #include "DNA_brush_enums.h" #include "DNA_brush_types.h" @@ -72,11 +71,7 @@ class SnakeHookOperation : public CurvesSculptStrokeOperation { */ struct SnakeHookOperatorExecutor { SnakeHookOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -90,13 +85,20 @@ struct SnakeHookOperatorExecutor { Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; - float4x4 curves_to_world_mat_; - float4x4 world_to_curves_mat_; + VArray<float> curve_factors_; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; + + CurvesSculptTransforms transforms_; float2 brush_pos_prev_re_; float2 brush_pos_re_; float2 brush_pos_diff_re_; + SnakeHookOperatorExecutor(const bContext &C) : ctx_(C) + { + } + void execute(SnakeHookOperation &self, const bContext &C, const StrokeExtension &stroke_extension) @@ -104,40 +106,41 @@ struct SnakeHookOperatorExecutor { BLI_SCOPED_DEFER([&]() { self.last_mouse_position_re_ = stroke_extension.mouse_position; }); self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape); - curves_to_world_mat_ = object_->obmat; - world_to_curves_mat_ = curves_to_world_mat_.inverted(); - curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); if (curves_->curves_num() == 0) { return; } + transforms_ = CurvesSculptTransforms(*object_, curves_id_->surface); + + curve_factors_ = get_curves_selection(*curves_id_); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + brush_pos_prev_re_ = self.last_mouse_position_re_; brush_pos_re_ = stroke_extension.mouse_position; brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_; if (stroke_extension.is_first) { if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { - std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_); + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); if (brush_3d.has_value()) { self_->brush_3d_ = *brush_3d; } @@ -158,7 +161,7 @@ struct SnakeHookOperatorExecutor { curves_->tag_positions_changed(); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } void projected_snake_hook_with_symmetry() @@ -177,7 +180,7 @@ struct SnakeHookOperatorExecutor { MutableSpan<float3> positions_cu = curves_->positions_for_write(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_sq_re = pow2f(brush_radius_re); @@ -189,7 +192,7 @@ struct SnakeHookOperatorExecutor { const float3 old_pos_cu = brush_transform_inv * positions_cu[last_point_i]; float2 old_pos_re; - ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values); const float distance_to_brush_sq_re = math::distance_squared(old_pos_re, brush_pos_prev_re_); @@ -199,15 +202,19 @@ struct SnakeHookOperatorExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i]; const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight; float3 new_position_wo; - ED_view3d_win_to_3d( - v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo); - const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo); - - this->move_last_point_and_resample(positions_cu.slice(points), new_position_cu); + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * old_pos_cu, + new_position_re, + new_position_wo); + const float3 new_position_cu = brush_transform * + (transforms_.world_to_curves * new_position_wo); + + move_last_point_and_resample(positions_cu.slice(points), new_position_cu); } }); } @@ -215,21 +222,21 @@ struct SnakeHookOperatorExecutor { void spherical_snake_hook_with_symmetry() { float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); float3 brush_start_wo, brush_end_wo; - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_prev_re_, brush_start_wo); - ED_view3d_win_to_3d(v3d_, - region_, - curves_to_world_mat_ * self_->brush_3d_.position_cu, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + transforms_.curves_to_world * self_->brush_3d_.position_cu, brush_pos_re_, brush_end_wo); - const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo; - const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo; + const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo; + const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo; const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; @@ -265,52 +272,20 @@ struct SnakeHookOperatorExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, distance_to_brush_cu, brush_radius_cu); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i]; const float3 new_pos_cu = old_pos_cu + weight * brush_diff_cu; - this->move_last_point_and_resample(positions_cu.slice(points), new_pos_cu); + move_last_point_and_resample(positions_cu.slice(points), new_pos_cu); } }); } - - void move_last_point_and_resample(MutableSpan<float3> positions, - const float3 &new_last_position) const - { - /* Find the accumulated length of each point in the original curve, - * treating it as a poly curve for performance reasons and simplicity. */ - Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false)); - length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths); - const float orig_total_length = orig_lengths.last(); - - /* Find the factor by which the new curve is shorter or longer than the original. */ - const float new_last_segment_length = math::distance(positions.last(1), new_last_position); - const float new_total_length = orig_lengths.last(1) + new_last_segment_length; - const float length_factor = new_total_length / orig_total_length; - - /* Calculate the lengths to sample the original curve with by scaling the original lengths. */ - Array<float> new_lengths(positions.size() - 1); - new_lengths.first() = 0.0f; - for (const int i : new_lengths.index_range().drop_front(1)) { - new_lengths[i] = orig_lengths[i - 1] * length_factor; - } - - Array<int> indices(positions.size() - 1); - Array<float> factors(positions.size() - 1); - length_parameterize::create_samples_from_sorted_lengths( - orig_lengths, new_lengths, false, indices, factors); - - Array<float3> new_positions(positions.size() - 1); - length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions); - positions.drop_back(1).copy_from(new_positions); - positions.last() = new_last_position; - } }; void SnakeHookOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - SnakeHookOperatorExecutor executor; + SnakeHookOperatorExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 861da185975..c5ebcf870a3 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -38,6 +38,7 @@ #include "IMB_imbuf_types.h" +#include "ED_image.h" #include "ED_view3d.h" #include "DEG_depsgraph.h" @@ -1358,7 +1359,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon ViewContext *vc = &pcontext->vc; SculptCursorGeometryInfo gi; - const float mouse[2] = { + const float mval_fl[2] = { pcontext->x - pcontext->region->winrct.xmin, pcontext->y - pcontext->region->winrct.ymin, }; @@ -1368,7 +1369,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon pcontext->prev_active_vertex_index = ss->active_vertex_index; if (!ups->stroke_active) { pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update( - C, &gi, mouse, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)); + C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)); copy_v3_v3(pcontext->location, gi.location); copy_v3_v3(pcontext->normal, gi.normal); } @@ -1932,7 +1933,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* Public API */ -void paint_cursor_start(Paint *p, bool (*poll)(bContext *C)) +void ED_paint_cursor_start(Paint *p, bool (*poll)(bContext *C)) { if (p && !p->paint_cursor) { p->paint_cursor = WM_paint_cursor_activate( diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc index a313489885d..56cd4751881 100644 --- a/source/blender/editors/sculpt_paint/paint_image.cc +++ b/source/blender/editors/sculpt_paint/paint_image.cc @@ -287,7 +287,7 @@ static bool image_paint_poll_ex(bContext *C, bool check_tool) return false; } -bool image_paint_poll(bContext *C) +bool ED_image_tools_paint_poll(bContext *C) { return image_paint_poll_ex(C, true); } @@ -301,7 +301,7 @@ static bool image_paint_2d_clone_poll(bContext *C) { Brush *brush = image_paint_brush(C); - if (!CTX_wm_region_view3d(C) && image_paint_poll(C)) { + if (!CTX_wm_region_view3d(C) && ED_image_tools_paint_poll(C)) { if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) { if (brush->clone.image) { return true; @@ -430,7 +430,7 @@ static void toggle_paint_cursor(Scene *scene, bool enable) paint_cursor_delete_textures(); } else if (enable) { - paint_cursor_start(p, image_paint_poll); + ED_paint_cursor_start(p, ED_image_tools_paint_poll); } } @@ -455,7 +455,7 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene) if (enabled) { BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT); - paint_cursor_start(&imapaint->paint, image_paint_poll); + ED_paint_cursor_start(&imapaint->paint, ED_image_tools_paint_poll); } else { paint_cursor_delete_textures(); @@ -736,7 +736,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot) ot->poll = sample_color_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER; /* properties */ PropertyRNA *prop; @@ -925,7 +925,7 @@ static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) static bool brush_colors_flip_poll(bContext *C) { - if (image_paint_poll(C)) { + if (ED_image_tools_paint_poll(C)) { Brush *br = image_paint_brush(C); if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL)) { return true; @@ -954,7 +954,7 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot) ot->poll = brush_colors_flip_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER; } void ED_imapaint_bucket_fill(struct bContext *C, @@ -991,7 +991,7 @@ static bool texture_paint_poll(bContext *C) bool image_texture_paint_poll(bContext *C) { - return (texture_paint_poll(C) || image_paint_poll(C)); + return (texture_paint_poll(C) || ED_image_tools_paint_poll(C)); } bool facemask_paint_poll(bContext *C) diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc index 8ddf1614e41..a671c24c514 100644 --- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc +++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc @@ -34,6 +34,8 @@ #include "WM_toolsystem.h" #include "WM_types.h" +#include "ED_image.h" + #include "paint_intern.h" namespace blender::ed::sculpt_paint::image::ops::paint { @@ -316,7 +318,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) { pop->cursor = WM_paint_cursor_activate( - SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop); + SPACE_TYPE_ANY, RGN_TYPE_ANY, ED_image_tools_paint_poll, gradient_draw_line, pop); } settings->imapaint.flag |= IMAGEPAINT_DRAWING; @@ -520,7 +522,7 @@ void PAINT_OT_image_paint(wmOperatorType *ot) ot->invoke = paint_invoke; ot->modal = paint_modal; ot->exec = paint_exec; - ot->poll = image_paint_poll; + ot->poll = ED_image_tools_paint_poll; ot->cancel = paint_cancel; /* flags */ diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index b7ec427349f..50480b8aef0 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3132,7 +3132,7 @@ static void project_paint_face_init(const ProjPaintState *ps, } } - /* Is this UV visible from the view? - raytrace */ + /* Is this UV visible from the view? - ray-trace */ /* project_paint_PickFace is less complex, use for testing */ // if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) { if ((ps->do_occlude == false) || @@ -3222,7 +3222,7 @@ static void project_paint_face_init(const ProjPaintState *ps, float seam_subsection[4][2]; float fac1, fac2; - /* Pixelspace UVs. */ + /* Pixel-space UV's. */ float lt_puv[3][2]; lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x; @@ -4492,7 +4492,8 @@ static void project_paint_begin(const bContext *C, } } - /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ + /* when using sub-surface or multi-resolution, + * mesh-data arrays are thrown away, we need to keep a copy. */ if (ps->is_shared_user == false) { proj_paint_state_cavity_init(ps); } @@ -6488,14 +6489,14 @@ static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object { char name[MAX_NAME] = ""; float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - AttributeDomain domain = ATTR_DOMAIN_POINT; - CustomDataType type = CD_PROP_COLOR; + eAttrDomain domain = ATTR_DOMAIN_POINT; + eCustomDataType type = CD_PROP_COLOR; if (op) { RNA_string_get(op->ptr, "name", name); RNA_float_get_array(op->ptr, "color", color); - domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); - type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); + domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain"); + type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); } ID *id = (ID *)ob->data; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 187f793eefe..ea17114efa5 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -98,7 +98,6 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke); float paint_stroke_distance_get(struct PaintStroke *stroke); void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data); bool PAINT_brush_tool_poll(struct bContext *C); -void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C)); /** * Delete overlay cursor textures to preserve memory and invalidate all overlay flags. */ @@ -135,18 +134,10 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot); unsigned int vpaint_get_current_color(struct Scene *scene, struct VPaint *vp, bool secondary); -/* paint_vertex_color_utils.c */ - /** * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool */ unsigned int ED_vpaint_blend_tool(int tool, uint col, uint paintcol, int alpha_i); -/** - * Apply callback to each vertex of the active vertex color layer. - */ -bool ED_vpaint_color_transform(struct Object *ob, - VPaintTransform_Callback vpaint_tx_fn, - const void *user_data); /* paint_vertex_weight_utils.c */ diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index fb5e76b578f..89bbf2a3c92 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1584,9 +1584,9 @@ static int sculpt_trim_gesture_box_invoke(bContext *C, wmOperator *op, const wmE SculptSession *ss = ob->sculpt; SculptCursorGeometryInfo sgi; - float mouse[2] = {event->mval[0], event->mval[1]}; + const float mval_fl[2] = {UNPACK2(event->mval)}; SCULPT_vertex_random_access_ensure(ss); - ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); if (ss->gesture_initial_hit) { copy_v3_v3(ss->gesture_initial_location, sgi.location); copy_v3_v3(ss->gesture_initial_normal, sgi.normal); @@ -1625,9 +1625,9 @@ static int sculpt_trim_gesture_lasso_invoke(bContext *C, wmOperator *op, const w SculptSession *ss = ob->sculpt; SculptCursorGeometryInfo sgi; - float mouse[2] = {event->mval[0], event->mval[1]}; + const float mval_fl[2] = {UNPACK2(event->mval)}; SCULPT_vertex_random_access_ensure(ss); - ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); if (ss->gesture_initial_hit) { copy_v3_v3(ss->gesture_initial_location, sgi.location); copy_v3_v3(ss->gesture_initial_normal, sgi.normal); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 926a564184a..ce6b397af15 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -82,11 +82,85 @@ static void BRUSH_OT_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool, + enum eContextObjectMode mode) +{ + switch (mode) { + case CTX_MODE_PAINT_GPENCIL: { + if (STREQ(tool->runtime->data_block, "DRAW")) { + return GP_BRUSH_PRESET_PENCIL; + } + if (STREQ(tool->runtime->data_block, "FILL")) { + return GP_BRUSH_PRESET_FILL_AREA; + } + if (STREQ(tool->runtime->data_block, "ERASE")) { + return GP_BRUSH_PRESET_ERASER_SOFT; + } + if (STREQ(tool->runtime->data_block, "TINT")) { + return GP_BRUSH_PRESET_TINT; + } + break; + } + case CTX_MODE_SCULPT_GPENCIL: { + if (STREQ(tool->runtime->data_block, "SMOOTH")) { + return GP_BRUSH_PRESET_SMOOTH_STROKE; + } + if (STREQ(tool->runtime->data_block, "STRENGTH")) { + return GP_BRUSH_PRESET_STRENGTH_STROKE; + } + if (STREQ(tool->runtime->data_block, "THICKNESS")) { + return GP_BRUSH_PRESET_THICKNESS_STROKE; + } + if (STREQ(tool->runtime->data_block, "GRAB")) { + return GP_BRUSH_PRESET_GRAB_STROKE; + } + if (STREQ(tool->runtime->data_block, "PUSH")) { + return GP_BRUSH_PRESET_PUSH_STROKE; + } + if (STREQ(tool->runtime->data_block, "TWIST")) { + return GP_BRUSH_PRESET_TWIST_STROKE; + } + if (STREQ(tool->runtime->data_block, "PINCH")) { + return GP_BRUSH_PRESET_PINCH_STROKE; + } + if (STREQ(tool->runtime->data_block, "RANDOMIZE")) { + return GP_BRUSH_PRESET_RANDOMIZE_STROKE; + } + if (STREQ(tool->runtime->data_block, "CLONE")) { + return GP_BRUSH_PRESET_CLONE_STROKE; + } + break; + } + case CTX_MODE_WEIGHT_GPENCIL: { + return GP_BRUSH_PRESET_DRAW_WEIGHT; + } + case CTX_MODE_VERTEX_GPENCIL: { + if (STREQ(tool->runtime->data_block, "DRAW")) { + return GP_BRUSH_PRESET_VERTEX_DRAW; + } + if (STREQ(tool->runtime->data_block, "BLUR")) { + return GP_BRUSH_PRESET_VERTEX_BLUR; + } + if (STREQ(tool->runtime->data_block, "AVERAGE")) { + return GP_BRUSH_PRESET_VERTEX_AVERAGE; + } + if (STREQ(tool->runtime->data_block, "SMEAR")) { + return GP_BRUSH_PRESET_VERTEX_SMEAR; + } + if (STREQ(tool->runtime->data_block, "REPLACE")) { + return GP_BRUSH_PRESET_VERTEX_REPLACE; + } + break; + } + default: + return GP_BRUSH_PRESET_UNKNOWN; + } + return GP_BRUSH_PRESET_UNKNOWN; +} + static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op)) { - // int type = RNA_enum_get(op->ptr, "type"); - ToolSettings *ts = CTX_data_tool_settings(C); - Paint *paint = &ts->gp_paint->paint; + Paint *paint = BKE_paint_get_active_from_context(C); Brush *br = BKE_paint_brush(paint); Main *bmain = CTX_data_main(C); @@ -94,15 +168,70 @@ static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op)) br = (Brush *)BKE_id_copy(bmain, &br->id); } else { - br = BKE_brush_add(bmain, "Brush", OB_MODE_PAINT_GPENCIL); + /* Get the active tool to determine what type of brush is active. */ + bScreen *screen = CTX_wm_screen(C); + if (screen == NULL) { + return OPERATOR_CANCELLED; + } - /* Init grease pencil specific data. */ - BKE_brush_init_gpencil_settings(br); - } + bToolRef *tool = NULL; + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype == SPACE_VIEW3D) { + /* Check the current tool is a brush. */ + bToolRef *tref = area->runtime.tool; + if (tref && tref->runtime && tref->runtime->data_block[0]) { + tool = tref; + break; + } + } + } - id_us_min(&br->id); /* fake user only */ + if (tool == NULL) { + return OPERATOR_CANCELLED; + } - BKE_paint_brush_set(paint, br); + /* Get Brush mode base on context mode. */ + const enum eContextObjectMode mode = CTX_data_mode_enum(C); + eObjectMode obmode = OB_MODE_PAINT_GPENCIL; + switch (mode) { + case CTX_MODE_PAINT_GPENCIL: + obmode = OB_MODE_PAINT_GPENCIL; + break; + case CTX_MODE_SCULPT_GPENCIL: + obmode = OB_MODE_SCULPT_GPENCIL; + break; + case CTX_MODE_WEIGHT_GPENCIL: + obmode = OB_MODE_WEIGHT_GPENCIL; + break; + case CTX_MODE_VERTEX_GPENCIL: + obmode = OB_MODE_VERTEX_GPENCIL; + break; + default: + return OPERATOR_CANCELLED; + break; + } + + /* Get brush preset using the actual tool. */ + eGPBrush_Presets preset = gpencil_get_brush_preset_from_tool(tool, mode); + + /* Capitalize Brush name first letter using the tool name. */ + char name[64]; + BLI_strncpy(name, tool->runtime->data_block, sizeof(name)); + BLI_str_tolower_ascii(name, sizeof(name)); + name[0] = BLI_toupper_ascii(name[0]); + + /* Create the brush and assign default values. */ + br = BKE_brush_add(bmain, name, obmode); + if (br) { + BKE_brush_init_gpencil_settings(br); + BKE_gpencil_brush_preset_set(bmain, br, preset); + } + } + + if (br) { + id_us_min(&br->id); /* fake user only */ + BKE_paint_brush_set(paint, br); + } return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 210cffcbcda..63e6dc7e965 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -506,7 +506,7 @@ static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert) /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */ static void paint_brush_stroke_add_step( - bContext *C, wmOperator *op, PaintStroke *stroke, const float mouse_in[2], float pressure) + bContext *C, wmOperator *op, PaintStroke *stroke, const float mval[2], float pressure) { Scene *scene = CTX_data_scene(C); Paint *paint = BKE_paint_get_active_from_context(C); @@ -546,7 +546,7 @@ static void paint_brush_stroke_add_step( /* copy last position -before- jittering, or space fill code * will create too many dabs */ - copy_v2_v2(stroke->last_mouse_position, mouse_in); + copy_v2_v2(stroke->last_mouse_position, mval); stroke->last_pressure = pressure; if (paint_stroke_use_scene_spacing(brush, mode)) { @@ -562,24 +562,24 @@ static void paint_brush_stroke_add_step( factor *= pressure; } - BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out); + BKE_brush_jitter_pos(scene, brush, mval, mouse_out); /* XXX: meh, this is round about because * BKE_brush_jitter_pos isn't written in the best way to * be reused here */ if (factor != 1.0f) { - sub_v2_v2v2(delta, mouse_out, mouse_in); + sub_v2_v2v2(delta, mouse_out, mval); mul_v2_fl(delta, factor); - add_v2_v2v2(mouse_out, mouse_in, delta); + add_v2_v2v2(mouse_out, mval, delta); } } else { - copy_v2_v2(mouse_out, mouse_in); + copy_v2_v2(mouse_out, mval); } bool is_location_is_set; ups->last_hit = paint_brush_update( - C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set); + C, brush, mode, stroke, mval, mouse_out, pressure, location, &is_location_is_set); if (is_location_is_set) { copy_v3_v3(ups->last_location, location); } @@ -605,7 +605,7 @@ static void paint_brush_stroke_add_step( /* Mouse coordinates modified by the stroke type options. */ RNA_float_set_array(&itemptr, "mouse", mouse_out); /* Original mouse coordinates. */ - RNA_float_set_array(&itemptr, "mouse_event", mouse_in); + RNA_float_set_array(&itemptr, "mouse_event", mval); RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip); RNA_float_set(&itemptr, "pressure", pressure); RNA_float_set(&itemptr, "x_tilt", stroke->x_tilt); @@ -912,8 +912,13 @@ PaintStroke *paint_stroke_new(bContext *C, rv3d->rflag |= RV3D_PAINTING; } - zero_v3(ups->average_stroke_accum); - ups->average_stroke_counter = 0; + /* Preserve location from last stroke while applying and resetting + * ups->average_stroke_counter to 1. + */ + if (ups->average_stroke_counter) { + mul_v3_fl(ups->average_stroke_accum, 1.0f / (float)ups->average_stroke_counter); + ups->average_stroke_counter = 1; + } /* initialize here to avoid initialization conflict with threaded strokes */ BKE_curvemapping_init(br->curve); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index fb1c8ceaa1a..b8403b1e34b 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -56,6 +56,7 @@ #include "WM_types.h" #include "ED_armature.h" +#include "ED_image.h" #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" @@ -139,8 +140,8 @@ struct NormalAnglePrecalc { /* Returns number of elements. */ static int get_vcol_elements(Mesh *me, size_t *r_elem_size) { - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); - AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); + const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); if (r_elem_size) { *r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL; @@ -217,7 +218,7 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev, MDeformVert *dvert_curr, int index) { - MDeformVert *dv_curr = &dvert_curr[index]; + const MDeformVert *dv_curr = &dvert_curr[index]; MDeformVert *dv_prev = &dvert_prev[index]; if (dv_prev->flag == 1) { dv_prev->flag = 0; @@ -226,22 +227,6 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev, return dv_prev; } -/* check if we can do partial updates and have them draw realtime - * (without evaluating modifiers) */ -static bool vertex_paint_use_fast_update_check(Object *ob) -{ - const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob); - - if (me_eval != nullptr) { - Mesh *me = BKE_mesh_from_object(ob); - if (me && me->mloopcol) { - return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_PROP_BYTE_COLOR)); - } - } - - return false; -} - static void paint_last_stroke_update(Scene *scene, const float location[3]) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -252,13 +237,14 @@ static void paint_last_stroke_update(Scene *scene, const float location[3]) bool vertex_paint_mode_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + const Object *ob = CTX_data_active_object(C); - if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly)) { + if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((const Mesh *)ob->data)->totpoly)) { return false; } - CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)ob->data); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get( + static_cast<const ID *>(ob->data)); return layer != nullptr; } @@ -291,15 +277,15 @@ bool vertex_paint_poll_ignore_tool(bContext *C) bool weight_paint_mode_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + const Object *ob = CTX_data_active_object(C); - return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly; + return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((const Mesh *)ob->data)->totpoly; } static bool weight_paint_poll_ex(bContext *C, bool check_tool) { - Object *ob = CTX_data_active_object(C); - ScrArea *area; + const Object *ob = CTX_data_active_object(C); + const ScrArea *area; if ((ob != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT) && (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != nullptr) && @@ -324,10 +310,10 @@ bool weight_paint_poll_ignore_tool(bContext *C) return weight_paint_poll_ex(C, false); } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary) { - Brush *brush = BKE_paint_brush(&vp->paint); + const Brush *brush = BKE_paint_brush_for_read(&vp->paint); float color[4]; const float *brush_color = secondary ? BKE_brush_secondary_color_get(scene, brush) : BKE_brush_color_get(scene, brush); @@ -360,7 +346,7 @@ static Color vpaint_blend(const VPaint *vp, const Brush *brush = vp->paint.brush; const IMB_BlendMode blend = (IMB_BlendMode)brush->blend; - Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha); + const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha); /* If no accumulate, clip color adding with `color_orig` & `color_test`. */ if (!brush_use_accumulate(vp)) { @@ -1321,7 +1307,7 @@ static void ed_vwpaintmode_enter_generic( BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint); Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - paint_cursor_start(paint, vertex_paint_poll); + ED_paint_cursor_start(paint, vertex_paint_poll); BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT); } else if (mode_flag == OB_MODE_WEIGHT_PAINT) { @@ -1329,7 +1315,7 @@ static void ed_vwpaintmode_enter_generic( BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint); Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - paint_cursor_start(paint, weight_paint_poll); + ED_paint_cursor_start(paint, weight_paint_poll); BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT); /* weight paint specific */ @@ -1606,10 +1592,10 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache /* Initialize the stroke cache invariants from operator properties */ static void vwpaint_update_cache_invariants( - bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2]) + bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mval[2]) { StrokeCache *cache; - Scene *scene = CTX_data_scene(C); + const Scene *scene = CTX_data_scene(C); UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; ViewContext *vc = paint_stroke_view_context((PaintStroke *)op->customdata); Object *ob = CTX_data_active_object(C); @@ -1627,8 +1613,8 @@ static void vwpaint_update_cache_invariants( } /* Initial mouse location */ - if (mouse) { - copy_v2_v2(cache->initial_mouse, mouse); + if (mval) { + copy_v2_v2(cache->initial_mouse, mval); } else { zero_v2(cache->initial_mouse); @@ -1651,7 +1637,7 @@ static void vwpaint_update_cache_invariants( } copy_v2_v2(cache->mouse, cache->initial_mouse); - Brush *brush = vp->paint.brush; + const Brush *brush = vp->paint.brush; /* Truly temporary data that isn't stored in properties */ cache->vc = vc; cache->brush = brush; @@ -2823,11 +2809,11 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) struct VPaintDataBase { ViewContext vc; - AttributeDomain domain; - CustomDataType type; + eAttrDomain domain; + eCustomDataType type; }; -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> struct VPaintData : public VPaintDataBase { NormalAnglePrecalc normal_angle_precalc; @@ -2836,16 +2822,6 @@ struct VPaintData : public VPaintDataBase { struct VertProjHandle *vp_handle; CoNo *vertexcosnos; - /** - * Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this - * array, otherwise we need to refresh the modifier stack. - */ - bool use_fast_update; - - /* loops tagged as having been painted, to apply shared vertex color - * blending only to modified loops */ - bool *mlooptag; - bool is_texbrush; /* Special storage for smear brush, avoid feedback loop - update each step. */ @@ -2855,7 +2831,7 @@ struct VPaintData : public VPaintDataBase { } smear; }; -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void *vpaint_init_vpaint(bContext *C, wmOperator *op, Scene *scene, @@ -2891,20 +2867,6 @@ static void *vpaint_init_vpaint(bContext *C, vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex; - /* are we painting onto a modified mesh?, - * if not we can skip face map trickiness */ - if (vertex_paint_use_fast_update_check(ob)) { - vpd->use_fast_update = true; - } - else { - vpd->use_fast_update = false; - } - - /* to keep tracked of modified loops for shared vertex color blending */ - if (brush->vertexpaint_tool == VPAINT_TOOL_BLUR) { - vpd->mlooptag = (bool *)MEM_mallocN(sizeof(bool) * elem_num, "VPaintData mlooptag"); - } - if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) { CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); @@ -2949,7 +2911,7 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo return false; } - AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer); + eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); void *vpd = nullptr; if (domain == ATTR_DOMAIN_POINT) { @@ -3272,7 +3234,7 @@ static void do_vpaint_brush_blur_verts(bContext *C, }); } -template<typename Color = ColorPaint4b, typename Traits, AttributeDomain domain> +template<typename Color = ColorPaint4b, typename Traits, eAttrDomain domain> static void do_vpaint_brush_smear(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, @@ -3451,7 +3413,7 @@ static void do_vpaint_brush_smear(bContext *C, }); } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd, Object *ob, Mesh *me, @@ -3541,7 +3503,7 @@ static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static float paint_and_tex_color_alpha(VPaint *vp, VPaintData<Color, Traits, domain> *vpd, const float v_co[3], @@ -3559,7 +3521,7 @@ static float paint_and_tex_color_alpha(VPaint *vp, return rgba[3]; } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_draw(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, @@ -3699,7 +3661,7 @@ static void vpaint_do_draw(bContext *C, }); } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_blur(bContext *C, Sculpt *sd, VPaint *vp, @@ -3718,7 +3680,7 @@ static void vpaint_do_blur(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_paint_leaves(bContext *C, Sculpt *sd, VPaint *vp, @@ -3754,7 +3716,7 @@ static void vpaint_paint_leaves(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_paint(bContext *C, Sculpt *sd, VPaint *vp, @@ -3785,7 +3747,7 @@ static void vpaint_do_paint(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_radial_symmetry(bContext *C, Sculpt *sd, VPaint *vp, @@ -3804,7 +3766,7 @@ static void vpaint_do_radial_symmetry(bContext *C, /* near duplicate of: sculpt.c's, * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */ -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_symmetrical_brush_actions( bContext *C, Sculpt *sd, VPaint *vp, VPaintData<Color, Traits, domain> *vpd, Object *ob) { @@ -3851,7 +3813,7 @@ static void vpaint_do_symmetrical_brush_actions( cache->is_last_valid = true; } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, PointerRNA *itemptr) { Scene *scene = CTX_data_scene(C); @@ -3899,15 +3861,7 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P ED_region_tag_redraw(vc->region); - if (vpd->use_fast_update == false) { - /* recalculate modifier stack to get new colors, slow, - * avoid this if we can! */ - DEG_id_tag_update((ID *)ob->data, 0); - } - else { - /* Flush changes through DEG. */ - DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE); - } + DEG_id_tag_update((ID *)ob->data, ID_RECALC_GEOMETRY); } static void vpaint_stroke_update_step(bContext *C, @@ -3939,7 +3893,7 @@ static void vpaint_stroke_update_step(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd) { VPaintData<Color, Traits, domain> *vpd = static_cast<VPaintData<Color, Traits, domain> *>(_vpd); @@ -3948,9 +3902,6 @@ static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd) ED_vpaint_proj_handle_free(vpd->vp_handle); } - if (vpd->mlooptag) { - MEM_freeN(vpd->mlooptag); - } if (vpd->smear.color_prev) { MEM_freeN(vpd->smear.color_prev); } @@ -4096,7 +4047,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) /** \name Set Vertex Colors Operator * \{ */ -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_layer) { Mesh *me; @@ -4164,7 +4115,7 @@ static bool paint_object_attributes_active_color_fill_ex(Object *ob, me->editflag &= ~ME_EDIT_PAINT_FACE_SEL; me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; } - AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer); + eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); bool ok = false; if (domain == ATTR_DOMAIN_POINT) { if (layer->type == CD_PROP_COLOR) { diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c deleted file mode 100644 index a2e1adff50a..00000000000 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ /dev/null @@ -1,485 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup edsculpt - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BLI_math_base.h" -#include "BLI_math_color.h" - -#include "BKE_context.h" -#include "BKE_deform.h" -#include "BKE_mesh.h" - -#include "DEG_depsgraph.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_mesh.h" - -#include "paint_intern.h" /* own include */ - -/* -------------------------------------------------------------------- */ -/** \name Internal Utility Functions - * \{ */ - -static bool vertex_weight_paint_mode_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - Mesh *me = BKE_mesh_from_object(ob); - return (ob && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) && - (me && me->totpoly && me->dvert); -} - -static void tag_object_after_update(Object *object) -{ - BLI_assert(object->type == OB_MESH); - Mesh *mesh = object->data; - DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE); - /* NOTE: Original mesh is used for display, so tag it directly here. */ - BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Vertex Color from Weight Operator - * \{ */ - -static bool vertex_paint_from_weight(Object *ob) -{ - Mesh *me; - const MPoly *mp; - int vgroup_active; - - if (((me = BKE_mesh_from_object(ob)) == NULL || (ED_mesh_color_ensure(me, NULL)) == false)) { - return false; - } - - /* TODO: respect selection. */ - /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway. */ - mp = me->mpoly; - vgroup_active = me->vertex_group_active_index - 1; - for (int i = 0; i < me->totpoly; i++, mp++) { - MLoopCol *lcol = &me->mloopcol[mp->loopstart]; - uint j = 0; - do { - uint vidx = me->mloop[mp->loopstart + j].v; - const float weight = BKE_defvert_find_weight(&me->dvert[vidx], vgroup_active); - const uchar grayscale = weight * 255; - lcol->r = grayscale; - lcol->b = grayscale; - lcol->g = grayscale; - lcol++; - j++; - } while (j < mp->totloop); - } - - tag_object_after_update(ob); - - return true; -} - -static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obact = CTX_data_active_object(C); - if (vertex_paint_from_weight(obact)) { - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Color from Weight"; - ot->idname = "PAINT_OT_vertex_color_from_weight"; - ot->description = "Convert active weight into gray scale vertex colors"; - - /* api callback */ - ot->exec = vertex_paint_from_weight_exec; - ot->poll = vertex_weight_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* TODO: invert, alpha */ -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Smooth Vertex Colors Operator - * \{ */ - -static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag) -{ - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - const MPoly *mp; - int(*scol)[4]; - bool has_shared = false; - - if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) { - return; - } - - scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol"); - - int i; - for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { - if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { - const MLoop *ml = me->mloop + mp->loopstart; - MLoopCol *lcol = me->mloopcol + mp->loopstart; - for (int j = 0; j < mp->totloop; j++, ml++, lcol++) { - scol[ml->v][0] += lcol->r; - scol[ml->v][1] += lcol->g; - scol[ml->v][2] += lcol->b; - scol[ml->v][3] += 1; - has_shared = 1; - } - } - } - - if (has_shared) { - for (i = 0; i < me->totvert; i++) { - if (scol[i][3] != 0) { - scol[i][0] = divide_round_i(scol[i][0], scol[i][3]); - scol[i][1] = divide_round_i(scol[i][1], scol[i][3]); - scol[i][2] = divide_round_i(scol[i][2], scol[i][3]); - } - } - - for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) { - if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) { - const MLoop *ml = me->mloop + mp->loopstart; - MLoopCol *lcol = me->mloopcol + mp->loopstart; - for (int j = 0; j < mp->totloop; j++, ml++, lcol++) { - if (mlooptag[mp->loopstart + j]) { - lcol->r = scol[ml->v][0]; - lcol->g = scol[ml->v][1]; - lcol->b = scol[ml->v][2]; - } - } - } - } - } - - MEM_freeN(scol); -} - -static bool vertex_color_smooth(Object *ob) -{ - Mesh *me; - const MPoly *mp; - int i, j; - - bool *mlooptag; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) { - return false; - } - - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - - mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag"); - - /* simply tag loops of selected faces */ - mp = me->mpoly; - for (i = 0; i < me->totpoly; i++, mp++) { - const MLoop *ml = me->mloop + mp->loopstart; - - if (use_face_sel && !(mp->flag & ME_FACE_SEL)) { - continue; - } - - j = 0; - do { - if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) { - mlooptag[mp->loopstart + j] = true; - } - ml++; - j++; - } while (j < mp->totloop); - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - vertex_color_smooth_looptag(me, mlooptag); - - MEM_freeN(mlooptag); - - tag_object_after_update(ob); - - return true; -} - -static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obact = CTX_data_active_object(C); - if (vertex_color_smooth(obact)) { - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Smooth Vertex Colors"; - ot->idname = "PAINT_OT_vertex_color_smooth"; - ot->description = "Smooth colors across vertices"; - - /* api callbacks */ - ot->exec = vertex_color_smooth_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Vertex Color Transformation Operators - * \{ */ - -struct VPaintTx_BrightContrastData { - /* pre-calculated */ - float gain; - float offset; -}; - -static void vpaint_tx_brightness_contrast(const float col[3], - const void *user_data, - float r_col[3]) -{ - const struct VPaintTx_BrightContrastData *data = user_data; - - for (int i = 0; i < 3; i++) { - r_col[i] = data->gain * col[i] + data->offset; - } -} - -static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - float gain, offset; - { - float brightness = RNA_float_get(op->ptr, "brightness"); - float contrast = RNA_float_get(op->ptr, "contrast"); - brightness /= 100.0f; - float delta = contrast / 200.0f; - /* - * The algorithm is by Werner D. Streidt - * (http://visca.com/ffactory/archives/5-99/msg00021.html) - * Extracted of OpenCV demhist.c - */ - if (contrast > 0) { - gain = 1.0f - delta * 2.0f; - gain = 1.0f / max_ff(gain, FLT_EPSILON); - offset = gain * (brightness - delta); - } - else { - delta *= -1; - gain = max_ff(1.0f - delta * 2.0f, 0.0f); - offset = gain * brightness + delta; - } - } - - const struct VPaintTx_BrightContrastData user_data = { - .gain = gain, - .offset = offset, - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Vertex Paint Brightness/Contrast"; - ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; - ot->description = "Adjust vertex color brightness/contrast"; - - /* api callbacks */ - ot->exec = vertex_color_brightness_contrast_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - const float min = -100, max = +100; - prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); - prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); - RNA_def_property_ui_range(prop, min, max, 1, 1); -} - -struct VPaintTx_HueSatData { - float hue; - float sat; - float val; -}; - -static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_HueSatData *data = user_data; - float hsv[3]; - rgb_to_hsv_v(col, hsv); - - hsv[0] += (data->hue - 0.5f); - if (hsv[0] > 1.0f) { - hsv[0] -= 1.0f; - } - else if (hsv[0] < 0.0f) { - hsv[0] += 1.0f; - } - hsv[1] *= data->sat; - hsv[2] *= data->val; - - hsv_to_rgb_v(hsv, r_col); -} - -static int vertex_color_hsv_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - const struct VPaintTx_HueSatData user_data = { - .hue = RNA_float_get(op->ptr, "h"), - .sat = RNA_float_get(op->ptr, "s"), - .val = RNA_float_get(op->ptr, "v"), - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Hue Saturation Value"; - ot->idname = "PAINT_OT_vertex_color_hsv"; - ot->description = "Adjust vertex color HSV values"; - - /* api callbacks */ - ot->exec = vertex_color_hsv_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); - RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); - RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); -} - -static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3]) -{ - for (int i = 0; i < 3; i++) { - r_col[i] = 1.0f - col[i]; - } -} - -static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obact = CTX_data_active_object(C); - - if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -void PAINT_OT_vertex_color_invert(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Invert"; - ot->idname = "PAINT_OT_vertex_color_invert"; - ot->description = "Invert RGB values"; - - /* api callbacks */ - ot->exec = vertex_color_invert_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -struct VPaintTx_LevelsData { - float gain; - float offset; -}; - -static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) -{ - const struct VPaintTx_LevelsData *data = user_data; - for (int i = 0; i < 3; i++) { - r_col[i] = data->gain * (col[i] + data->offset); - } -} - -static int vertex_color_levels_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - - const struct VPaintTx_LevelsData user_data = { - .gain = RNA_float_get(op->ptr, "gain"), - .offset = RNA_float_get(op->ptr, "offset"), - }; - - if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -void PAINT_OT_vertex_color_levels(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Paint Levels"; - ot->idname = "PAINT_OT_vertex_color_levels"; - ot->description = "Adjust levels of vertex colors"; - - /* api callbacks */ - ot->exec = vertex_color_levels_exec; - ot->poll = vertex_paint_mode_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* params */ - RNA_def_float( - ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); - RNA_def_float( - ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); -} - -/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc new file mode 100644 index 00000000000..0fb4ded3b2a --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc @@ -0,0 +1,518 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_array.hh" +#include "BLI_index_mask_ops.hh" +#include "BLI_math_base.h" +#include "BLI_math_color.h" +#include "BLI_vector.hh" + +#include "BKE_attribute_math.hh" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_geometry_set.hh" +#include "BKE_mesh.h" + +#include "DEG_depsgraph.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" + +#include "paint_intern.h" /* own include */ + +using blender::Array; +using blender::ColorGeometry4f; +using blender::GMutableSpan; +using blender::IndexMask; +using blender::Vector; + +/* -------------------------------------------------------------------- */ +/** \name Internal Utility Functions + * \{ */ + +static bool vertex_weight_paint_mode_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + return (ob && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) && + (me && me->totpoly && me->dvert); +} + +static void tag_object_after_update(Object *object) +{ + BLI_assert(object->type == OB_MESH); + Mesh *mesh = static_cast<Mesh *>(object->data); + DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE); + /* NOTE: Original mesh is used for display, so tag it directly here. */ + BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Color from Weight Operator + * \{ */ + +static bool vertex_paint_from_weight(Object *ob) +{ + using namespace blender; + + Mesh *me; + if (((me = BKE_mesh_from_object(ob)) == nullptr || + (ED_mesh_color_ensure(me, nullptr)) == false)) { + return false; + } + + const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id); + if (active_color_layer == nullptr) { + BLI_assert_unreachable(); + return false; + } + + const int active_vertex_group_index = me->vertex_group_active_index - 1; + const bDeformGroup *deform_group = static_cast<const bDeformGroup *>( + BLI_findlink(&me->vertex_group_names, active_vertex_group_index)); + if (deform_group == nullptr) { + BLI_assert_unreachable(); + return false; + } + + MeshComponent component; + component.replace(me, GeometryOwnershipType::Editable); + + bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write( + active_color_layer->name); + if (!color_attribute) { + BLI_assert_unreachable(); + return false; + } + + /* Retrieve the vertex group with the domain and type of the existing color + * attribute, in order to let the attribute API handle both conversions. */ + const GVArray vertex_group = component.attribute_get_for_read( + deform_group->name, + ATTR_DOMAIN_POINT, + bke::cpp_type_to_custom_data_type(color_attribute.varray.type())); + if (!vertex_group) { + BLI_assert_unreachable(); + return false; + } + + GVArray_GSpan interpolated{component.attribute_try_adapt_domain( + vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)}; + + color_attribute.varray.set_all(interpolated.data()); + + if (color_attribute.tag_modified_fn) { + color_attribute.tag_modified_fn(); + } + tag_object_after_update(ob); + + return true; +} + +static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + if (vertex_paint_from_weight(obact)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; +} + +void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Color from Weight"; + ot->idname = "PAINT_OT_vertex_color_from_weight"; + ot->description = "Convert active weight into gray scale vertex colors"; + + /* api callback */ + ot->exec = vertex_paint_from_weight_exec; + ot->poll = vertex_weight_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* TODO: invert, alpha */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth Vertex Colors Operator + * \{ */ + +static IndexMask get_selected_indices(const Mesh &mesh, + const eAttrDomain domain, + Vector<int64_t> &indices) +{ + using namespace blender; + Span<MVert> verts(mesh.mvert, mesh.totvert); + Span<MPoly> faces(mesh.mpoly, mesh.totpoly); + + MeshComponent component; + component.replace(&const_cast<Mesh &>(mesh), GeometryOwnershipType::ReadOnly); + + if (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) { + const VArray<bool> selection = component.attribute_try_adapt_domain( + VArray<bool>::ForFunc(faces.size(), + [&](const int i) { return faces[i].flag & ME_FACE_SEL; }), + ATTR_DOMAIN_FACE, + domain); + + return index_mask_ops::find_indices_from_virtual_array( + IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices); + } + if (mesh.editflag & ME_EDIT_PAINT_VERT_SEL) { + const VArray<bool> selection = component.attribute_try_adapt_domain( + VArray<bool>::ForFunc(verts.size(), [&](const int i) { return verts[i].flag & SELECT; }), + ATTR_DOMAIN_POINT, + domain); + + return index_mask_ops::find_indices_from_virtual_array( + IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices); + } + return IndexMask(component.attribute_domain_num(domain)); +} + +static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask selection) +{ + using namespace blender; + + const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id); + if (active_color_layer == nullptr) { + BLI_assert_unreachable(); + return; + } + + MeshComponent component; + component.replace(&mesh, GeometryOwnershipType::Editable); + + if (component.attribute_get_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) { + return; + } + + GVArray color_attribute_point = component.attribute_try_get_for_read(active_color_layer->name, + ATTR_DOMAIN_POINT); + + GVArray color_attribute_corner = component.attribute_try_adapt_domain( + color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER); + + color_attribute_corner.materialize(selection, active_color_layer->data); +} + +static bool vertex_color_smooth(Object *ob) +{ + Mesh *me; + if (((me = BKE_mesh_from_object(ob)) == nullptr) || + (ED_mesh_color_ensure(me, nullptr) == false)) { + return false; + } + + Vector<int64_t> indices; + const IndexMask selection = get_selected_indices(*me, ATTR_DOMAIN_CORNER, indices); + + face_corner_color_equalize_vertices(*me, selection); + + tag_object_after_update(ob); + + return true; +} + +static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + if (vertex_color_smooth(obact)) { + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + return OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; +} + +void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Smooth Vertex Colors"; + ot->idname = "PAINT_OT_vertex_color_smooth"; + ot->description = "Smooth colors across vertices"; + + /* api callbacks */ + ot->exec = vertex_color_smooth_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Color Transformation Operators + * \{ */ + +template<typename TransformFn> +static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn) +{ + using namespace blender; + + const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id); + if (active_color_layer == nullptr) { + BLI_assert_unreachable(); + return false; + } + + MeshComponent component; + component.replace(&mesh, GeometryOwnershipType::Editable); + + bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write( + active_color_layer->name); + if (!color_attribute) { + BLI_assert_unreachable(); + return false; + } + + Vector<int64_t> indices; + const IndexMask selection = get_selected_indices(mesh, color_attribute.domain, indices); + + attribute_math::convert_to_static_type(color_attribute.varray.type(), [&](auto dummy) { + using T = decltype(dummy); + threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + if constexpr (std::is_same_v<T, ColorGeometry4f>) { + ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4f>(i); + transform_fn(color); + color_attribute.varray.set_by_copy(i, &color); + } + else if constexpr (std::is_same_v<T, ColorGeometry4b>) { + ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4b>(i).decode(); + transform_fn(color); + ColorGeometry4b color_encoded = color.encode(); + color_attribute.varray.set_by_copy(i, &color_encoded); + } + } + }); + }); + + DEG_id_tag_update(&mesh.id, 0); + + return true; +} + +static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + float gain, offset; + { + float brightness = RNA_float_get(op->ptr, "brightness"); + float contrast = RNA_float_get(op->ptr, "contrast"); + brightness /= 100.0f; + float delta = contrast / 200.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + if (contrast > 0) { + gain = 1.0f - delta * 2.0f; + gain = 1.0f / max_ff(gain, FLT_EPSILON); + offset = gain * (brightness - delta); + } + else { + delta *= -1; + gain = max_ff(1.0f - delta * 2.0f, 0.0f); + offset = gain * brightness + delta; + } + } + + Mesh *me; + if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) { + return OPERATOR_CANCELLED; + } + + transform_active_color(*me, [&](ColorGeometry4f &color) { + for (int i = 0; i < 3; i++) { + color[i] = gain * color[i] + offset; + } + }); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Vertex Paint Brightness/Contrast"; + ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; + ot->description = "Adjust vertex color brightness/contrast"; + + /* api callbacks */ + ot->exec = vertex_color_brightness_contrast_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + const float min = -100, max = +100; + prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); + prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); + RNA_def_property_ui_range(prop, min, max, 1, 1); +} + +static int vertex_color_hsv_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const float hue = RNA_float_get(op->ptr, "h"); + const float sat = RNA_float_get(op->ptr, "s"); + const float val = RNA_float_get(op->ptr, "v"); + + Mesh *me; + if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) { + return OPERATOR_CANCELLED; + } + + transform_active_color(*me, [&](ColorGeometry4f &color) { + float hsv[3]; + rgb_to_hsv_v(color, hsv); + + hsv[0] += (hue - 0.5f); + if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + else if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + hsv[1] *= sat; + hsv[2] *= val; + + hsv_to_rgb_v(hsv, color); + }); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Hue Saturation Value"; + ot->idname = "PAINT_OT_vertex_color_hsv"; + ot->description = "Adjust vertex color HSV values"; + + /* api callbacks */ + ot->exec = vertex_color_hsv_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); + RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); + RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); +} + +static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + + Mesh *me; + if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) { + return OPERATOR_CANCELLED; + } + + transform_active_color(*me, [&](ColorGeometry4f &color) { + for (int i = 0; i < 3; i++) { + color[i] = 1.0f - color[i]; + } + }); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_vertex_color_invert(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Invert"; + ot->idname = "PAINT_OT_vertex_color_invert"; + ot->description = "Invert RGB values"; + + /* api callbacks */ + ot->exec = vertex_color_invert_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int vertex_color_levels_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const float gain = RNA_float_get(op->ptr, "gain"); + const float offset = RNA_float_get(op->ptr, "offset"); + + Mesh *me; + if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) { + return OPERATOR_CANCELLED; + } + + transform_active_color(*me, [&](ColorGeometry4f &color) { + for (int i = 0; i < 3; i++) { + color[i] = gain * (color[i] + offset); + } + }); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_vertex_color_levels(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Levels"; + ot->idname = "PAINT_OT_vertex_color_levels"; + ot->description = "Adjust levels of vertex colors"; + + /* api callbacks */ + ot->exec = vertex_color_levels_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float( + ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); + RNA_def_float( + ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c deleted file mode 100644 index cd099f71ccd..00000000000 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c +++ /dev/null @@ -1,75 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup edsculpt - * - * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`. - */ - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" - -#include "BLI_math_base.h" -#include "BLI_math_color.h" - -#include "IMB_colormanagement.h" -#include "IMB_imbuf.h" - -#include "BKE_context.h" -#include "BKE_mesh.h" - -#include "DEG_depsgraph.h" - -#include "ED_mesh.h" - -#include "paint_intern.h" /* own include */ - -#define EPS_SATURATION 0.0005f - -bool ED_vpaint_color_transform(struct Object *ob, - VPaintTransform_Callback vpaint_tx_fn, - const void *user_data) -{ - Mesh *me; - const MPoly *mp; - int i, j; - - if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) { - return false; - } - - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - - mp = me->mpoly; - for (i = 0; i < me->totpoly; i++, mp++) { - MLoopCol *lcol = me->mloopcol + mp->loopstart; - - if (use_face_sel && !(mp->flag & ME_FACE_SEL)) { - continue; - } - - j = 0; - do { - uint vidx = me->mloop[mp->loopstart + j].v; - if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) { - float col_mix[3]; - rgb_uchar_to_float(col_mix, &lcol->r); - - vpaint_tx_fn(col_mix, user_data, col_mix); - - rgb_float_to_uchar(&lcol->r, col_mix); - } - lcol++; - j++; - } while (j < mp->totloop); - } - - /* remove stale me->mcol, will be added later */ - BKE_mesh_tessface_clear(me); - - DEG_id_tag_update(&me->id, 0); - - return true; -} diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 2c6c4c82676..0ec75525bc0 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -148,7 +148,7 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index) bool SCULPT_has_loop_colors(const Object *ob) { Mesh *me = BKE_object_get_original_mesh(ob); - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); return layer && BKE_id_attribute_domain(&me->id, layer) == ATTR_DOMAIN_CORNER; } @@ -1181,6 +1181,12 @@ void SCULPT_floodfill_free(SculptFloodFill *flood) /** \} */ +static bool sculpt_tool_has_cube_tip(const char sculpt_tool) +{ + return ELEM( + sculpt_tool, SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_PAINT, SCULPT_TOOL_MULTIPLANE_SCRAPE); +} + /* -------------------------------------------------------------------- */ /** \name Tool Capabilities * @@ -1623,7 +1629,7 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test, const float local[4][4], const float roundness) { - float side = M_SQRT1_2; + float side = 1.0f; float local_co[3]; if (sculpt_brush_test_clipping(test, co)) { @@ -2375,7 +2381,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, /* Get strength by feeding the vertex location directly into a texture. */ avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool); } - else if (ss->texcache) { + else { float symm_point[3], point_2d[2]; /* Quite warnings. */ float x = 0.0f, y = 0.0f; @@ -3110,7 +3116,7 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) for (a = 0; a < me->totvert; a++, mvert++) { copy_v3_v3(mvert->co, vertCos[a]); } - BKE_mesh_normals_tag_dirty(me); + BKE_mesh_tag_coords_changed(me); } /* Apply new coords on active key block, no need to re-allocate kb->data here! */ @@ -3254,6 +3260,11 @@ static void do_brush_action(Sculpt *sd, ss->cache->original; float radius_scale = 1.0f; + /* Corners of square brushes can go outside the brush radius. */ + if (sculpt_tool_has_cube_tip(brush->sculpt_tool)) { + radius_scale = M_SQRT2; + } + /* With these options enabled not all required nodes are inside the original brush radius, so * the brush can produce artifacts in some situations. */ if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) { @@ -3535,15 +3546,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; Sculpt *sd = data->sd; Object *ob = data->ob; - - /* These brushes start from original coordinates. */ - const bool use_orco = ELEM(data->brush->sculpt_tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_ELASTIC_DEFORM, - SCULPT_TOOL_BOUNDARY, - SCULPT_TOOL_POSE); + const bool use_orco = data->use_proxies_orco; PBVHVertexIter vd; PBVHProxyNode *proxies; @@ -3598,12 +3601,23 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) return; } + /* First line is tools that don't support proxies. */ + const bool use_orco = ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_ELASTIC_DEFORM, + SCULPT_TOOL_BOUNDARY, + SCULPT_TOOL_POSE); + BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); + SculptThreadedTaskData data = { .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, + .use_proxies_orco = use_orco, }; TaskParallelSettings settings; @@ -3612,6 +3626,27 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) MEM_SAFE_FREE(nodes); } +void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob) +{ + SculptSession *ss = ob->sculpt; + PBVHNode **nodes; + int totnode; + + BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .nodes = nodes, + .use_proxies_orco = false, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); + + MEM_SAFE_FREE(nodes); +} + /** * Copy the modified vertices from the #PBVH to the active key. */ @@ -3902,27 +3937,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, } } -static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - const int radius = BKE_brush_size_get(scene, brush); - - MEM_SAFE_FREE(ss->texcache); - - if (ss->tex_pool) { - BKE_image_pool_free(ss->tex_pool); - ss->tex_pool = NULL; - } - - /* Need to allocate a bigger buffer for bigger brush size. */ - ss->texcache_side = 2 * radius; - if (!ss->texcache || ss->texcache_side > ss->texcache_actual) { - ss->texcache = BKE_brush_gen_texture_cache(brush, radius, false); - ss->texcache_actual = ss->texcache_side; - ss->tex_pool = BKE_image_pool_new(); - } -} - bool SCULPT_mode_poll(bContext *C) { Object *ob = CTX_data_active_object(C); @@ -4150,7 +4164,7 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache /* Initialize the stroke cache invariants from operator properties. */ static void sculpt_update_cache_invariants( - bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2]) + bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2]) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; @@ -4180,8 +4194,8 @@ static void sculpt_update_cache_invariants( sculpt_init_mirror_clipping(ob, ss); /* Initial mouse location. */ - if (mouse) { - copy_v2_v2(cache->initial_mouse, mouse); + if (mval) { + copy_v2_v2(cache->initial_mouse, mval); } else { zero_v2(cache->initial_mouse); @@ -4319,7 +4333,8 @@ static bool sculpt_needs_delta_from_anchored_origin(Brush *brush) SCULPT_TOOL_POSE, SCULPT_TOOL_BOUNDARY, SCULPT_TOOL_THUMB, - SCULPT_TOOL_ELASTIC_DEFORM)) { + SCULPT_TOOL_ELASTIC_DEFORM, + SCULPT_TOOL_SMEAR)) { return true; } if (brush->sculpt_tool == SCULPT_TOOL_CLOTH && @@ -4349,7 +4364,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru { SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; - const float mouse[2] = { + const float mval[2] = { cache->mouse_event[0], cache->mouse_event[1], }; @@ -4368,6 +4383,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_POSE, SCULPT_TOOL_BOUNDARY, + SCULPT_TOOL_SMEAR, SCULPT_TOOL_THUMB) && !sculpt_brush_use_topology_rake(ss, brush)) { return; @@ -4389,9 +4405,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru add_v3_v3(cache->true_location, cache->grab_delta); } - /* Compute 3d coordinate at same z from original location + mouse. */ + /* Compute 3d coordinate at same z from original location + mval. */ mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location); - ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mouse, grab_location); + ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location); /* Compute delta to move verts by. */ if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { @@ -4759,7 +4775,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t } float SCULPT_raycast_init(ViewContext *vc, - const float mouse[2], + const float mval[2], float ray_start[3], float ray_end[3], float ray_normal[3], @@ -4773,7 +4789,7 @@ float SCULPT_raycast_init(ViewContext *vc, /* TODO: what if the segment is totally clipped? (return == 0). */ ED_view3d_win_to_segment_clipped( - vc->depsgraph, vc->region, vc->v3d, mouse, ray_start, ray_end, true); + vc->depsgraph, vc->region, vc->v3d, mval, ray_start, ray_end, true); invert_m4_m4(obimat, ob->obmat); mul_m4_v3(obimat, ray_start); @@ -4797,7 +4813,7 @@ float SCULPT_raycast_init(ViewContext *vc, bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, - const float mouse[2], + const float mval[2], bool use_sampled_normal) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); @@ -4826,7 +4842,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C, } /* PBVH raycast to get active vertex and face normal. */ - depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original); + depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original); SCULPT_stroke_modifiers_check(C, ob, brush); SculptRaycastData srd = { @@ -4924,7 +4940,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C, return true; } -bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2]) +bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2]) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Object *ob; @@ -4946,7 +4962,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2]) SCULPT_stroke_modifiers_check(C, ob, brush); - depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original); + depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original); if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { BM_mesh_elem_table_ensure(ss->bm, BM_VERT); @@ -5003,7 +5019,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2]) return hit; } -static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) +static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss) { Brush *brush = BKE_paint_brush(&sd->paint); MTex *mtex = &brush->mtex; @@ -5014,14 +5030,13 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession ntreeTexBeginExecTree(mtex->tex->nodetree); } - /* TODO: Shouldn't really have to do this at the start of every stroke, but sculpt would need - * some sort of notification when changes are made to the texture. */ - sculpt_update_tex(scene, sd, ss); + if (ss->tex_pool == NULL) { + ss->tex_pool = BKE_image_pool_new(); + } } static void sculpt_brush_stroke_init(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; @@ -5040,7 +5055,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op) } view3d_operator_needs_opengl(C); - sculpt_brush_init_tex(scene, sd, ss); + sculpt_brush_init_tex(sd, ss); need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, mode); needs_colors = SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool); @@ -5251,14 +5266,10 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up /* Returns whether the mouse/stylus is over the mesh (1) * or over the background (0). */ -static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), float x, float y) +static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2]) { - float mouse[2], co[3]; - - mouse[0] = x; - mouse[1] = y; - - return SCULPT_stroke_get_location(C, co, mouse); + float co_dummy[3]; + return SCULPT_stroke_get_location(C, co_dummy, mval); } bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports) @@ -5279,14 +5290,13 @@ bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports) return false; } -static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2]) +static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mval[2]) { - /* Don't start the stroke until mouse goes over the mesh. - * NOTE: mouse will only be null when re-executing the saved stroke. - * We have exception for 'exec' strokes since they may not set 'mouse', + /* Don't start the stroke until `mval` goes over the mesh. + * NOTE: `mval` will only be null when re-executing the saved stroke. + * We have exception for 'exec' strokes since they may not set `mval`, * only 'location', see: T52195. */ - if (((op->flag & OP_IS_INVOKE) == 0) || (mouse == NULL) || - over_mesh(C, op, mouse[0], mouse[1])) { + if (((op->flag & OP_IS_INVOKE) == 0) || (mval == NULL) || over_mesh(C, op, mval)) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -5304,10 +5314,10 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C)); - sculpt_update_cache_invariants(C, sd, ss, op, mouse); + sculpt_update_cache_invariants(C, sd, ss, op, mval); SculptCursorGeometryInfo sgi; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + SCULPT_cursor_geometry_info_update(C, &sgi, mval, false); /* Setup the correct undo system. Image painting and sculpting are mutual exclusive. * Color attributes are part of the sculpting undo system. */ @@ -5499,7 +5509,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent /* For tablet rotation. */ ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click"); - if (ignore_background_click && !over_mesh(C, op, event->xy[0], event->xy[1])) { + if (ignore_background_click && !over_mesh(C, op, (const float[2]){UNPACK2(event->mval)})) { paint_stroke_free(C, op, op->customdata); return OPERATOR_PASS_THROUGH; } @@ -5759,7 +5769,8 @@ void SCULPT_connected_components_ensure(Object *ob) { SculptSession *ss = ob->sculpt; - /* Topology IDs already initialized. They only need to be recalculated when the PBVH is rebuild. + /* Topology IDs already initialized. They only need to be recalculated when the PBVH is + * rebuild. */ if (ss->vertex_info.connected_component) { return; @@ -5823,7 +5834,8 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist) SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); - /* Fake neighbors were already initialized with the same distance, so no need to be recalculated. + /* Fake neighbors were already initialized with the same distance, so no need to be + * recalculated. */ if (ss->fake_neighbors.fake_neighbor_index && ss->fake_neighbors.current_max_distance == max_dist) { diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index d7a2a18504c..bb101717c9b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -9,6 +9,7 @@ #include "BLI_blenlib.h" #include "BLI_hash.h" +#include "BLI_index_range.hh" #include "BLI_math.h" #include "BLI_task.h" @@ -43,8 +44,10 @@ #include "bmesh.h" -#include <math.h> -#include <stdlib.h> +#include <cmath> +#include <cstdlib> + +using blender::IndexRange; AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss) { @@ -54,7 +57,7 @@ AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss) if (ss->filter_cache) { return ss->filter_cache->automasking; } - return NULL; + return nullptr; } bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, @@ -167,18 +170,18 @@ static bool sculpt_automasking_is_constrained_by_radius(Brush *br) return false; } -typedef struct AutomaskFloodFillData { +struct AutomaskFloodFillData { float *automask_factor; float radius; bool use_radius; float location[3]; char symm; -} AutomaskFloodFillData; +}; static bool automask_floodfill_cb( SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) { - AutomaskFloodFillData *data = userdata; + AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata; data->automask_factor[to_v] = 1.0f; data->automask_factor[from_v] = 1.0f; @@ -194,11 +197,11 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { BLI_assert_msg(0, "Topology masking: pmap missing"); - return NULL; + return nullptr; } const int totvert = SCULPT_vertex_count_get(ss); - for (int i = 0; i < totvert; i++) { + for (int i : IndexRange(totvert)) { automask_factor[i] = 0.0f; } @@ -209,12 +212,13 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au const float radius = ss->cache ? ss->cache->radius : FLT_MAX; SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius); - AutomaskFloodFillData fdata = { - .automask_factor = automask_factor, - .radius = radius, - .use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush), - .symm = SCULPT_mesh_symmetry_xyz_get(ob), - }; + AutomaskFloodFillData fdata = {nullptr}; + + fdata.automask_factor = automask_factor; + fdata.radius = radius; + fdata.use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush); + fdata.symm = SCULPT_mesh_symmetry_xyz_get(ob); + copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss)); SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata); SCULPT_floodfill_free(&flood); @@ -228,17 +232,17 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a Brush *brush = BKE_paint_brush(&sd->paint); if (!SCULPT_is_automasking_enabled(sd, ss, brush)) { - return NULL; + return nullptr; } if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { BLI_assert_msg(0, "Face Sets automasking: pmap missing"); - return NULL; + return nullptr; } int tot_vert = SCULPT_vertex_count_get(ss); int active_face_set = SCULPT_active_face_set_get(ss); - for (int i = 0; i < tot_vert; i++) { + for (int i : IndexRange(tot_vert)) { if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { automask_factor[i] *= 0.0f; } @@ -258,13 +262,13 @@ float *SCULPT_boundary_automasking_init(Object *ob, if (!ss->pmap) { BLI_assert_msg(0, "Boundary Edges masking: pmap missing"); - return NULL; + return nullptr; } const int totvert = SCULPT_vertex_count_get(ss); - int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor"); + int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor"); - for (int i = 0; i < totvert; i++) { + for (int i : IndexRange(totvert)) { edge_distance[i] = EDGE_DISTANCE_INF; switch (mode) { case AUTOMASK_INIT_BOUNDARY_EDGES: @@ -280,8 +284,8 @@ float *SCULPT_boundary_automasking_init(Object *ob, } } - for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) { - for (int i = 0; i < totvert; i++) { + for (int propagation_it : IndexRange(propagation_steps)) { + for (int i : IndexRange(totvert)) { if (edge_distance[i] != EDGE_DISTANCE_INF) { continue; } @@ -295,7 +299,7 @@ float *SCULPT_boundary_automasking_init(Object *ob, } } - for (int i = 0; i < totvert; i++) { + for (int i : IndexRange(totvert)) { if (edge_distance[i] == EDGE_DISTANCE_INF) { continue; } @@ -323,10 +327,11 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object const int totvert = SCULPT_vertex_count_get(ss); if (!SCULPT_is_automasking_enabled(sd, ss, brush)) { - return NULL; + return nullptr; } - AutomaskingCache *automasking = MEM_callocN(sizeof(AutomaskingCache), "automasking cache"); + AutomaskingCache *automasking = (AutomaskingCache *)MEM_callocN(sizeof(AutomaskingCache), + "automasking cache"); SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush); SCULPT_boundary_info_ensure(ob); @@ -334,8 +339,8 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object return automasking; } - automasking->factor = MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor"); - for (int i = 0; i < totvert; i++) { + automasking->factor = (float *)MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor"); + for (int i : IndexRange(totvert)) { automasking->factor[i] = 1.0f; } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index dcf90f9e819..9d231f2ccd2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -1553,11 +1553,9 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent const eSculptClothFilterType filter_type = RNA_enum_get(op->ptr, "type"); /* Update the active vertex */ - float mouse[2]; + float mval_fl[2] = {UNPACK2(event->mval)}; SculptCursorGeometryInfo sgi; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); SCULPT_vertex_random_access_ensure(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index fe69cf6b84f..00503087e39 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -158,7 +158,7 @@ static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = { {0, NULL, 0, NULL, NULL}, }; -static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my) +static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2]) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Object *ob = vc->obact; @@ -169,8 +169,8 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my) SCULPT_vertex_random_access_ensure(ss); /* Update the active vertex. */ - const float mouse[2] = {mx, my}; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + const float mval_fl[2] = {UNPACK2(mval)}; + SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); /* Average the edge length of the connected edges to the active vertex. */ @@ -201,7 +201,7 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin) } } -static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my) +static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2]) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Object *ob = vc->obact; @@ -209,9 +209,9 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, SCULPT_stroke_modifiers_check(C, ob, brush); - const float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; + const float mval_fl[2] = {UNPACK2(mval)}; float ray_start[3], ray_end[3], ray_normal[3]; - float depth = SCULPT_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false); + float depth = SCULPT_raycast_init(vc, mval_fl, ray_start, ray_end, ray_normal, false); SculptDetailRaycastData srd; srd.hit = 0; @@ -228,14 +228,12 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, } } -static int sample_detail(bContext *C, int mx, int my, int mode) +static int sample_detail(bContext *C, const int event_xy[2], int mode) { /* Find 3D view to pick from. */ bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my}); - ARegion *region = (area) ? - BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) : - NULL; + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, event_xy); + ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy) : NULL; if (region == NULL) { return OPERATOR_CANCELLED; } @@ -260,6 +258,11 @@ static int sample_detail(bContext *C, int mx, int my, int mode) return OPERATOR_CANCELLED; } + const int mval[2] = { + event_xy[0] - region->winrct.xmin, + event_xy[1] - region->winrct.ymin, + }; + /* Pick sample detail. */ switch (mode) { case SAMPLE_DETAIL_DYNTOPO: @@ -268,7 +271,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode) CTX_wm_region_set(C, prev_region); return OPERATOR_CANCELLED; } - sample_detail_dyntopo(C, &vc, region, mx, my); + sample_detail_dyntopo(C, &vc, mval); break; case SAMPLE_DETAIL_VOXEL: if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { @@ -276,7 +279,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode) CTX_wm_region_set(C, prev_region); return OPERATOR_CANCELLED; } - sample_detail_voxel(C, &vc, mx, my); + sample_detail_voxel(C, &vc, mval); break; } @@ -292,7 +295,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op) int ss_co[2]; RNA_int_get_array(op->ptr, "location", ss_co); int mode = RNA_enum_get(op->ptr, "mode"); - return sample_detail(C, ss_co[0], ss_co[1], mode); + return sample_detail(C, ss_co, mode); } static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e)) @@ -308,12 +311,10 @@ static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wm switch (event->type) { case LEFTMOUSE: if (event->val == KM_PRESS) { - const int ss_co[2] = {event->xy[0], event->xy[1]}; - int mode = RNA_enum_get(op->ptr, "mode"); - sample_detail(C, ss_co[0], ss_co[1], mode); + sample_detail(C, event->xy, mode); - RNA_int_set_array(op->ptr, "location", ss_co); + RNA_int_set_array(op->ptr, "location", event->xy); WM_cursor_modal_restore(CTX_wm_window(C)); ED_workspace_status_text(C, NULL); WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); @@ -657,11 +658,13 @@ static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmE ED_region_tag_redraw(region); - if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) { - cd->sample_mode = true; - } - if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) { - cd->sample_mode = false; + if (ELEM(event->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) { + if (event->val == KM_PRESS) { + cd->sample_mode = true; + } + else if (event->val == KM_RELEASE) { + cd->sample_mode = false; + } } /* Sample mode sets the detail size sampling the average edge length under the surface. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 644f14905ba..fbf988d63e8 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -1450,13 +1450,11 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v * Updates the #SculptSession cursor data and gets the active vertex * if the cursor is over the mesh. */ -static int sculpt_expand_target_vertex_update_and_get(bContext *C, - Object *ob, - const float mouse[2]) +static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const float mval[2]) { SculptSession *ss = ob->sculpt; SculptCursorGeometryInfo sgi; - if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) { + if (SCULPT_cursor_geometry_info_update(C, &sgi, mval, false)) { return SCULPT_active_vertex_get(ss); } return SCULPT_EXPAND_VERTEX_NONE; @@ -1588,16 +1586,16 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob, static void sculpt_expand_set_initial_components_for_mouse(bContext *C, Object *ob, ExpandCache *expand_cache, - const float mouse[2]) + const float mval[2]) { SculptSession *ss = ob->sculpt; - int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse); + int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval); if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) { /* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active * vertex in the sculpt session. */ initial_vertex = SCULPT_active_vertex_get(ss); } - copy_v2_v2(ss->expand_cache->initial_mouse, mouse); + copy_v2_v2(ss->expand_cache->initial_mouse, mval); expand_cache->initial_active_vertex = initial_vertex; expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss); @@ -1629,14 +1627,14 @@ static void sculpt_expand_move_propagation_origin(bContext *C, { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - const float mouse[2] = {event->mval[0], event->mval[1]}; + const float mval_fl[2] = {UNPACK2(event->mval)}; float move_disp[2]; - sub_v2_v2v2(move_disp, mouse, expand_cache->initial_mouse_move); + sub_v2_v2v2(move_disp, mval_fl, expand_cache->initial_mouse_move); - float new_mouse[2]; - add_v2_v2v2(new_mouse, move_disp, expand_cache->original_mouse_move); + float new_mval[2]; + add_v2_v2v2(new_mval, move_disp, expand_cache->original_mouse_move); - sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mouse); + sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mval); sculpt_expand_falloff_factors_from_vertex_and_symm_create( expand_cache, sd, @@ -1697,8 +1695,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event sculpt_expand_ensure_sculptsession_data(ob); /* Update and get the active vertex (and face) from the cursor. */ - const float mouse[2] = {event->mval[0], event->mval[1]}; - const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse); + const float mval_fl[2] = {UNPACK2(event->mval)}; + const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval_fl); /* Handle the modal keymap state changes. */ ExpandCache *expand_cache = ss->expand_cache; @@ -1756,7 +1754,7 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event } expand_cache->move = true; expand_cache->move_original_falloff_type = expand_cache->falloff_type; - copy_v2_v2(expand_cache->initial_mouse_move, mouse); + copy_v2_v2(expand_cache->initial_mouse_move, mval_fl); copy_v2_v2(expand_cache->original_mouse_move, expand_cache->initial_mouse); if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_GEODESIC && SCULPT_vertex_count_get(ss) > expand_cache->max_geodesic_move_preview) { diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index d03c5ecab4d..ce704e619ea 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -949,11 +949,9 @@ static int sculpt_face_sets_change_visibility_invoke(bContext *C, /* Update the active vertex and Face Set using the cursor position to avoid relying on the paint * cursor updates. */ SculptCursorGeometryInfo sgi; - float mouse[2]; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; + const float mval_fl[2] = {UNPACK2(event->mval)}; SCULPT_vertex_random_access_ensure(ss); - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); return sculpt_face_sets_change_visibility_exec(C, op); } @@ -1401,8 +1399,8 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven /* Update the current active Face Set and Vertex as the operator can be used directly from the * tool without brush cursor. */ SculptCursorGeometryInfo sgi; - const float mouse[2] = {event->mval[0], event->mval[1]}; - if (!SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) { + const float mval_fl[2] = {UNPACK2(event->mval)}; + if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) { /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */ return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index 26d18823b37..95c01d24c6d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -339,11 +339,9 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent if (use_automasking) { /* Update the active face set manually as the paint cursor is not enabled when using the Mesh * Filter Tool. */ - float mouse[2]; + float mval_fl[2] = {UNPACK2(event->mval)}; SculptCursorGeometryInfo sgi; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); } /* Disable for multires and dyntopo for now */ @@ -378,7 +376,7 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot) /* identifiers */ ot->name = "Filter Color"; ot->idname = "SCULPT_OT_color_filter"; - ot->description = "Applies a filter to modify the current sculpt vertex colors"; + ot->description = "Applies a filter to modify the active color attribute"; /* api callbacks */ ot->invoke = sculpt_color_filter_invoke; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index a32b1c3015b..dbed5624adf 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -675,11 +675,9 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent if (use_automasking) { /* Update the active face set manually as the paint cursor is not enabled when using the Mesh * Filter Tool. */ - float mouse[2]; + float mval_fl[2] = {UNPACK2(event->mval)}; SculptCursorGeometryInfo sgi; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); } SCULPT_vertex_random_access_ensure(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 5fa115ed629..fe96257dc01 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -247,6 +247,10 @@ typedef struct SculptThreadedTaskData { float (*mat)[4]; float (*vertCos)[3]; + /* When true, the displacement stored in the proxies will be aplied to the original coordinates + * instead of to the current coordinates. */ + bool use_proxies_orco; + /* X and Z vectors aligned to the stroke direction for operations where perpendicular vectors to * the stroke direction are needed. */ float (*stroke_xz)[3]; @@ -290,6 +294,10 @@ typedef struct SculptThreadedTaskData { bool mask_expand_create_face_set; float transform_mats[8][4][4]; + float elastic_transform_mat[4][4]; + float elastic_transform_pivot[3]; + float elastic_transform_pivot_init[3]; + float elastic_transform_radius; /* Boundary brush */ float boundary_deform_strength; @@ -372,6 +380,14 @@ typedef enum SculptFilterOrientation { SCULPT_FILTER_ORIENTATION_VIEW = 2, } SculptFilterOrientation; +/* Defines how transform tools are going to apply its displacement. */ +typedef enum SculptTransformDisplacementMode { + /* Displaces the elements from their original coordinates. */ + SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL = 0, + /* Displaces the elements incrementally from their previous position. */ + SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1, +} SculptTransformDisplacementMode; + #define SCULPT_CLAY_STABILIZER_LEN 10 typedef struct AutomaskingSettings { @@ -440,6 +456,8 @@ typedef struct FilterCache { int active_face_set; + SculptTransformDisplacementMode transform_displacement_mode; + /* Auto-masking. */ AutomaskingCache *automasking; @@ -840,7 +858,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush); float SCULPT_raycast_init(struct ViewContext *vc, - const float mouse[2], + const float mval[2], float ray_start[3], float ray_end[3], float ray_normal[3], @@ -1137,12 +1155,15 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v); */ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v); +void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob); + /** * Initialize a point-in-brush test with a given falloff shape. * * \param falloff_shape: #PAINT_FALLOFF_SHAPE_SPHERE or #PAINT_FALLOFF_SHAPE_TUBE. * \return The brush falloff function. */ + SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss, SculptBrushTest *test, char falloff_shape); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 201e02b8235..4593c6a8b60 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -167,10 +167,8 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * if (RNA_boolean_get(op->ptr, "use_cursor")) { SculptCursorGeometryInfo sgi; - float mouse[2]; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) { + const float mval_fl[2] = {UNPACK2(event->mval)}; + if (SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) { /* The cursor is over the mesh, get the update iteration from the updated active vertex. */ mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)]; } @@ -340,16 +338,14 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set"); SculptCursorGeometryInfo sgi; - float mouse[2]; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; + const float mval_fl[2] = {UNPACK2(event->mval)}; SCULPT_vertex_random_access_ensure(ss); op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position"); - copy_v2_v2(op->customdata, mouse); + copy_v2_v2(op->customdata, mval_fl); - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index dc620f0ee93..f16763be735 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -84,6 +84,7 @@ #include "WM_toolsystem.h" #include "WM_types.h" +#include "ED_image.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_sculpt.h" @@ -349,7 +350,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain, Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT); BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT); - paint_cursor_start(paint, SCULPT_mode_poll_view3d); + ED_paint_cursor_start(paint, SCULPT_mode_poll_view3d); /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, * As long as no data was added that is not supported. */ @@ -1060,10 +1061,8 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, * so it needs to be updated here. */ SculptCursorGeometryInfo sgi; - float mouse[2]; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + 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"); BKE_sculpt_color_layer_create_if_needed(ob); @@ -1098,7 +1097,7 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot) /* identifiers */ ot->name = "Mask by Color"; ot->idname = "SCULPT_OT_mask_by_color"; - ot->description = "Creates a mask based on the sculpt vertex colors"; + ot->description = "Creates a mask based on the active color attribute"; /* api callbacks */ ot->invoke = sculpt_mask_by_color_invoke; diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index ac05652b058..fa9f24377da 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -380,6 +380,15 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + float brush_delta[3]; + + if (brush->flag & BRUSH_ANCHORED) { + copy_v3_v3(brush_delta, ss->cache->grab_delta_symmetry); + } + else { + sub_v3_v3v3(brush_delta, ss->cache->location, ss->cache->last_location); + } + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -404,7 +413,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, switch (brush->smear_deform_type) { case BRUSH_SMEAR_DEFORM_DRAG: - sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + copy_v3_v3(current_disp, brush_delta); break; case BRUSH_SMEAR_DEFORM_PINCH: sub_v3_v3v3(current_disp, ss->cache->location, vd.co); @@ -529,12 +538,10 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode const int totvert = SCULPT_vertex_count_get(ss); - if (SCULPT_stroke_is_first_brush_step(ss->cache)) { - if (!ss->cache->prev_colors) { - ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors"); - for (int i = 0; i < totvert; i++) { - SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]); - } + if (!ss->cache->prev_colors) { + ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors"); + for (int i = 0; i < totvert; i++) { + SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index b3616254b26..48033f3407e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -16,6 +16,7 @@ #include "BKE_brush.h" #include "BKE_context.h" +#include "BKE_kelvinlet.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_object.h" @@ -33,6 +34,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_sculpt.h" +#include "ED_view3d.h" #include "paint_intern.h" #include "sculpt_intern.h" @@ -54,6 +56,10 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob) copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot); copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale); + copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos); + 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"); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); @@ -61,10 +67,18 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob) SCULPT_vertex_random_access_ensure(ss); SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); + + if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) { + ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL; + } + else { + ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL; + } } static void sculpt_transform_matrices_init(SculptSession *ss, const char symm, + const SculptTransformDisplacementMode t_mode, float r_transform_mats[8][4][4]) { @@ -73,9 +87,18 @@ static void sculpt_transform_matrices_init(SculptSession *ss, transform_mat[4][4]; float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3]; - copy_v3_v3(start_pivot_pos, ss->init_pivot_pos); - copy_v4_v4(start_pivot_rot, ss->init_pivot_rot); - copy_v3_v3(start_pivot_scale, ss->init_pivot_scale); + switch (t_mode) { + case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL: + copy_v3_v3(start_pivot_pos, ss->init_pivot_pos); + copy_v4_v4(start_pivot_rot, ss->init_pivot_rot); + copy_v3_v3(start_pivot_scale, ss->init_pivot_scale); + break; + case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL: + copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos); + copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot); + copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale); + break; + } for (int i = 0; i < PAINT_SYMM_AREAS; i++) { ePaintSymmetryAreas v_symm = i; @@ -134,16 +157,26 @@ static void sculpt_transform_task_cb(void *__restrict userdata, SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); + float *start_co; float transformed_co[3], orig_co[3], disp[3]; float fade = vd.mask ? *vd.mask : 0.0f; copy_v3_v3(orig_co, orig_data.co); char symm_area = SCULPT_get_vertex_symm_area(orig_co); - copy_v3_v3(transformed_co, orig_co); + switch (ss->filter_cache->transform_displacement_mode) { + case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL: + start_co = orig_co; + break; + case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL: + start_co = vd.co; + break; + } + + copy_v3_v3(transformed_co, start_co); mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co); - sub_v3_v3v3(disp, transformed_co, orig_co); + sub_v3_v3v3(disp, transformed_co, start_co); mul_v3_fl(disp, 1.0f - fade); - add_v3_v3v3(vd.co, orig_co, disp); + add_v3_v3v3(vd.co, start_co, disp); if (vd.mvert) { BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); @@ -165,7 +198,8 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob) .nodes = ss->filter_cache->nodes, }; - sculpt_transform_matrices_init(ss, symm, data.transform_mats); + sculpt_transform_matrices_init( + ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats); /* Regular transform applies all symmetry passes at once as it is split by symmetry areas * (each vertex can only be transformed once by the transform matrix of its area). */ @@ -175,6 +209,98 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob) 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings); } +static void sculpt_elastic_transform_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + + float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[i])->co; + + SculptOrigVertData orig_data; + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]); + + KelvinletParams params; + /* TODO(pablodp606): These parameters can be exposed if needed as transform strength and volume + * preservation like in the elastic deform brushes. Setting them to the same default as elastic + * deform triscale grab because they work well in most cases. */ + const float force = 1.0f; + const float shear_modulus = 1.0f; + const float poisson_ratio = 0.4f; + BKE_kelvinlet_init_params( + ¶ms, data->elastic_transform_radius, force, shear_modulus, poisson_ratio); + + SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + float transformed_co[3], orig_co[3], disp[3]; + const float fade = vd.mask ? *vd.mask : 0.0f; + copy_v3_v3(orig_co, orig_data.co); + + copy_v3_v3(transformed_co, vd.co); + mul_m4_v3(data->elastic_transform_mat, transformed_co); + sub_v3_v3v3(disp, transformed_co, vd.co); + + float final_disp[3]; + BKE_kelvinlet_grab_triscale(final_disp, ¶ms, vd.co, data->elastic_transform_pivot, disp); + mul_v3_fl(final_disp, 20.0f * (1.0f - fade)); + + copy_v3_v3(proxy[vd.i], final_disp); + + if (vd.mvert) { + BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + } + } + BKE_pbvh_vertex_iter_end; + + BKE_pbvh_node_mark_update(node); +} + +static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float transform_radius) +{ + SculptSession *ss = ob->sculpt; + BLI_assert(ss->filter_cache->transform_displacement_mode == + SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL); + + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .nodes = ss->filter_cache->nodes, + .elastic_transform_radius = transform_radius, + }; + + sculpt_transform_matrices_init( + ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats); + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); + + /* Elastic transform needs to apply all transform matrices to all vertices and then combine the + * displacement proxies as all vertices are modified by all symmetry passes. */ + for (ePaintSymmetryFlags symmpass = 0; symmpass <= symm; symmpass++) { + if (SCULPT_is_symmetry_iteration_valid(symmpass, symm)) { + flip_v3_v3(data.elastic_transform_pivot, ss->pivot_pos, symmpass); + flip_v3_v3(data.elastic_transform_pivot_init, ss->init_pivot_pos, symmpass); + + printf( + "%.2f %.2f %.2f\n", ss->init_pivot_pos[0], ss->init_pivot_pos[1], ss->init_pivot_pos[2]); + + const int symm_area = SCULPT_get_vertex_symm_area(data.elastic_transform_pivot); + copy_m4_m4(data.elastic_transform_mat, data.transform_mats[symm_area]); + BLI_task_parallel_range( + 0, ss->filter_cache->totnode, &data, sculpt_elastic_transform_task_cb, &settings); + } + } + SCULPT_combine_transform_proxies(sd, ob); +} + void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -184,7 +310,36 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob) SCULPT_vertex_random_access_ensure(ss); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - sculpt_transform_all_vertices(sd, ob); + switch (sd->transform_mode) { + case SCULPT_TRANSFORM_MODE_ALL_VERTICES: { + sculpt_transform_all_vertices(sd, ob); + break; + } + case SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC: { + Brush *brush = BKE_paint_brush(&sd->paint); + Scene *scene = CTX_data_scene(C); + float transform_radius; + + if (BKE_brush_use_locked_size(scene, brush)) { + transform_radius = BKE_brush_unprojected_radius_get(scene, brush); + } + else { + ViewContext vc; + + ED_view3d_viewcontext_init(C, &vc, depsgraph); + + transform_radius = paint_calc_object_space_radius( + &vc, ss->init_pivot_pos, BKE_brush_size_get(scene, brush)); + } + + sculpt_transform_radius_elastic(sd, ob, transform_radius); + break; + } + } + + copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos); + copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot); + copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale); if (ss->deform_modifiers_active || ss->shapekey_active) { SCULPT_flush_stroke_deform(sd, ob, true); @@ -267,10 +422,11 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op) /* Pivot to ray-cast surface. */ else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) { float stroke_location[3]; - float mouse[2]; - mouse[0] = RNA_float_get(op->ptr, "mouse_x"); - mouse[1] = RNA_float_get(op->ptr, "mouse_y"); - if (SCULPT_stroke_get_location(C, stroke_location, mouse)) { + const float mval[2] = { + RNA_float_get(op->ptr, "mouse_x"), + RNA_float_get(op->ptr, "mouse_y"), + }; + if (SCULPT_stroke_get_location(C, stroke_location, mval)) { copy_v3_v3(ss->pivot_pos, stroke_location); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 1fee20444e7..f50e942f795 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -50,6 +50,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_geometry.h" #include "ED_object.h" #include "ED_sculpt.h" #include "ED_undo.h" @@ -105,7 +106,7 @@ typedef struct UndoSculpt { } UndoSculpt; typedef struct SculptAttrRef { - AttributeDomain domain; + eAttrDomain domain; int type; char name[MAX_CUSTOMDATA_LAYER_NAME]; bool was_set; @@ -854,7 +855,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase if (tag_update) { Mesh *mesh = ob->data; - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(mesh); BKE_sculptsession_free_deformMats(ss); } @@ -1464,7 +1465,7 @@ static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b) static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr) { Mesh *me = BKE_object_get_original_mesh(ob); - CustomDataLayer *layer; + const CustomDataLayer *layer; if (ob && me && (layer = BKE_id_attributes_active_color_get((ID *)me))) { attr->domain = BKE_id_attribute_domain((ID *)me, layer); @@ -1565,6 +1566,24 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr CustomDataLayer *layer; layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); + /* Temporary fix for T97408. This is a fundamental + * bug in the undo stack; the operator code needs to push + * an extra undo step before running an operator if a + * non-memfile undo system is active. + * + * For now, detect if the layer does exist but with a different + * domain and just unconvert it. + */ + 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) { /* Memfile undo killed the layer; re-create it. */ CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata; diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 87e88d094d7..cf7c3b51ae3 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -102,6 +102,16 @@ bool ED_space_clip_maskedit_poll(bContext *C) return false; } +bool ED_space_clip_maskedit_visible_splines_poll(bContext *C) +{ + if (!ED_space_clip_maskedit_poll(C)) { + return false; + } + + const SpaceClip *space_clip = CTX_wm_space_clip(C); + return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE; +} + bool ED_space_clip_maskedit_mask_poll(bContext *C) { if (ED_space_clip_maskedit_poll(C)) { @@ -117,6 +127,16 @@ bool ED_space_clip_maskedit_mask_poll(bContext *C) return false; } +bool ED_space_clip_maskedit_mask_visible_splines_poll(bContext *C) +{ + if (!ED_space_clip_maskedit_mask_poll(C)) { + return false; + } + + const SpaceClip *space_clip = CTX_wm_space_clip(C); + return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -272,7 +292,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc, return true; } -bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3]) +bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, const int mval[2], float r_col[3]) { ImBuf *ibuf; float fx, fy, co[2]; diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index e61c264ca06..f5bf850791a 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -777,7 +777,7 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* flags */ - ot->flag |= OPTYPE_LOCK_BYPASS; + ot->flag = OPTYPE_LOCK_BYPASS; /* properties */ prop = RNA_def_float_vector(ot->srna, @@ -834,7 +834,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* flags */ - ot->flag |= OPTYPE_LOCK_BYPASS; + ot->flag = OPTYPE_LOCK_BYPASS; /* properties */ prop = RNA_def_float_vector(ot->srna, @@ -883,7 +883,7 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* flags */ - ot->flag |= OPTYPE_LOCK_BYPASS; + ot->flag = OPTYPE_LOCK_BYPASS; /* properties */ RNA_def_float(ot->srna, diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 5f52e1a3071..a73883e7624 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -860,6 +860,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region) sc->mask_info.draw_flag, sc->mask_info.draw_type, sc->mask_info.overlay_mode, + sc->mask_info.blend_factor, mask_width, mask_height, aspx, diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index bbfbbd2cc58..28e304bfa74 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -394,8 +394,6 @@ static int select_exec(bContext *C, wmOperator *op) else if (deselect_all) { ed_tracking_deselect_all_tracks(tracksbase); ed_tracking_deselect_all_plane_tracks(plane_tracks_base); - /* Mask as well if we are in combined mask / track view. */ - ED_mask_deselect_all(C); } ED_clip_view_lock_state_restore_no_jump(C, &lock_state); diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index e5a4919f548..87595ecdb88 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -407,8 +407,15 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr std::string basic_tip = is_multiple_assets ? TIP_("Move assets to catalog") : TIP_("Move asset to catalog"); - return basic_tip + ": " + catalog_item_.get_name() + " (" + catalog_item_.catalog_path().str() + - ")"; + basic_tip += ": " + catalog_item_.get_name(); + + /* Display the full catalog path, but only if it's not exactly the same as the already shown name + * (i.e. not a root level catalog with no parent). */ + if (catalog_item_.get_name() != catalog_item_.catalog_path().str()) { + basic_tip += " (" + catalog_item_.catalog_path().str() + ")"; + } + + return basic_tip; } bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag) diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 1ee6445f4ba..655a7983e2b 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -83,6 +83,7 @@ void FILE_OT_rename(struct wmOperatorType *ot); void FILE_OT_smoothscroll(struct wmOperatorType *ot); void FILE_OT_filepath_drop(struct wmOperatorType *ot); void FILE_OT_start_filter(struct wmOperatorType *ot); +void FILE_OT_edit_directory_path(struct wmOperatorType *ot); void FILE_OT_view_selected(struct wmOperatorType *ot); void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 578288ca289..62bdd583bc1 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2914,9 +2914,9 @@ void FILE_OT_delete(struct wmOperatorType *ot) static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op)) { - ScrArea *area = CTX_wm_area(C); - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_active_params(sfile); + const ScrArea *area = CTX_wm_area(C); + const SpaceFile *sfile = CTX_wm_space_file(C); + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); ARegion *region_ctx = CTX_wm_region(C); @@ -2950,6 +2950,46 @@ void FILE_OT_start_filter(struct wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Edit Directory Path Operator + * \{ */ + +static int file_edit_directory_path_exec(bContext *C, wmOperator *UNUSED(op)) +{ + const ScrArea *area = CTX_wm_area(C); + const SpaceFile *sfile = CTX_wm_space_file(C); + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); + + ARegion *region_ctx = CTX_wm_region(C); + + if (area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + CTX_wm_region_set(C, region); + if (UI_textbutton_activate_rna(C, region, params, "directory")) { + break; + } + } + } + + CTX_wm_region_set(C, region_ctx); + + return OPERATOR_FINISHED; +} + +void FILE_OT_edit_directory_path(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Edit Directory Path"; + ot->description = "Start editing directory field"; + ot->idname = "FILE_OT_edit_directory_path"; + + /* api callbacks */ + ot->exec = file_edit_directory_path_exec; + ot->poll = ED_operator_file_active; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Macro Operators * \{ */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index cfbbc1a1b45..183af0c14f5 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2803,7 +2803,7 @@ int ED_path_extension_type(const char *path) return FILE_TYPE_ARCHIVE; } if (BLI_path_extension_check_n( - path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) { + path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", ".stl", NULL)) { return FILE_TYPE_OBJECT_IO; } if (BLI_path_extension_check_array(path, imb_ext_image)) { @@ -3075,7 +3075,7 @@ static int filelist_readjob_list_dir(const char *root, } target = entry->redirection_path; #ifdef WIN32 - /* On Windows don't show ".lnk" extension for valid shortcuts. */ + /* On Windows don't show `.lnk` extension for valid shortcuts. */ BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, ""); #endif } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index ce36e3e4e4f..e42e1e98660 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -983,6 +983,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region) if (params->display == FILE_IMGDISPLAY) { const float pad_fac = compact ? 0.15f : 0.3f; + /* Matches UI_preview_tile_size_x()/_y() by default. */ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; layout->tile_border_x = pad_fac * UI_UNIT_X; @@ -1009,6 +1010,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region) else if (params->display == FILE_VERTICALDISPLAY) { int rowcount; + /* Matches UI_preview_tile_size_x()/_y() by default. */ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; layout->tile_border_x = 0.4f * UI_UNIT_X; @@ -1030,6 +1032,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region) layout->flag = FILE_LAYOUT_VER; } else if (params->display == FILE_HORIZONTALDISPLAY) { + /* Matches UI_preview_tile_size_x()/_y() by default. */ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; layout->tile_border_x = 0.4f * UI_UNIT_X; diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 10cde239987..310c688383b 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -890,7 +890,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) continue; } - /* Exclude "all my files" as it makes no sense in blender fileselector */ + /* Exclude "all my files" as it makes no sense in blender file-selector. */ /* Exclude "airdrop" if wlan not active as it would show "" ) */ if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) { fsmenu_insert_entry( diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 0170361f244..a462476aae0 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -695,6 +695,7 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_smoothscroll); WM_operatortype_append(FILE_OT_filepath_drop); WM_operatortype_append(FILE_OT_start_filter); + WM_operatortype_append(FILE_OT_edit_directory_path); WM_operatortype_append(FILE_OT_view_selected); } diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index c385420b18e..39fb41245bf 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -61,7 +61,7 @@ if(WITH_IMAGE_CINEON) endif() if(WITH_IMAGE_WEBP) - add_definitions(-DWITH_WEBP) + add_definitions(-DWITH_WEBP) endif() blender_add_lib(bf_editor_space_image "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 208928afc1f..d0c21f85472 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -845,7 +845,10 @@ void uiTemplateImage(uiLayout *layout, row = uiLayoutRow(row, true); uiLayoutSetEnabled(row, is_packed == false); - uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); + + prop = RNA_struct_find_property(&imaptr, "filepath"); + uiDefAutoButR(block, &imaptr, prop, -1, "", ICON_NONE, 0, 0, 200, UI_UNIT_Y); + uiItemO(row, "", ICON_FILEBROWSER, "image.file_browse"); uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); } diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index e851b99d3ba..950acd77f6a 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -483,6 +483,16 @@ bool ED_space_image_maskedit_poll(bContext *C) return false; } +bool ED_space_image_maskedit_visible_splines_poll(bContext *C) +{ + if (!ED_space_image_maskedit_poll(C)) { + return false; + } + + const SpaceImage *space_image = CTX_wm_space_image(C); + return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE; +} + bool ED_space_image_paint_curve(const bContext *C) { SpaceImage *sima = CTX_wm_space_image(C); @@ -508,6 +518,16 @@ bool ED_space_image_maskedit_mask_poll(bContext *C) return false; } +bool ED_space_image_maskedit_mask_visible_splines_poll(bContext *C) +{ + if (!ED_space_image_maskedit_mask_poll(C)) { + return false; + } + + const SpaceImage *space_image = CTX_wm_space_image(C); + return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE; +} + bool ED_space_image_cursor_poll(bContext *C) { return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) || diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index 2322420069e..364bec1377d 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -49,6 +49,7 @@ void IMAGE_OT_new(struct wmOperatorType *ot); * Called by other space types too. */ void IMAGE_OT_open(struct wmOperatorType *ot); +void IMAGE_OT_file_browse(struct wmOperatorType *ot); /** * Called by other space types too. */ diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index bd1cb3a345e..537132ac428 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -197,6 +197,20 @@ static ImageUser *image_user_from_context(const bContext *C) return (sima) ? &sima->iuser : NULL; } +static ImageUser image_user_from_active_tile(Image *ima) +{ + ImageUser iuser; + BKE_imageuser_default(&iuser); + + /* Use the file associated with the active tile. Otherwise use the first tile. */ + if (ima && ima->source == IMA_SRC_TILED) { + const ImageTile *active = (ImageTile *)BLI_findlink(&ima->tiles, ima->active_tile_index); + iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number; + } + + return iuser; +} + static bool image_from_context_has_data_poll(bContext *C) { Image *ima = image_from_context(C); @@ -214,13 +228,14 @@ static bool image_from_context_has_data_poll(bContext *C) } /** - * Use this when the image buffer is accessed without the image user. + * Use this when the image buffer is accessing the active tile without the image user. */ -static bool image_from_context_has_data_poll_no_image_user(bContext *C) +static bool image_from_context_has_data_poll_active_tile(bContext *C) { Image *ima = image_from_context(C); + ImageUser iuser = image_user_from_active_tile(ima); - return BKE_image_has_ibuf(ima, NULL); + return BKE_image_has_ibuf(ima, &iuser); } static bool image_not_packed_poll(bContext *C) @@ -949,7 +964,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) static bool image_view_selected_poll(bContext *C) { - return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C))); + return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_maskedit_poll(C))); } void IMAGE_OT_view_selected(wmOperatorType *ot) @@ -1446,7 +1461,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( image_open_init(C, op); - /* show multiview save options only if scene has multiviews */ + /* Show multi-view save options only if scene has multi-views. */ PropertyRNA *prop; prop = RNA_struct_find_property(op->ptr, "show_multiview"); RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0); @@ -1535,6 +1550,115 @@ void IMAGE_OT_open(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Browse Image Operator + * \{ */ + +static int image_file_browse_exec(bContext *C, wmOperator *op) +{ + Image *ima = op->customdata; + if (ima == NULL) { + return OPERATOR_CANCELLED; + } + + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + + /* If loading into a tiled texture, ensure that the filename is tokenized. */ + if (ima->source == IMA_SRC_TILED) { + char *filename = (char *)BLI_path_basename(filepath); + BKE_image_ensure_tile_token(filename); + } + + PointerRNA imaptr; + PropertyRNA *imaprop; + RNA_id_pointer_create(&ima->id, &imaptr); + imaprop = RNA_struct_find_property(&imaptr, "filepath"); + + RNA_property_string_set(&imaptr, imaprop, filepath); + RNA_property_update(C, &imaptr, imaprop); + + return OPERATOR_FINISHED; +} + +static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Image *ima = image_from_context(C); + if (!ima) { + return OPERATOR_CANCELLED; + } + + char filepath[FILE_MAX]; + BLI_strncpy(filepath, ima->filepath, sizeof(filepath)); + + /* Shift+Click to open the file, Alt+Click to browse a folder in the OS's browser. */ + if (event->modifier & (KM_SHIFT | KM_ALT)) { + wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true); + PointerRNA props_ptr; + + if (event->modifier & KM_ALT) { + char *lslash = (char *)BLI_path_slash_rfind(filepath); + if (lslash) { + *lslash = '\0'; + } + } + else if (ima->source == IMA_SRC_TILED) { + ImageUser iuser = image_user_from_active_tile(ima); + BKE_image_user_file_path(&iuser, ima, filepath); + } + + WM_operator_properties_create_ptr(&props_ptr, ot); + RNA_string_set(&props_ptr, "filepath", filepath); + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr, NULL); + WM_operator_properties_free(&props_ptr); + + return OPERATOR_CANCELLED; + } + + /* The image is typically passed to the operator via layout/button context (e.g. + * #uiLayoutSetContextPointer()). The File Browser doesn't support restoring this context + * when calling `exec()` though, so we have to pass it the image via custom data. */ + op->customdata = ima; + + image_filesel(C, op, filepath); + + return OPERATOR_RUNNING_MODAL; +} + +static bool image_file_browse_poll(bContext *C) +{ + return image_from_context(C) != NULL; +} + +void IMAGE_OT_file_browse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Browse Image"; + ot->description = + "Open an image file browser, hold Shift to open the file, Alt to browse containing " + "directory"; + ot->idname = "IMAGE_OT_file_browse"; + + /* api callbacks */ + ot->exec = image_file_browse_exec; + ot->invoke = image_file_browse_invoke; + ot->poll = image_file_browse_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, + FILE_SPECIAL, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Match Movie Length Operator * \{ */ @@ -1696,7 +1820,6 @@ static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOp RNA_boolean_get(op->ptr, "copy")); opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); - opts->do_newpath = true; } static bool save_image_op( @@ -1733,6 +1856,8 @@ static ImageSaveData *image_save_as_init(bContext *C, wmOperator *op) return NULL; } + isd->opts.do_newpath = true; + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { RNA_string_set(op->ptr, "filepath", isd->opts.filepath); } @@ -2573,7 +2698,8 @@ void IMAGE_OT_new(wmOperatorType *ot) static int image_flip_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImageUser iuser = image_user_from_active_tile(ima); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); SpaceImage *sima = CTX_wm_space_image(C); const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); @@ -2670,7 +2796,7 @@ void IMAGE_OT_flip(wmOperatorType *ot) /* api callbacks */ ot->exec = image_flip_exec; - ot->poll = image_from_context_has_data_poll_no_image_user; + ot->poll = image_from_context_has_data_poll_active_tile; /* properties */ PropertyRNA *prop; @@ -2693,7 +2819,8 @@ void IMAGE_OT_flip(wmOperatorType *ot) static int image_invert_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImageUser iuser = image_user_from_active_tile(ima); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); SpaceImage *sima = CTX_wm_space_image(C); const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); @@ -2791,7 +2918,7 @@ void IMAGE_OT_invert(wmOperatorType *ot) /* api callbacks */ ot->exec = image_invert_exec; - ot->poll = image_from_context_has_data_poll_no_image_user; + ot->poll = image_from_context_has_data_poll_active_tile; /* properties */ prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert red channel"); @@ -2816,9 +2943,10 @@ void IMAGE_OT_invert(wmOperatorType *ot) static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Image *ima = image_from_context(C); + ImageUser iuser = image_user_from_active_tile(ima); PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size"); if (!RNA_property_is_set(op->ptr, prop)) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); const int size[2] = {ibuf->x, ibuf->y}; RNA_property_int_set_array(op->ptr, prop, size); BKE_image_release_ibuf(ima, ibuf, NULL); @@ -2829,7 +2957,8 @@ static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED static int image_scale_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImageUser iuser = image_user_from_active_tile(ima); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); SpaceImage *sima = CTX_wm_space_image(C); const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); @@ -2879,7 +3008,7 @@ void IMAGE_OT_resize(wmOperatorType *ot) /* api callbacks */ ot->invoke = image_scale_invoke; ot->exec = image_scale_exec; - ot->poll = image_from_context_has_data_poll_no_image_user; + ot->poll = image_from_context_has_data_poll_active_tile; /* properties */ RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX); @@ -3075,7 +3204,7 @@ bool ED_space_image_get_position(SpaceImage *sima, } bool ED_space_image_color_sample( - SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data) + SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data) { if (r_is_data) { *r_is_data = false; diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index 1fd9fde084b..a7a8bde1115 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -287,7 +287,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles) ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ } if (ibuf->mipmap[0]) { - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */ + ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */ } ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 63f919a1713..785a5419e04 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -199,6 +199,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_new); WM_operatortype_append(IMAGE_OT_open); + WM_operatortype_append(IMAGE_OT_file_browse); WM_operatortype_append(IMAGE_OT_match_movie_length); WM_operatortype_append(IMAGE_OT_replace); WM_operatortype_append(IMAGE_OT_reload); @@ -315,6 +316,9 @@ static void image_listener(const wmSpaceTypeListenerParams *params) ED_area_tag_redraw(area); break; case ND_MODE: + ED_paint_cursor_start(¶ms->scene->toolsettings->imapaint.paint, + ED_image_tools_paint_poll); + if (wmn->subtype == NS_EDITMODE_MESH) { ED_area_tag_refresh(area); } @@ -690,6 +694,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region) sima->mask_info.draw_flag & ~MASK_DRAWFLAG_OVERLAY, sima->mask_info.draw_type, sima->mask_info.overlay_mode, + sima->mask_info.blend_factor, width, height, aspx, diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index b817ff887ce..29a7eb150a1 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -46,6 +46,7 @@ #include "BKE_pbvh.h" #include "BKE_scene.h" #include "BKE_subdiv_ccg.h" +#include "BKE_subdiv_modifier.h" #include "DEG_depsgraph_query.h" @@ -92,15 +93,18 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st } int totvert, totedge, totface, totloop; - if (me_eval->runtime.subdiv_ccg != nullptr) { - const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg; + + const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg; + const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data; + + if (subdiv_ccg != nullptr) { BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop); } - else if (me_eval->runtime.subsurf_resolution != 0) { - totvert = me_eval->runtime.subsurf_totvert; - totedge = me_eval->runtime.subsurf_totedge; - totface = me_eval->runtime.subsurf_totpoly; - totloop = me_eval->runtime.subsurf_totloop; + else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) { + totvert = subsurf_runtime_data->stats_totvert; + totedge = subsurf_runtime_data->stats_totedge; + totface = subsurf_runtime_data->stats_totpoly; + totloop = subsurf_runtime_data->stats_totloop; } else { totvert = me_eval->totvert; diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 6c631f46069..bb9e201d94a 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -621,7 +621,6 @@ static void nla_draw_strip(SpaceNla *snla, static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, - int index, View2D *v2d, float xminc, float xmaxc, @@ -636,7 +635,7 @@ static void nla_draw_strip_text(AnimData *adt, /* just print the name and the range */ if (strip->flag & NLASTRIP_FLAG_TEMP_META) { - str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index); + str_len = BLI_snprintf_rlen(str, sizeof(str), "Temp-Meta"); } else { str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str)); @@ -702,6 +701,89 @@ static void nla_draw_strip_frames_text( /* ---------------------- */ +/** + * Gets the first and last visible NLA strips on a track. + * Note that this also includes tracks that might only be + * visible because of their extendmode. + */ +static ListBase get_visible_nla_strips(NlaTrack *nlt, View2D *v2d) +{ + if (BLI_listbase_is_empty(&nlt->strips)) { + ListBase empty = {NULL, NULL}; + return empty; + } + + NlaStrip *first = NULL; + NlaStrip *last = NULL; + + /* Find the first strip that is within the bounds of the view. */ + LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) { + if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) { + first = last = strip; + break; + } + } + + const bool has_strips_within_bounds = first != NULL; + + if (has_strips_within_bounds) { + /* Find the last visible strip. */ + for (NlaStrip *strip = first->next; strip; strip = strip->next) { + if (!BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) { + break; + } + last = strip; + } + /* Check if the first strip is adjacent to a strip outside the view to the left + * that has an extendmode region that should be drawn. + * If so, adjust the first strip to include drawing that strip as well. + */ + NlaStrip *prev = first->prev; + if (prev && prev->extendmode != NLASTRIP_EXTEND_NOTHING) { + first = prev; + } + } + else { + /* No immediately visible strips. + * Figure out where our view is relative to the strips, then determine + * if the view is adjacent to a strip that should have its extendmode + * rendered. + */ + NlaStrip *first_strip = nlt->strips.first; + NlaStrip *last_strip = nlt->strips.last; + if (first_strip && v2d->cur.xmax < first_strip->start && + first_strip->extendmode == NLASTRIP_EXTEND_HOLD) { + /* The view is to the left of all strips and the first strip has an + * extendmode that should be drawn. + */ + first = last = first_strip; + } + else if (last_strip && v2d->cur.xmin > last_strip->end && + last_strip->extendmode != NLASTRIP_EXTEND_NOTHING) { + /* The view is to the right of all strips and the last strip has an + * extendmode that should be drawn. + */ + first = last = last_strip; + } + else { + /* The view is in the middle of two strips. */ + LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) { + /* Find the strip to the left by finding the strip to the right and getting its prev. */ + if (v2d->cur.xmax < strip->start) { + /* If the strip to the left has an extendmode, set that as the only visible strip. */ + if (strip->prev && strip->prev->extendmode != NLASTRIP_EXTEND_NOTHING) { + first = last = strip->prev; + } + break; + } + } + } + } + + ListBase visible_strips = {first, last}; + return visible_strips; +} + void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region) { View2D *v2d = ®ion->v2d; @@ -737,29 +819,26 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region) case ANIMTYPE_NLATRACK: { AnimData *adt = ale->adt; NlaTrack *nlt = (NlaTrack *)ale->data; - NlaStrip *strip; - int index; - - /* draw each strip in the track (if visible) */ - for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) { - if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) { - const float xminc = strip->start + text_margin_x; - const float xmaxc = strip->end - text_margin_x; - - /* draw the visualization of the strip */ - nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax); - - /* add the text for this strip to the cache */ - if (xminc < xmaxc) { - nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, ymin, ymax); - } - - /* if transforming strips (only real reason for temp-metas currently), - * add to the cache the frame numbers of the strip's extents - */ - if (strip->flag & NLASTRIP_FLAG_TEMP_META) { - nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax); - } + ListBase visible_nla_strips = get_visible_nla_strips(nlt, v2d); + + /* Draw each visible strip in the track. */ + LISTBASE_FOREACH (NlaStrip *, strip, &visible_nla_strips) { + const float xminc = strip->start + text_margin_x; + const float xmaxc = strip->end - text_margin_x; + + /* draw the visualization of the strip */ + nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax); + + /* add the text for this strip to the cache */ + if (xminc < xmaxc) { + nla_draw_strip_text(adt, nlt, strip, v2d, xminc, xmaxc, ymin, ymax); + } + + /* if transforming strips (only real reason for temp-metas currently), + * add to the cache the frame numbers of the strip's extents + */ + if (strip->flag & NLASTRIP_FLAG_TEMP_META) { + nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax); } } break; diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 2aa9b347ed7..81520445000 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1004,7 +1004,7 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op)) NlaStrip *strip; if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { - /* No making metastrips in non-local tracks of override data. */ + /* No making meta-strips in non-local tracks of override data. */ continue; } @@ -1078,7 +1078,7 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nlt = (NlaTrack *)ale->data; if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { - /* No removing metastrips from non-local tracks of override data. */ + /* No removing meta-strips from non-local tracks of override data. */ continue; } @@ -1714,7 +1714,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) BKE_nlatrack_add_strip(nlt, sb, is_liboverride); } - /* clear (temp) metastrips */ + /* Clear (temp) meta-strips. */ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1); } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index e0ff4212a94..b879219e39c 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -66,6 +66,7 @@ #include "NOD_geometry_nodes_eval_log.hh" #include "NOD_node_declaration.hh" +#include "NOD_socket_declarations_geometry.hh" #include "FN_field.hh" #include "FN_field_cpp_type.hh" @@ -75,7 +76,7 @@ using blender::GPointer; using blender::fn::GField; namespace geo_log = blender::nodes::geometry_nodes_eval_log; -using geo_log::NamedAttributeUsage; +using geo_log::eNamedAttrUsage; extern "C" { /* XXX interface.h */ @@ -748,15 +749,14 @@ static void node_socket_outline_color_get(const bool selected, if (selected) { UI_GetThemeColor4fv(TH_ACTIVE, r_outline_color); } + else if (socket_type == SOCK_CUSTOM) { + /* Until there is a better place for per socket color, + * the outline color for virtual sockets is set here. */ + copy_v4_v4(r_outline_color, virtual_node_socket_outline_color); + } else { UI_GetThemeColor4fv(TH_WIRE, r_outline_color); } - - /* Until there is a better place for per socket color, - * the outline color for virtual sockets is set here. */ - if (socket_type == SOCK_CUSTOM) { - copy_v4_v4(r_outline_color, virtual_node_socket_outline_color); - } } void node_socket_color_get(const bContext &C, @@ -871,7 +871,8 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v } static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log, - std::stringstream &ss) + std::stringstream &ss, + const nodes::decl::Geometry *geometry) { Span<GeometryComponentType> component_types = value_log.component_types(); if (component_types.is_empty()) { @@ -938,6 +939,45 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo } } } + + /* If the geometry declaration is null, as is the case for input to group output, + * or it is an output socket don't show supported types. */ + if (geometry == nullptr || geometry->in_out() == SOCK_OUT) { + return; + } + + Span<GeometryComponentType> supported_types = geometry->supported_types(); + if (supported_types.is_empty()) { + ss << ".\n\n" << TIP_("Supported: All Types"); + return; + } + + ss << ".\n\n" << TIP_("Supported: "); + for (GeometryComponentType type : supported_types) { + switch (type) { + case GEO_COMPONENT_TYPE_MESH: { + ss << TIP_("Mesh"); + break; + } + case GEO_COMPONENT_TYPE_POINT_CLOUD: { + ss << TIP_("Point Cloud"); + break; + } + case GEO_COMPONENT_TYPE_CURVE: { + ss << TIP_("Curve"); + break; + } + case GEO_COMPONENT_TYPE_INSTANCES: { + ss << TIP_("Instances"); + break; + } + case GEO_COMPONENT_TYPE_VOLUME: { + ss << TIP_("Volume"); + break; + } + } + ss << ((type == supported_types.last()) ? "" : ", "); + } } static std::optional<std::string> create_socket_inspection_string(bContext *C, @@ -970,7 +1010,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C, } else if (const geo_log::GeometryValueLog *geo_value_log = dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { - create_inspection_string_for_geometry(*geo_value_log, ss); + create_inspection_string_for_geometry( + *geo_value_log, + ss, + dynamic_cast<const nodes::decl::Geometry *>(socket.runtime->declaration)); } return ss.str(); @@ -1695,7 +1738,7 @@ struct NodeExtraInfoRow { }; struct NamedAttributeTooltipArg { - Map<std::string, NamedAttributeUsage> usage_by_attribute; + Map<std::string, eNamedAttrUsage> usage_by_attribute; }; static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) @@ -1707,7 +1750,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char struct NameWithUsage { StringRefNull name; - NamedAttributeUsage usage; + eNamedAttrUsage usage; }; Vector<NameWithUsage> sorted_used_attribute; @@ -1722,16 +1765,16 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char for (const NameWithUsage &attribute : sorted_used_attribute) { const StringRefNull name = attribute.name; - const NamedAttributeUsage usage = attribute.usage; + const eNamedAttrUsage usage = attribute.usage; ss << " \u2022 \"" << name << "\": "; Vector<std::string> usages; - if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) { usages.append(TIP_("read")); } - if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) { usages.append(TIP_("write")); } - if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) { usages.append(TIP_("remove")); } for (const int i : usages.index_range()) { @@ -1749,7 +1792,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char } static NodeExtraInfoRow row_from_used_named_attribute( - const Map<std::string, NamedAttributeUsage> &usage_by_attribute_name) + const Map<std::string, eNamedAttrUsage> &usage_by_attribute_name) { const int attributes_num = usage_by_attribute_name.size(); @@ -1777,7 +1820,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp return std::nullopt; } - Map<std::string, NamedAttributeUsage> usage_by_attribute; + Map<std::string, eNamedAttrUsage> usage_by_attribute; tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) { usage_by_attribute.lookup_or_add_as(used_attribute.name, @@ -1807,7 +1850,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp if (node_log == nullptr) { return std::nullopt; } - Map<std::string, NamedAttributeUsage> usage_by_attribute; + Map<std::string, eNamedAttrUsage> usage_by_attribute; for (const geo_log::UsedNamedAttribute &used_attribute : node_log->used_named_attributes()) { usage_by_attribute.lookup_or_add_as(used_attribute.name, used_attribute.usage) |= used_attribute.usage; diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index ab80a44d636..ffc9befc81c 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -15,6 +15,7 @@ #include "DNA_text_types.h" #include "DNA_world_types.h" +#include "BKE_callbacks.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" @@ -275,6 +276,7 @@ static void compo_startjob(void *cjv, // XXX BIF_store_spare(); /* 1 is do_previews */ + BKE_callback_exec_id(cj->bmain, &scene->id, BKE_CB_EVT_COMPOSITE_PRE); if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) { ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, ""); @@ -293,6 +295,22 @@ static void compo_startjob(void *cjv, ntree->progress = nullptr; } +static void compo_canceljob(void *cjv) +{ + CompoJob *cj = (CompoJob *)cjv; + Main *bmain = cj->bmain; + Scene *scene = cj->scene; + BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_CANCEL); +} + +static void compo_completejob(void *cjv) +{ + CompoJob *cj = (CompoJob *)cjv; + Main *bmain = cj->bmain; + Scene *scene = cj->scene; + BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_POST); +} + /** \} */ } // namespace blender::ed::space_node @@ -339,7 +357,13 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene /* setup job */ WM_jobs_customdata_set(wm_job, cj, compo_freejob); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT); - WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, nullptr); + WM_jobs_callbacks_ex(wm_job, + compo_startjob, + compo_initjob, + compo_updatejob, + nullptr, + compo_completejob, + compo_canceljob); WM_jobs_start(CTX_wm_manager(C), wm_job); } diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 9c0172cfabf..f08e23c8371 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -82,8 +82,10 @@ static Vector<const GeometryAttributeInfo *> get_attribute_info_from_context( if (const geo_log::GeometryValueLog *geo_value_log = dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) { - if (names.add(attribute.name)) { - attributes.append(&attribute); + if (bke::allow_procedural_attribute_access(attribute.name)) { + if (names.add(attribute.name)) { + attributes.append(&attribute); + } } } } @@ -126,7 +128,7 @@ static void attribute_search_update_fn( * Some custom data types don't correspond to node types and therefore can't be * used by the named attribute input node. Find the best option or fallback to float. */ -static CustomDataType data_type_in_attribute_input_node(const CustomDataType type) +static eCustomDataType data_type_in_attribute_input_node(const eCustomDataType type) { switch (type) { case CD_PROP_FLOAT: @@ -185,7 +187,7 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) /* For the attribute input node, also adjust the type and links connected to the output. */ if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE && item->data_type.has_value()) { NodeGeometryInputNamedAttribute &storage = *(NodeGeometryInputNamedAttribute *)node->storage; - const CustomDataType new_type = data_type_in_attribute_input_node(*item->data_type); + const eCustomDataType new_type = data_type_in_attribute_input_node(*item->data_type); if (new_type != storage.data_type) { storage.data_type = new_type; /* Make the output socket with the new type on the attribute input node active. */ diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 5796a712205..e10bedb18f4 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -454,7 +454,7 @@ static bool socket_can_be_viewed(const OutputSocketRef &socket) SOCK_RGBA); } -static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type) +static eCustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type) { switch (socket_type) { case SOCK_FLOAT: @@ -491,7 +491,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, return viewer_socket; } NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node.storage; - const CustomDataType data_type = socket_type_to_custom_data_type( + const eCustomDataType data_type = socket_type_to_custom_data_type( (eNodeSocketDatatype)src_socket.type); BLI_assert(data_type != CD_AUTO_FROM_NAME); storage->data_type = data_type; diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc index bd6d3d89706..877e0fc325c 100644 --- a/source/blender/editors/space_outliner/outliner_select.cc +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -1693,7 +1693,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; - ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; PropertyRNA *prop; prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection for activation"); @@ -2028,7 +2028,7 @@ void OUTLINER_OT_select_walk(wmOperatorType *ot) ot->invoke = outliner_walk_select_invoke; ot->poll = ED_operator_outliner_active; - ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ PropertyRNA *prop; diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 3b018d59881..ec19e8d5e5b 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -222,13 +222,33 @@ static void unlink_action_fn(bContext *C, } static void unlink_material_fn(bContext *UNUSED(C), - ReportList *UNUSED(reports), + ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, - TreeStoreElem *UNUSED(tselem), + TreeStoreElem *tselem, void *UNUSED(user_data)) { + const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA); + + if (!te_is_material) { + /* Just fail silently. Another element may be selected that is a material, we don't want to + * confuse users with an error in that case. */ + return; + } + + if (!tsep || !TSE_IS_REAL_ID(tsep)) { + /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE + * for example) so there's no data to unlink from. */ + BKE_reportf(reports, + RPT_WARNING, + "Cannot unlink material '%s'. It's not clear which object or object-data it " + "should be unlinked from, there's no object or object-data as parent in the " + "Outliner tree", + tselem->id->name + 2); + return; + } + Material **matar = nullptr; int a, totcol = 0; @@ -1954,7 +1974,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; /* flags */ - ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ PropertyRNA *prop = RNA_def_boolean( @@ -2008,7 +2028,7 @@ static const EnumPropertyItem prop_id_op_types[] = { 0, "Remap Users", "Make all users of selected data-blocks to use instead current (clicked) one"}, - {0, "", 0, nullptr, nullptr}, + RNA_ENUM_ITEM_SEPR, {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, "OVERRIDE_LIBRARY_CREATE", 0, @@ -2067,10 +2087,10 @@ static const EnumPropertyItem prop_id_op_types[] = { "Clear Library Override Hierarchy", "Delete this local override (including its hierarchy of override dependencies) and relink " "its usages to the linked data-blocks"}, - {0, "", 0, nullptr, nullptr}, + RNA_ENUM_ITEM_SEPR, {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, - {0, "", 0, nullptr, nullptr}, + RNA_ENUM_ITEM_SEPR, {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index e6098631a68..aa739758ecb 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -802,7 +802,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, void *idv, TreeElement *parent, short type, - short index) + short index, + const bool expand) { ID *id = reinterpret_cast<ID *>(idv); @@ -894,10 +895,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, te->idcode = GS(id->name); } - if (te->abstract_element && te->abstract_element->isExpandValid()) { + if (expand && te->abstract_element && te->abstract_element->isExpandValid()) { tree_element_expand(*te->abstract_element, *space_outliner); } - else if (type == TSE_SOME_ID) { + else if (expand && (type == TSE_SOME_ID)) { /* ID types not (fully) ported to new design yet. */ if (te->abstract_element->expandPoll(*space_outliner)) { outliner_add_id_contents(space_outliner, te, tselem, id); 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 38025b58fd2..67798e978ab 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 @@ -34,13 +34,6 @@ TreeDisplayOverrideLibraryHierarchies::TreeDisplayOverrideLibraryHierarchies( { } -/* XXX Remove expanded subtree, we add our own items here. Expanding should probably be - * optional. */ -static void remove_expanded_children(TreeElement &te) -{ - outliner_free_tree(&te.subtree); -} - ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &source_data) { ListBase tree = {nullptr}; @@ -114,8 +107,7 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main( }); TreeElement *new_id_te = outliner_add_element( - &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0); - remove_expanded_children(*new_id_te); + &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0, false); build_hierarchy_for_ID(bmain, *iter_id, *tree_element_cast<TreeElementID>(new_id_te)); } @@ -193,8 +185,8 @@ static int build_hierarchy_foreach_ID_cb(LibraryIDLinkCallbackData *cb_data) &id, &build_data.parent_te->getLegacyElement(), TSE_SOME_ID, - 0); - remove_expanded_children(*new_te); + 0, + false); build_data.sibling_ids.add(&id); BuildHierarchyForeachIDCbData child_build_data{build_data.bmain, diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index 80b3365766a..c8869d90eca 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -271,14 +271,14 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections() if (!found) { /* We add the child in the tree even if it is not in the collection. - * We deliberately clear its sub-tree though, to make it less prominent. */ + * We don't expand its sub-tree though, to make it less prominent. */ TreeElement *child_ob_tree_element = outliner_add_element(&outliner_, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, TSE_SOME_ID, - 0); - outliner_free_tree(&child_ob_tree_element->subtree); + 0, + false); child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION; child_ob_tree_elements.append(child_ob_tree_element); } diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index 0dcd75d340d..1098068d628 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -94,13 +94,19 @@ class AbstractTreeElement { * \note "ID" is not always a real ID. * \note If child items are only added to the tree if the item is open, * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change(). + * + * \param expand: If true, the element may add its own sub-tree. E.g. objects will list their + * animation data, object data, constraints, modifiers, ... This often adds visual + * noise, and can be expensive to add in big scenes. So prefer setting this to + * false. */ struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, void *idv, struct TreeElement *parent, short type, - short index); + short index, + const bool expand = true); void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc index 53e7b88c923..d1babda642e 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc @@ -67,21 +67,36 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const for (auto *override_prop : ListBaseWrapper<IDOverrideLibraryProperty>(id.override_library->properties)) { + int rnaprop_index = 0; const bool is_rna_path_valid = BKE_lib_override_rna_property_find( - &idpoin, override_prop, &override_rna_ptr, &override_rna_prop); - if (is_rna_path_valid && !show_system_overrides && - ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) && - RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) { - bool do_continue = true; - for (auto *override_prop_op : - ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) { - if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) { - do_continue = false; - break; + &idpoin, override_prop, &override_rna_ptr, &override_rna_prop, &rnaprop_index); + + /* Check for conditions where the liboverride property should be considered as a system + * override, if needed. */ + if (is_rna_path_valid && !show_system_overrides) { + bool do_skip = true; + bool is_system_override = false; + + /* Matching ID pointers are considered as system overrides. */ + if (ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) && + RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) { + for (auto *override_prop_op : + ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) { + if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) { + do_skip = false; + break; + } + is_system_override = true; } } - if (do_continue) { + /* Animated/driven properties are considered as system overrides. */ + if (!is_system_override && !BKE_lib_override_library_property_is_animated( + &id, override_prop, override_rna_prop, rnaprop_index)) { + do_skip = false; + } + + if (do_skip) { continue; } } diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.cc b/source/blender/editors/space_outliner/tree/tree_iterator.cc index 85ff9e6437e..8d2b0b21433 100644 --- a/source/blender/editors/space_outliner/tree/tree_iterator.cc +++ b/source/blender/editors/space_outliner/tree/tree_iterator.cc @@ -43,13 +43,14 @@ void all_open(const SpaceOutliner &space_outliner, { LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) { /* Get needed data out in case element gets freed. */ - const bool is_open = TSELEM_OPEN(element->store_elem, &space_outliner); + const TreeStoreElem *tselem = TREESTORE(element); const ListBase subtree = element->subtree; visitor(element); - /* Don't access element from now on, it may be freed. */ + /* Don't access element from now on, it may be freed. Note that the open/collapsed state may + * also have been changed in the visitor callback. */ - if (is_open) { + if (TSELEM_OPEN(tselem, &space_outliner)) { all_open(space_outliner, subtree, visitor); } } diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh index e3b3c90eaad..de5bcd2c462 100644 --- a/source/blender/editors/space_outliner/tree/tree_iterator.hh +++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh @@ -26,7 +26,7 @@ void all(const ListBase &subtree, VisitorFn visitor); /** * Preorder (meaning depth-first) traversal of all elements not part of a collapsed sub-tree. - * Freeing the currently visited element in \a visitor is fine. + * Freeing the currently visited element in \a visitor is fine (but not its tree-store element). */ void all_open(const SpaceOutliner &, VisitorFn visitor); void all_open(const SpaceOutliner &, const ListBase &subtree, VisitorFn visitor); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 10c6e828e96..647d13a4d56 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -191,10 +191,11 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type) } for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if ((ELEM(type, -1, seq->type)) && (seq->enddisp < timeline_frame) && - (timeline_frame - seq->enddisp < proximity)) { + const int strip_end = SEQ_time_right_handle_frame_get(seq); + if ((ELEM(type, -1, seq->type)) && (strip_end < timeline_frame) && + (timeline_frame - strip_end < proximity)) { tgt = seq; - proximity = timeline_frame - seq->enddisp; + proximity = timeline_frame - strip_end; } } @@ -339,7 +340,7 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence ScrArea *area = CTX_wm_area(C); const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) != 0; - SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers); + SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers); SEQ_collection_free(strip_col); } @@ -785,7 +786,6 @@ static void seq_build_proxy(bContext *C, SeqCollection *movie_strips) } static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, - ListBase *seqbase, Sequence *seq_movie, Sequence *seq_sound) { @@ -793,9 +793,8 @@ static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, return; } - SEQ_time_right_handle_frame_set(seq_sound, SEQ_time_right_handle_frame_get(seq_movie)); - SEQ_time_left_handle_frame_set(seq_sound, SEQ_time_left_handle_frame_get(seq_movie)); - SEQ_time_update_sequence(scene, seqbase, seq_sound); + SEQ_time_right_handle_frame_set(scene, seq_sound, SEQ_time_right_handle_frame_get(seq_movie)); + SEQ_time_left_handle_frame_set(scene, seq_sound, SEQ_time_left_handle_frame_get(seq_movie)); } static void sequencer_add_movie_multiple_strips(bContext *C, @@ -833,7 +832,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C, else { if (RNA_boolean_get(op->ptr, "sound")) { seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); - sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); + sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound); if (seq_sound) { /* The video has sound, shift the video strip up a channel to make room for the sound @@ -842,7 +841,8 @@ static void sequencer_add_movie_multiple_strips(bContext *C, } } - load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp; + load_data->start_frame += SEQ_time_right_handle_frame_get(seq_movie) - + SEQ_time_left_handle_frame_get(seq_movie); if (overlap_shuffle_override) { has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap( C, op, seq_sound, strip_col); @@ -863,7 +863,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C, ScrArea *area = CTX_wm_area(C); const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) != 0; - SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers); + SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers); } SEQ_collection_free(strip_col); @@ -890,7 +890,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, } if (RNA_boolean_get(op->ptr, "sound")) { seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); - sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); + sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound); if (seq_sound) { /* The video has sound, shift the video strip up a channel to make room for the sound * strip. */ @@ -913,7 +913,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, ScrArea *area = CTX_wm_area(C); const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) != 0; - SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers); + SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers); } SEQ_collection_free(strip_col); @@ -1073,7 +1073,8 @@ static void sequencer_add_sound_multiple_strips(bContext *C, } else { seq_load_apply_generic_options(C, op, seq); - load_data->start_frame += seq->enddisp - seq->startdisp; + load_data->start_frame += SEQ_time_right_handle_frame_get(seq) - + SEQ_time_left_handle_frame_get(seq); } } RNA_END; @@ -1300,8 +1301,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) /* Adjust length. */ if (load_data.image.len == 1) { - SEQ_time_right_handle_frame_set(seq, load_data.image.end_frame); - SEQ_time_update_sequence(scene, SEQ_active_seqbase_get(ed), seq); + SEQ_time_right_handle_frame_set(scene, seq, load_data.image.end_frame); } seq_load_apply_generic_options(C, op, seq); diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c index 645c0dc9a1d..8dadb9360e3 100644 --- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c @@ -231,9 +231,8 @@ static void update_overlay_strip_poistion_data(bContext *C, const int mval[2]) else { /* Check if there is a strip that would intersect with the new strip(s). */ coords->is_intersecting = false; - Sequence dummy_seq = {.machine = coords->channel, - .startdisp = coords->start_frame, - .enddisp = coords->start_frame + coords->strip_len}; + Sequence dummy_seq = { + .machine = coords->channel, .start = coords->start_frame, .len = coords->strip_len}; Editing *ed = SEQ_editing_get(scene); for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) { diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 02e77732e02..25701c323b9 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -617,8 +617,8 @@ static void drawmeta_contents(Scene *scene, /* Draw only immediate children (1 level depth). */ for (seq = meta_seqbase->first; seq; seq = seq->next) { - const int startdisp = seq->startdisp + offset; - const int enddisp = seq->enddisp + offset; + const int startdisp = SEQ_time_left_handle_frame_get(seq) + offset; + const int enddisp = SEQ_time_right_handle_frame_get(seq) + offset; if ((startdisp > x2 || enddisp < x1) == 0) { float y_chan = (seq->machine - chan_min) / (float)(chan_range)*draw_range; @@ -668,7 +668,10 @@ float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx) const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize; /* Ensure that handle is not wider, than quarter of strip. */ - return min_ff(maxhandle, ((float)(seq->enddisp - seq->startdisp) / 4.0f)); + return min_ff( + maxhandle, + ((float)(SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq)) / + 4.0f)); } /* Draw a handle, on left or right side of strip. */ @@ -686,8 +689,8 @@ static void draw_seq_handle(View2D *v2d, uint whichsel = 0; uchar col[4]; - x1 = seq->startdisp; - x2 = seq->enddisp; + x1 = SEQ_time_left_handle_frame_get(seq); + x2 = SEQ_time_right_handle_frame_get(seq); y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; y2 = seq->machine + SEQ_STRIP_OFSTOP; @@ -739,7 +742,11 @@ static void draw_seq_handle(View2D *v2d, BLF_set_default(); /* Calculate if strip is wide enough for showing the labels. */ - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d%d", seq->startdisp, seq->enddisp); + numstr_len = BLI_snprintf_rlen(numstr, + sizeof(numstr), + "%d%d", + SEQ_time_left_handle_frame_get(seq), + SEQ_time_right_handle_frame_get(seq)); float tot_width = BLF_width(fontid, numstr, numstr_len); if ((x2 - x1) / pixelx > 20 + tot_width) { @@ -747,12 +754,14 @@ static void draw_seq_handle(View2D *v2d, float text_margin = 1.2f * handsize_clamped; if (direction == SEQ_LEFTHANDLE) { - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp); + numstr_len = BLI_snprintf_rlen( + numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(seq)); x1 += text_margin; y1 += 0.09f; } else { - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1); + numstr_len = BLI_snprintf_rlen( + numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(seq) - 1); x1 = x2 - (text_margin + pixelx * BLF_width(fontid, numstr, numstr_len)); y1 += 0.09f; } @@ -913,7 +922,8 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq, char strip_duration_text[16]; if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) { - const int strip_duration = seq->enddisp - seq->startdisp; + const int strip_duration = SEQ_time_right_handle_frame_get(seq) - + SEQ_time_left_handle_frame_get(seq); SNPRINTF(strip_duration_text, "%d", strip_duration); if (i != 0) { text_array[i++] = text_sep; @@ -980,8 +990,8 @@ static void draw_sequence_extensions_overlay( float x1, x2, y1, y2; uchar col[4], blend_col[3]; - x1 = seq->startdisp; - x2 = seq->enddisp; + x1 = SEQ_time_left_handle_frame_get(seq); + x2 = SEQ_time_right_handle_frame_get(seq); y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; y2 = seq->machine + SEQ_STRIP_OFSTOP; @@ -1038,15 +1048,19 @@ static void draw_color_strip_band( immUniformColor4ubv(col); - immRectf(pos, seq->startdisp, y1, seq->enddisp, text_margin_y); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + y1, + SEQ_time_right_handle_frame_get(seq), + text_margin_y); /* 1px line to better separate the color band. */ UI_GetColorPtrShade3ubv(col, col, -20); immUniformColor4ubv(col); immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, seq->startdisp, text_margin_y); - immVertex2f(pos, seq->enddisp, text_margin_y); + immVertex2f(pos, SEQ_time_left_handle_frame_get(seq), text_margin_y); + immVertex2f(pos, SEQ_time_right_handle_frame_get(seq), text_margin_y); immEnd(); GPU_blend(GPU_BLEND_NONE); @@ -1111,12 +1125,12 @@ static void draw_seq_background(Scene *scene, immUniformColor4ubv(col); if (SEQ_time_has_left_still_frames(seq)) { - const float content_start = min_ff(seq->enddisp, seq->start); - immRectf(pos, seq->startdisp, y1, content_start, y2); + const float content_start = min_ff(SEQ_time_right_handle_frame_get(seq), seq->start); + immRectf(pos, SEQ_time_left_handle_frame_get(seq), y1, content_start, y2); } if (SEQ_time_has_right_still_frames(seq)) { - const float content_end = max_ff(seq->startdisp, seq->start + seq->len); - immRectf(pos, content_end, y1, seq->enddisp, y2); + const float content_end = max_ff(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len); + immRectf(pos, content_end, y1, SEQ_time_right_handle_frame_get(seq), y2); } } @@ -1333,14 +1347,15 @@ static void draw_seq_strip(const bContext *C, SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG); /* Draw strip body. */ - x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : seq->startdisp; + x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : SEQ_time_left_handle_frame_get(seq); y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; - x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : seq->enddisp; + x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : + SEQ_time_right_handle_frame_get(seq); y2 = seq->machine + SEQ_STRIP_OFSTOP; /* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */ - x1 = min_ff(x1, seq->enddisp); - x2 = max_ff(x2, seq->startdisp); + x1 = min_ff(x1, SEQ_time_right_handle_frame_get(seq)); + x2 = max_ff(x2, SEQ_time_left_handle_frame_get(seq)); float text_margin_y; bool y_threshold; @@ -1380,8 +1395,8 @@ static void draw_seq_strip(const bContext *C, } immUnbindProgram(); - x1 = seq->startdisp; - x2 = seq->enddisp; + x1 = SEQ_time_left_handle_frame_get(seq); + x2 = SEQ_time_right_handle_frame_get(seq); if ((seq->type == SEQ_TYPE_META) || ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) { @@ -1471,23 +1486,23 @@ static void draw_effect_inputs_highlight(Sequence *seq) immUniformColor4ub(255, 255, 255, 48); immRectf(pos, - seq1->startdisp, + SEQ_time_left_handle_frame_get(seq1), seq1->machine + SEQ_STRIP_OFSBOTTOM, - seq1->enddisp, + SEQ_time_right_handle_frame_get(seq1), seq1->machine + SEQ_STRIP_OFSTOP); if (seq2 && seq2 != seq1) { immRectf(pos, - seq2->startdisp, + SEQ_time_left_handle_frame_get(seq2), seq2->machine + SEQ_STRIP_OFSBOTTOM, - seq2->enddisp, + SEQ_time_right_handle_frame_get(seq2), seq2->machine + SEQ_STRIP_OFSTOP); } if (seq3 && !ELEM(seq3, seq1, seq2)) { immRectf(pos, - seq3->startdisp, + SEQ_time_left_handle_frame_get(seq3), seq3->machine + SEQ_STRIP_OFSBOTTOM, - seq3->enddisp, + SEQ_time_right_handle_frame_get(seq3), seq3->machine + SEQ_STRIP_OFSTOP); } immUnbindProgram(); @@ -2081,10 +2096,10 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene) int preview_frame; if (last_seq->flag & SEQ_RIGHTSEL) { - preview_frame = last_seq->enddisp - 1; + preview_frame = SEQ_time_right_handle_frame_get(last_seq) - 1; } else { - preview_frame = last_seq->startdisp; + preview_frame = SEQ_time_left_handle_frame_get(last_seq); } return preview_frame; @@ -2310,10 +2325,10 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) if (seq == last_seq && (last_seq->flag & SELECT)) { continue; } - if (min_ii(seq->startdisp, seq->start) > v2d->cur.xmax) { + if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > v2d->cur.xmax) { continue; } - if (max_ii(seq->enddisp, seq->start + seq->len) < v2d->cur.xmin) { + if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < v2d->cur.xmin) { continue; } if (seq->machine + 1.0f < v2d->cur.ymin) { @@ -2368,9 +2383,9 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) immUniformColor4ub(255, 255, 255, 48); immRectf(pos, - seq->startdisp, + SEQ_time_left_handle_frame_get(seq), seq->machine + SEQ_STRIP_OFSBOTTOM, - seq->enddisp, + SEQ_time_right_handle_frame_get(seq), seq->machine + SEQ_STRIP_OFSTOP); immUnbindProgram(); @@ -2597,7 +2612,8 @@ static void draw_cache_view(const bContext *C) continue; } - if (seq->startdisp > v2d->cur.xmax || seq->enddisp < v2d->cur.xmin) { + if (SEQ_time_left_handle_frame_get(seq) > v2d->cur.xmax || + SEQ_time_right_handle_frame_get(seq) < v2d->cur.xmin) { continue; } @@ -2607,7 +2623,11 @@ static void draw_cache_view(const bContext *C) if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) { const float bg_color[4] = {1.0f, 0.1f, 0.02f, 0.1f}; immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]); - immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + stripe_bot, + SEQ_time_right_handle_frame_get(seq), + stripe_top); } stripe_bot += stripe_ht + stripe_ofs_y; @@ -2616,7 +2636,11 @@ static void draw_cache_view(const bContext *C) if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) { const float bg_color[4] = {0.1f, 0.1f, 0.75f, 0.1f}; immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]); - immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + stripe_bot, + SEQ_time_right_handle_frame_get(seq), + stripe_top); } stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y; @@ -2625,7 +2649,11 @@ static void draw_cache_view(const bContext *C) if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) { const float bg_color[4] = {1.0f, 0.6f, 0.0f, 0.1f}; immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]); - immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + stripe_bot, + SEQ_time_right_handle_frame_get(seq), + stripe_top); } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 08f98dfb161..16f663110ec 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -77,7 +77,6 @@ typedef struct TransSeq { int start, machine; - int startdisp, enddisp; int startofs, endofs; int anim_startofs, anim_endofs; /* int final_left, final_right; */ /* UNUSED */ @@ -174,6 +173,11 @@ bool sequencer_edit_poll(bContext *C) return (SEQ_editing_get(CTX_data_scene(C)) != NULL); } +bool sequencer_editing_initialized_and_active(bContext *C) +{ + return ED_operator_sequencer_active(C) && sequencer_edit_poll(C); +} + #if 0 /* UNUSED */ bool sequencer_strip_poll(bContext *C) { @@ -345,7 +349,6 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_active_seqbase_get(ed); ListBase *channels = SEQ_channels_displayed_get(ed); Sequence *seq; int snap_frame; @@ -361,15 +364,15 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) } else { if (seq->flag & SEQ_LEFTSEL) { - SEQ_time_left_handle_frame_set(seq, snap_frame); + SEQ_time_left_handle_frame_set(scene, seq, snap_frame); } else { /* SEQ_RIGHTSEL */ - SEQ_time_right_handle_frame_set(seq, snap_frame); + SEQ_time_right_handle_frame_set(scene, seq, snap_frame); } - SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_transform_handle_xlimits( + scene, seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); } - SEQ_time_update_sequence(scene, seqbase, seq); } } @@ -390,27 +393,22 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) if (seq->seq1 && (seq->seq1->flag & SELECT)) { if (!either_handle_selected) { - SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq))); } - SEQ_time_update_sequence(scene, seqbase, seq); } else if (seq->seq2 && (seq->seq2->flag & SELECT)) { if (!either_handle_selected) { - SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq))); } - SEQ_time_update_sequence(scene, seqbase, seq); } else if (seq->seq3 && (seq->seq3->flag & SELECT)) { if (!either_handle_selected) { - SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq))); } - SEQ_time_update_sequence(scene, seqbase, seq); } } } - SEQ_sort(SEQ_active_seqbase_get(ed)); - DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -477,8 +475,6 @@ static void transseq_backup(TransSeq *ts, Sequence *seq) { ts->start = seq->start; ts->machine = seq->machine; - ts->startdisp = seq->startdisp; - ts->enddisp = seq->enddisp; ts->startofs = seq->startofs; ts->endofs = seq->endofs; ts->anim_startofs = seq->anim_startofs; @@ -490,8 +486,6 @@ static void transseq_restore(TransSeq *ts, Sequence *seq) { seq->start = ts->start; seq->machine = ts->machine; - seq->startdisp = ts->startdisp; - seq->enddisp = ts->enddisp; seq->startofs = ts->startofs; seq->endofs = ts->endofs; seq->anim_startofs = ts->anim_startofs; @@ -592,35 +586,13 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) { - /* Iterate in reverse so meta-strips are iterated after their children. */ for (int i = data->num_seq - 1; i >= 0; i--) { Sequence *seq = data->seq_array[i]; - int endframe; - /* Offset seq start. */ seq->start = data->ts[i].start + offset; - if (data->trim[i]) { - /* Find the end-frame. */ - endframe = seq->start + seq->len; - - /* Compute the sequence offsets. */ - seq->endofs = endframe - seq->enddisp; - seq->startofs = seq->startdisp - seq->start; - } - else { - /* No transform data (likely effect strip). Only move start and end. */ - seq->startdisp = data->ts[i].startdisp + offset; - seq->enddisp = data->ts[i].enddisp + offset; - } - - /* Effects are only added if we they are in a meta-strip. - * In this case, dependent strips will just be transformed and - * we can skip calculating for effects. - * This way we can avoid an extra loop just for effects. */ - if (!(seq->type & SEQ_TYPE_EFFECT)) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); + seq->startofs = data->ts[i].startofs - offset; + seq->endofs = data->ts[i].endofs + offset; } } @@ -640,12 +612,12 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset) int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs; int diff = 0; - if (seq_content_start >= seq->enddisp) { - diff = seq->enddisp - seq_content_start - 1; + if (seq_content_start >= SEQ_time_right_handle_frame_get(seq)) { + diff = SEQ_time_right_handle_frame_get(seq) - seq_content_start - 1; } - if (seq_content_end <= seq->startdisp) { - diff = seq->startdisp - seq_content_end + 1; + if (seq_content_end <= SEQ_time_left_handle_frame_get(seq)) { + diff = SEQ_time_left_handle_frame_get(seq) - seq_content_end + 1; } *offset += diff; } @@ -791,8 +763,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even for (int i = 0; i < data->num_seq; i++) { Sequence *seq = data->seq_array[i]; SEQ_add_reload_new_file(bmain, scene, seq, false); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); } MEM_freeN(data->seq_array); @@ -1288,7 +1258,6 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) last_seq->seq3 = seq3; int old_start = last_seq->start; - SEQ_time_update_recursive(scene, last_seq); SEQ_relations_invalidate_cache_preprocessed(scene, last_seq); SEQ_offset_animdata(scene, last_seq, (last_seq->start - old_start)); @@ -1446,13 +1415,15 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) if (ignore_selection) { if (use_cursor_position) { LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { - if (seq->enddisp == split_frame && seq->machine == split_channel) { + if (SEQ_time_right_handle_frame_get(seq) == split_frame && + seq->machine == split_channel) { seq_selected = seq->flag & SEQ_ALLSEL; } } if (!seq_selected) { LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { - if (seq->startdisp == split_frame && seq->machine == split_channel) { + if (SEQ_time_left_handle_frame_get(seq) == split_frame && + seq->machine == split_channel) { seq->flag &= ~SEQ_ALLSEL; } } @@ -1463,20 +1434,18 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) if (split_side != SEQ_SIDE_BOTH) { LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (split_side == SEQ_SIDE_LEFT) { - if (seq->startdisp >= split_frame) { + if (SEQ_time_left_handle_frame_get(seq) >= split_frame) { seq->flag &= ~SEQ_ALLSEL; } } else { - if (seq->enddisp <= split_frame) { + if (SEQ_time_right_handle_frame_get(seq) <= split_frame) { seq->flag &= ~SEQ_ALLSEL; } } } } } - - SEQ_sort(SEQ_active_seqbase_get(ed)); } if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1791,8 +1760,6 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* Update lengths, etc. */ seq = ed->seqbasep->first; while (seq) { - ListBase *seqbase = SEQ_active_seqbase_get(ed); - SEQ_time_update_sequence(scene, seqbase, seq); SEQ_relations_invalidate_cache_preprocessed(scene, seq); seq = seq->next; } @@ -1883,8 +1850,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) BLI_strncpy(se_new->name, se->name, sizeof(se_new->name)); strip_new->stripdata = se_new; - SEQ_time_update_sequence(scene, seqbase, seq_new); - if (step > 1) { seq_new->flag &= ~SEQ_OVERLAP; if (SEQ_transform_test_overlap(seqbase, seq_new)) { @@ -1908,9 +1873,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } SEQ_edit_remove_flagged_sequences(scene, seqbase); - - SEQ_sort(seqbase); - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2020,8 +1982,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) BLI_addtail(&seqm->seqbase, seq); SEQ_relations_invalidate_cache_preprocessed(scene, seq); channel_max = max_ii(seq->machine, channel_max); - meta_start_frame = min_ii(seq->startdisp, meta_start_frame); - meta_end_frame = max_ii(seq->enddisp, meta_end_frame); + meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(seq), meta_start_frame); + meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(seq), meta_end_frame); } } @@ -2030,7 +1992,6 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) SEQ_sequence_base_unique_name_recursive(scene, &ed->seqbase, seqm); seqm->start = meta_start_frame; seqm->len = meta_end_frame - meta_start_frame; - SEQ_time_update_sequence(scene, active_seqbase, seqm); SEQ_select_active_set(scene, seqm); if (SEQ_transform_test_overlap(active_seqbase, seqm)) { SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene); @@ -2098,7 +2059,6 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) } } - SEQ_sort(active_seqbase); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2204,19 +2164,18 @@ static const EnumPropertyItem prop_side_lr_types[] = { static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - int gap = seqb->startdisp - seqa->enddisp; + int gap = SEQ_time_left_handle_frame_get(seqb) - SEQ_time_right_handle_frame_get(seqa); int seq_a_start; int seq_b_start; - seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp; + seq_b_start = (seqb->start - SEQ_time_left_handle_frame_get(seqb)) + + SEQ_time_left_handle_frame_get(seqa); SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start); - SEQ_time_update_sequence(scene, seqbase, seqb); SEQ_relations_invalidate_cache_preprocessed(scene, seqb); - seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap; + seq_a_start = (seqa->start - SEQ_time_left_handle_frame_get(seqa)) + + SEQ_time_right_handle_frame_get(seqb) + gap; SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start); - SEQ_time_update_sequence(scene, seqbase, seqa); SEQ_relations_invalidate_cache_preprocessed(scene, seqa); } @@ -2241,13 +2200,13 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i switch (lr) { case SEQ_SIDE_LEFT: - if (seq->enddisp <= test->startdisp) { - dist = test->enddisp - seq->startdisp; + if (SEQ_time_right_handle_frame_get(seq) <= SEQ_time_left_handle_frame_get(test)) { + dist = SEQ_time_right_handle_frame_get(test) - SEQ_time_left_handle_frame_get(seq); } break; case SEQ_SIDE_RIGHT: - if (seq->startdisp >= test->enddisp) { - dist = seq->startdisp - test->enddisp; + if (SEQ_time_left_handle_frame_get(seq) >= SEQ_time_right_handle_frame_get(test)) { + dist = SEQ_time_left_handle_frame_get(seq) - SEQ_time_right_handle_frame_get(test); } break; } @@ -2307,14 +2266,6 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) break; } - /* XXX: Should be a generic function. */ - for (iseq = seqbase->first; iseq; iseq = iseq->next) { - if ((iseq->type & SEQ_TYPE_EFFECT) && - (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) { - SEQ_time_update_sequence(scene, seqbase, iseq); - } - } - /* Do this in a new loop since both effects need to be calculated first. */ for (iseq = seqbase->first; iseq; iseq = iseq->next) { if ((iseq->type & SEQ_TYPE_EFFECT) && @@ -2326,10 +2277,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) } } - SEQ_sort(SEQ_active_seqbase_get(ed)); - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - return OPERATOR_FINISHED; } @@ -2446,6 +2394,13 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq) return; } + /* Add curves for strips inside meta strip. */ + if (seq->type == SEQ_TYPE_META) { + LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) { + sequencer_copy_animation(scene, meta_child); + } + } + GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves); if (fcurves == NULL) { return; @@ -2455,6 +2410,7 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq) BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu)); } GSET_FOREACH_END(); + BLI_gset_free(fcurves, NULL); } @@ -2576,8 +2532,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) else { int min_seq_startdisp = INT_MAX; LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { - if (seq->startdisp < min_seq_startdisp) { - min_seq_startdisp = seq->startdisp; + if (SEQ_time_left_handle_frame_get(seq) < min_seq_startdisp) { + min_seq_startdisp = SEQ_time_left_handle_frame_get(seq); } } /* Paste strips relative to the current-frame. */ @@ -2608,13 +2564,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) * in the new list. */ BLI_movelisttolist(ed->seqbasep, &nseqbase); + /* Make sure, that pasted strips have unique names. This has to be done immediately after adding + * strips to seqbase, for lookup cache to work correctly. */ + for (iseq = iseq_first; iseq; iseq = iseq->next) { + SEQ_ensure_unique_name(iseq, scene); + } + for (iseq = iseq_first; iseq; iseq = iseq->next) { if (SEQ_clipboard_pasted_seq_was_active(iseq)) { SEQ_select_active_set(scene, iseq); } - /* Make sure, that pasted strips have unique names. */ - SEQ_ensure_unique_name(iseq, scene); /* Translate after name has been changed, otherwise this will affect animdata of original * strip. */ SEQ_transform_translate_sequence(scene, iseq, ofs); @@ -2692,10 +2652,6 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) seq_act->scene_sound = NULL; seq_other->scene_sound = NULL; - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq_act); - SEQ_time_update_sequence(scene, seqbase, seq_other); - if (seq_act->sound) { BKE_sound_add_scene_sound_defaults(scene, seq_act); } @@ -2938,9 +2894,6 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) /* Correct start/end frames so we don't move. * Important not to set seq->len = len; allow the function to handle it. */ SEQ_add_reload_new_file(bmain, scene, seq, true); - - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { bSound *sound = seq->sound; @@ -3160,7 +3113,7 @@ static bool seq_get_text_strip_cb(Sequence *seq, void *user_data) ListBase *channels = SEQ_channels_displayed_get(ed); /* Only text strips that are not muted and don't end with negative frame. */ if ((seq->type == SEQ_TYPE_TEXT) && !SEQ_render_is_muted(channels, seq) && - (seq->enddisp > cd->scene->r.sfra)) { + (SEQ_time_right_handle_frame_get(seq) > cd->scene->r.sfra)) { BLI_addtail(cd->text_seq, MEM_dupallocN(seq)); } return true; @@ -3218,16 +3171,17 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) char timecode_str_end[32]; /* Write time-code relative to start frame of scene. Don't allow negative time-codes. */ - BLI_timecode_string_from_time(timecode_str_start, - sizeof(timecode_str_start), - -2, - FRA2TIME(max_ii(seq->startdisp - scene->r.sfra, 0)), - FPS, - USER_TIMECODE_SUBRIP); + BLI_timecode_string_from_time( + timecode_str_start, + sizeof(timecode_str_start), + -2, + FRA2TIME(max_ii(SEQ_time_left_handle_frame_get(seq) - scene->r.sfra, 0)), + FPS, + USER_TIMECODE_SUBRIP); BLI_timecode_string_from_time(timecode_str_end, sizeof(timecode_str_end), -2, - FRA2TIME(seq->enddisp - scene->r.sfra), + FRA2TIME(SEQ_time_right_handle_frame_get(seq) - scene->r.sfra), FPS, USER_TIMECODE_SUBRIP); @@ -3295,8 +3249,8 @@ static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { selected = true; - sfra = min_ii(sfra, seq->startdisp); - efra = max_ii(efra, seq->enddisp - 1); + sfra = min_ii(sfra, SEQ_time_left_handle_frame_get(seq)); + efra = max_ii(efra, SEQ_time_right_handle_frame_get(seq) - 1); } } diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 3307c3fde2f..3f91be9e9e8 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -133,6 +133,7 @@ int seq_effect_find_selected(struct Scene *scene, /* Operator helpers. */ bool sequencer_edit_poll(struct bContext *C); +bool sequencer_editing_initialized_and_active(struct bContext *C); /* UNUSED */ /* bool sequencer_strip_poll(struct bContext *C); */ bool sequencer_strip_has_path_poll(struct bContext *C); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 074be0fd120..f237fbc0a12 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -116,13 +116,13 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int if (channel == seq->machine) { switch (sel_side) { case SEQ_SIDE_LEFT: - if (frame > (seq->startdisp)) { + if (frame > (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } break; case SEQ_SIDE_RIGHT: - if (frame < (seq->startdisp)) { + if (frame < (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } @@ -152,13 +152,13 @@ static void select_active_side_range(ListBase *seqbase, } switch (sel_side) { case SEQ_SIDE_LEFT: - if (frame > (seq->startdisp)) { + if (frame > (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } break; case SEQ_SIDE_RIGHT: - if (frame < (seq->startdisp)) { + if (frame < (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } @@ -179,8 +179,8 @@ static void select_linked_time(ListBase *seqbase, Sequence *seq_link) for (seq = seqbase->first; seq; seq = seq->next) { if (seq_link->machine != seq->machine) { - int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0; - int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0; + int left_match = (SEQ_time_left_handle_frame_get(seq) == seq_link->startdisp) ? 1 : 0; + int right_match = (SEQ_time_right_handle_frame_get(seq) == seq_link->enddisp) ? 1 : 0; if (left_match && right_match) { /* Direct match, copy the selection settings. */ @@ -247,8 +247,8 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel void seq_rectf(Sequence *seq, rctf *rect) { - rect->xmin = seq->startdisp; - rect->xmax = seq->enddisp; + rect->xmin = SEQ_time_left_handle_frame_get(seq); + rect->xmax = SEQ_time_right_handle_frame_get(seq); rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM; rect->ymax = seq->machine + SEQ_STRIP_OFSTOP; } @@ -273,12 +273,12 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se (sel == 0 && (seq->flag & SELECT) == 0))) { switch (lr) { case SEQ_SIDE_LEFT: - if (test->startdisp == (seq->enddisp)) { + if (SEQ_time_left_handle_frame_get(test) == (SEQ_time_right_handle_frame_get(seq))) { return seq; } break; case SEQ_SIDE_RIGHT: - if (test->enddisp == (seq->startdisp)) { + if (SEQ_time_right_handle_frame_get(test) == (SEQ_time_left_handle_frame_get(seq))) { return seq; } break; @@ -311,13 +311,18 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ while (seq) { if (seq->machine == (int)y) { /* Check for both normal strips, and strips that have been flipped horizontally. */ - if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) || - ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) { + if (((SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(seq)) && + (SEQ_time_left_handle_frame_get(seq) <= x && + SEQ_time_right_handle_frame_get(seq) >= x)) || + ((SEQ_time_left_handle_frame_get(seq) > SEQ_time_right_handle_frame_get(seq)) && + (SEQ_time_left_handle_frame_get(seq) >= x && + SEQ_time_right_handle_frame_get(seq) <= x))) { if (SEQ_transform_sequence_can_be_translated(seq)) { /* Clamp handles to defined size in pixel space. */ handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx); - displen = (float)abs(seq->startdisp - seq->enddisp); + displen = (float)abs(SEQ_time_left_handle_frame_get(seq) - + SEQ_time_right_handle_frame_get(seq)); /* Don't even try to grab the handles of small strips. */ if (displen / pixelx > 16) { @@ -332,10 +337,10 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ CLAMP(handsize, 7 * pixelx, 30 * pixelx); } - if (handsize + seq->startdisp >= x) { + if (handsize + SEQ_time_left_handle_frame_get(seq) >= x) { *hand = SEQ_SIDE_LEFT; } - else if (-handsize + seq->enddisp <= x) { + else if (-handsize + SEQ_time_right_handle_frame_get(seq) <= x) { *hand = SEQ_SIDE_RIGHT; } } @@ -578,8 +583,8 @@ static void sequencer_select_side_of_frame(const bContext *C, const float x = UI_view2d_region_to_view_x(v2d, mval[0]); LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) { - if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) || - ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) { + if (((x < CFRA) && (SEQ_time_right_handle_frame_get(seq_iter) <= CFRA)) || + ((x >= CFRA) && (SEQ_time_left_handle_frame_get(seq_iter) >= CFRA))) { /* Select left or right. */ seq_iter->flag |= SELECT; recurs_sel_seq(seq_iter); @@ -634,7 +639,8 @@ static void sequencer_select_linked_handle(const bContext *C, case SEQ_SIDE_LEFT: if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) { seq->flag |= SELECT; - select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp); + select_active_side( + ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, SEQ_time_left_handle_frame_get(seq)); } else { seq->flag |= SELECT; @@ -647,7 +653,8 @@ static void sequencer_select_linked_handle(const bContext *C, case SEQ_SIDE_RIGHT: if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) { seq->flag |= SELECT; - select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp); + select_active_side( + ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, SEQ_time_left_handle_frame_get(seq)); } else { seq->flag |= SELECT; @@ -661,7 +668,8 @@ static void sequencer_select_linked_handle(const bContext *C, } else { - select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp); + select_active_side( + ed->seqbasep, sel_side, seq->machine, SEQ_time_left_handle_frame_get(seq)); } } } @@ -1428,10 +1436,10 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) bool test = false; switch (side) { case -1: - test = (timeline_frame >= seq->enddisp); + test = (timeline_frame >= SEQ_time_right_handle_frame_get(seq)); break; case 1: - test = (timeline_frame <= seq->startdisp); + test = (timeline_frame <= SEQ_time_left_handle_frame_get(seq)); break; case 2: test = SEQ_time_strip_intersects_frame(seq, timeline_frame); @@ -1505,10 +1513,10 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op) if (seq->flag & SELECT) { selected = true; if (sel_side == SEQ_SIDE_LEFT) { - *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp); + *frame_limit_p = max_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq)); } else { - *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp); + *frame_limit_p = min_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq)); } } } @@ -1648,7 +1656,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op) float handsize = sequence_handle_size_get_clamped(seq, pixelx); /* Right handle. */ - if (rectf.xmax > (seq->enddisp - handsize)) { + if (rectf.xmax > (SEQ_time_right_handle_frame_get(seq) - handsize)) { if (select) { seq->flag |= SELECT | SEQ_RIGHTSEL; } @@ -1661,7 +1669,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op) } } /* Left handle. */ - if (rectf.xmin < (seq->startdisp + handsize)) { + if (rectf.xmin < (SEQ_time_left_handle_frame_get(seq) + handsize)) { if (select) { seq->flag |= SELECT | SEQ_LEFTSEL; } @@ -1953,7 +1961,8 @@ static bool select_grouped_time_overlap(SeqCollection *strips, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, strips) { - if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) { + if (SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(actseq) && + SEQ_time_right_handle_frame_get(seq) > SEQ_time_left_handle_frame_get(actseq)) { seq->flag |= SELECT; changed = true; } @@ -1971,8 +1980,10 @@ static void query_lower_channel_strips(Sequence *seq_reference, if (seq_test->machine > seq_reference->machine) { continue; /* Not lower channel. */ } - if (seq_test->enddisp <= seq_reference->startdisp || - seq_test->startdisp >= seq_reference->enddisp) { + if (SEQ_time_right_handle_frame_get(seq_test) <= + SEQ_time_left_handle_frame_get(seq_reference) || + SEQ_time_left_handle_frame_get(seq_test) >= + SEQ_time_right_handle_frame_get(seq_reference)) { continue; /* Not intersecting in time. */ } SEQ_collection_append_strip(seq_test, collection); diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c index eab17d876f3..5c929e6673a 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c @@ -74,10 +74,10 @@ static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area) if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) { return false; } - if (min_ii(seq->startdisp, seq->start) > view_area->xmax) { + if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > view_area->xmax) { return false; } - if (max_ii(seq->enddisp, seq->start + seq->len) < view_area->xmin) { + if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < view_area->xmin) { return false; } if (seq->machine + 1.0f < view_area->ymin) { @@ -206,7 +206,7 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi else { if (val_need_update != NULL) { val_need_update->seq_dupli->start = seq->start; - val_need_update->seq_dupli->startdisp = seq->startdisp; + val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(seq); } } } @@ -363,15 +363,16 @@ static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame, static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame) { - if (timeline_frame <= seq->startdisp) { - return seq->startdisp; + if (timeline_frame <= SEQ_time_left_handle_frame_get(seq)) { + return SEQ_time_left_handle_frame_get(seq); } /* Set of "guaranteed" thumbnails. */ - const int frame_index = timeline_frame - seq->startdisp; + const int frame_index = timeline_frame - SEQ_time_left_handle_frame_get(seq); const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq); const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step; - const int nearest_guaranted_absolute_frame = relative_base_frame + seq->startdisp; + const int nearest_guaranted_absolute_frame = relative_base_frame + + SEQ_time_left_handle_frame_get(seq); return nearest_guaranted_absolute_frame; } @@ -426,6 +427,11 @@ void draw_seq_strip_thumbnail(View2D *v2d, float image_height, image_width, thumb_width; rcti crop; + StripElem *se = seq->strip->stripdata; + if (se->orig_height == 0 || se->orig_width == 0) { + return; + } + /* If width of the strip too small ignore drawing thumbnails. */ if ((y2 - y1) / pixely <= 20 * U.dpi_fac) { return; @@ -444,10 +450,11 @@ void draw_seq_strip_thumbnail(View2D *v2d, float thumb_y_end = y1 + thumb_height; float cut_off = 0; - float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : - seq->enddisp; + float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? + (seq->start + seq->len) : + SEQ_time_right_handle_frame_get(seq); if (seq->type == SEQ_TYPE_IMAGE) { - upper_thumb_bound = seq->enddisp; + upper_thumb_bound = SEQ_time_right_handle_frame_get(seq); } float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, thumb_width, &v2d->cur); @@ -473,8 +480,8 @@ void draw_seq_strip_thumbnail(View2D *v2d, } /* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */ - if (IN_RANGE_INCL(seq->startdisp, timeline_frame, thumb_x_end)) { - cut_off = seq->startdisp - timeline_frame; + if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(seq), timeline_frame, thumb_x_end)) { + cut_off = SEQ_time_left_handle_frame_get(seq) - timeline_frame; clipped = true; } diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 93641375d42..f7ca753c052 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -306,8 +306,8 @@ static void seq_view_collection_rect_timeline(Scene *scene, SeqCollection *strip int xmargin = FPS; SEQ_ITERATOR_FOREACH (seq, strips) { - xmin = min_ii(xmin, seq->startdisp); - xmax = max_ii(xmax, seq->enddisp); + xmin = min_ii(xmin, SEQ_time_left_handle_frame_get(seq)); + xmax = max_ii(xmax, SEQ_time_right_handle_frame_get(seq)); ymin = min_ii(ymin, seq->machine); ymax = max_ii(ymax, seq->machine); @@ -373,7 +373,7 @@ void SEQUENCER_OT_view_selected(wmOperatorType *ot) /* Api callbacks. */ ot->exec = sequencer_view_selected_exec; - ot->poll = ED_operator_sequencer_active; + ot->poll = sequencer_editing_initialized_and_active; /* Flags. */ ot->flag = OPTYPE_REGISTER; diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index a498e5e99cf..dd3aac1eae9 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -302,6 +302,7 @@ static float get_default_column_width(const ColumnValues &values) switch (values.type()) { case SPREADSHEET_VALUE_TYPE_BOOL: return 2.0f; + case SPREADSHEET_VALUE_TYPE_INT8: case SPREADSHEET_VALUE_TYPE_INT32: return float_width; case SPREADSHEET_VALUE_TYPE_FLOAT: diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index a29aa1fd026..46e98acb8e8 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -23,6 +23,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type) if (type.is<bool>()) { return SPREADSHEET_VALUE_TYPE_BOOL; } + if (type.is<int8_t>()) { + return SPREADSHEET_VALUE_TYPE_INT8; + } if (type.is<int>()) { return SPREADSHEET_VALUE_TYPE_INT32; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 7f696efabf7..f5315b616d0 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -81,6 +81,9 @@ void GeometryDataSource::foreach_default_column_ids( if (attribute_id.is_anonymous()) { return true; } + if (!bke::allow_procedural_attribute_access(attribute_id.name())) { + return true; + } SpreadsheetColumnID column_id; column_id.name = (char *)attribute_id.name().data(); fn(column_id, false); @@ -509,7 +512,7 @@ class GeometryComponentCacheValue : public SpreadsheetCache::Value { public: /* Stores the result of fields evaluated on a geometry component. Without this, fields would have * to be reevaluated on every redraw. */ - Map<std::pair<AttributeDomain, GField>, GArray<>> arrays; + Map<std::pair<eAttrDomain, GField>, GArray<>> arrays; }; static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, @@ -523,7 +526,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>( std::make_unique<GeometryComponentCacheKey>(component)); - const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; + const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain; const int domain_num = component.attribute_domain_num(domain); for (const auto item : fields_to_show.items()) { StringRef name = item.key; @@ -547,7 +550,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; + const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain; const GeometryComponentType component_type = get_display_component_type(C, object_eval); GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 8b281e5a558..04b4f6d8d06 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -40,7 +40,7 @@ class GeometryDataSource : public DataSource { Object *object_eval_; const GeometrySet geometry_set_; const GeometryComponent *component_; - AttributeDomain domain_; + eAttrDomain domain_; ExtraColumns extra_columns_; /* Some data is computed on the fly only when it is requested. Computing it does not change the @@ -53,7 +53,7 @@ class GeometryDataSource : public DataSource { GeometryDataSource(Object *object_eval, GeometrySet geometry_set, const GeometryComponentType component_type, - const AttributeDomain domain, + const eAttrDomain domain, ExtraColumns extra_columns) : object_eval_(object_eval), geometry_set_(std::move(geometry_set)), diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 724d0783707..ee22f4173ab 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -27,7 +27,7 @@ class GeometryDataSetTreeView; class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { GeometryComponentType component_type_; - std::optional<AttributeDomain> domain_; + std::optional<eAttrDomain> domain_; BIFIconID icon_; public: @@ -35,7 +35,7 @@ class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { StringRef label, BIFIconID icon); GeometryDataSetTreeViewItem(GeometryComponentType component_type, - AttributeDomain domain, + eAttrDomain domain, StringRef label, BIFIconID icon); @@ -113,7 +113,7 @@ GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType c this->set_collapsed(false); } GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, - AttributeDomain domain, + eAttrDomain domain, StringRef label, BIFIconID icon) : component_type_(component_type), domain_(domain), icon_(icon) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc index d76bbbf3be6..166c5de9fc3 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc @@ -84,7 +84,7 @@ static int select_component_domain_invoke(bContext *C, { GeometryComponentType component_type = static_cast<GeometryComponentType>( RNA_int_get(op->ptr, "component_type")); - AttributeDomain attribute_domain = static_cast<AttributeDomain>( + eAttrDomain attribute_domain = static_cast<eAttrDomain>( RNA_int_get(op->ptr, "attribute_domain_type")); SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc index 91ce5c2f6ec..d71a355850f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc @@ -71,6 +71,35 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter, } } } + else if (column_data.type().is<int8_t>()) { + const int value = row_filter.value_int; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + apply_filter_operation( + column_data.typed<int8_t>(), + [&](const int cell) { return cell == value; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed<int8_t>(), + [value](const int cell) { return cell > value; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed<int8_t>(), + [&](const int cell) { return cell < value; }, + prev_mask, + new_indices); + break; + } + } + } else if (column_data.type().is<int>()) { const int value = row_filter.value_int; switch (row_filter.operation) { @@ -166,25 +195,79 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter, } else if (column_data.type().is<ColorGeometry4f>()) { const ColorGeometry4f value = row_filter.value_color; - const float threshold_sq = pow2f(row_filter.threshold); - apply_filter_operation( - column_data.typed<ColorGeometry4f>(), - [&](const ColorGeometry4f cell) { return len_squared_v4v4(cell, value) <= threshold_sq; }, - prev_mask, - new_indices); + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = pow2f(row_filter.threshold); + apply_filter_operation( + column_data.typed<ColorGeometry4f>(), + [&](const ColorGeometry4f cell) { + return len_squared_v4v4(cell, value) <= threshold_sq; + }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed<ColorGeometry4f>(), + [&](const ColorGeometry4f cell) { + return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a; + }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed<ColorGeometry4f>(), + [&](const ColorGeometry4f cell) { + return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a; + }, + prev_mask, + new_indices); + break; + } + } } else if (column_data.type().is<ColorGeometry4b>()) { const ColorGeometry4b value = row_filter.value_byte_color; - const float4 value_floats = {(float)value.r, (float)value.g, (float)value.b, (float)value.a}; - const float threshold_sq = pow2f(row_filter.threshold); - apply_filter_operation( - column_data.typed<ColorGeometry4b>(), - [&](const ColorGeometry4b cell) { - const float4 cell_floats = {(float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a}; - return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq; - }, - prev_mask, - new_indices); + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float4 value_floats = { + (float)value.r, (float)value.g, (float)value.b, (float)value.a}; + const float threshold_sq = pow2f(row_filter.threshold); + apply_filter_operation( + column_data.typed<ColorGeometry4b>(), + [&](const ColorGeometry4b cell) { + const float4 cell_floats = { + (float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a}; + return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq; + }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed<ColorGeometry4b>(), + [&](const ColorGeometry4b cell) { + return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a; + }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed<ColorGeometry4b>(), + [&](const ColorGeometry4b cell) { + return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a; + }, + prev_mask, + new_indices); + break; + } + } } else if (column_data.type().is<InstanceReference>()) { const StringRef value = row_filter.value_string; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index 7c1ac024c12..6d8febc0e45 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -39,11 +39,7 @@ static void filter_panel_id_fn(void *UNUSED(row_filter_v), char *r_name) static std::string operation_string(const eSpreadsheetColumnValueType data_type, const eSpreadsheetFilterOperation operation) { - if (ELEM(data_type, - SPREADSHEET_VALUE_TYPE_BOOL, - SPREADSHEET_VALUE_TYPE_INSTANCES, - SPREADSHEET_VALUE_TYPE_COLOR, - SPREADSHEET_VALUE_TYPE_BYTE_COLOR)) { + if (ELEM(data_type, SPREADSHEET_VALUE_TYPE_BOOL, SPREADSHEET_VALUE_TYPE_INSTANCES)) { return "="; } @@ -63,6 +59,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter, const eSpreadsheetColumnValueType data_type) { switch (data_type) { + case SPREADSHEET_VALUE_TYPE_INT8: case SPREADSHEET_VALUE_TYPE_INT32: return std::to_string(row_filter.value_int); case SPREADSHEET_VALUE_TYPE_FLOAT: { @@ -200,6 +197,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) } switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) { + case SPREADSHEET_VALUE_TYPE_INT8: + uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); + uiItemR(layout, filter_ptr, "value_int8", 0, IFACE_("Value"), ICON_NONE); + break; case SPREADSHEET_VALUE_TYPE_INT32: uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE); @@ -232,15 +233,21 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE); break; case SPREADSHEET_VALUE_TYPE_COLOR: + uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE); - uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); + if (operation == SPREADSHEET_ROW_FILTER_EQUAL) { + uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); + } break; case SPREADSHEET_VALUE_TYPE_STRING: uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE); break; case SPREADSHEET_VALUE_TYPE_BYTE_COLOR: + uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); uiItemR(layout, filter_ptr, "value_byte_color", 0, IFACE_("Value"), ICON_NONE); - uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); + if (operation == SPREADSHEET_ROW_FILTER_EQUAL) { + uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); + } break; case SPREADSHEET_VALUE_TYPE_UNKNOWN: uiItemL(layout, IFACE_("Unknown column type"), ICON_ERROR); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 48abe71e35f..9ed2fec96db 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -594,7 +594,7 @@ static char *view3d_mat_drop_tooltip(bContext *C, { const char *name = WM_drag_get_item_name(drag); ARegion *region = CTX_wm_region(C); - int mval[2] = { + const int mval[2] = { xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin, }; diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c index 1e54afe46f0..395df42b2cb 100644 --- a/source/blender/editors/space_view3d/view3d_cursor_snap.c +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -8,7 +8,6 @@ */ #include "DNA_object_types.h" -#include "DNA_scene_types.h" #include "BLI_listbase.h" #include "BLI_rect.h" @@ -53,7 +52,7 @@ typedef struct SnapCursorDataIntern { struct SnapObjectContext *snap_context_v3d; const Scene *scene; - short snap_elem_hidden; + eSnapMode snap_elem_hidden; float prevpoint_stack[3]; @@ -373,7 +372,7 @@ void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d, const float normal[3], const uchar color_line[4], const uchar color_point[4], - const short snap_elem_type) + const eSnapMode snap_elem_type) { if (!loc_prev && !loc_curr) { return; @@ -538,9 +537,9 @@ static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, const w /** \name Update * \{ */ -static short v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene) +static eSnapMode v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene) { - short snap_elements = snap_state->snap_elem_force; + eSnapMode snap_elements = snap_state->snap_elem_force; if (!snap_elements) { return scene->toolsettings->snap_mode; } @@ -586,7 +585,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, v3d_cursor_snap_context_ensure(scene); float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3]; - short snap_elem = 0; + eSnapMode snap_elem = SCE_SNAP_MODE_NONE; int snap_elem_index[3] = {-1, -1, -1}; int index = -1; @@ -595,8 +594,8 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, zero_v3(face_nor); unit_m3(omat); - ushort snap_elements = v3d_cursor_snap_elements(state, scene); - data_intern->snap_elem_hidden = 0; + eSnapMode snap_elements = v3d_cursor_snap_elements(state, scene); + data_intern->snap_elem_hidden = SCE_SNAP_MODE_NONE; const bool calc_plane_omat = v3d_cursor_snap_calc_plane(); if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE)) { data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE; @@ -612,7 +611,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) { snap_data->is_enabled = false; if (!calc_plane_omat) { - snap_data->snap_elem = 0; + snap_data->snap_elem = SCE_SNAP_MODE_NONE; return; } snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE; @@ -620,8 +619,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, } #endif - if (snap_elements & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + if (snap_elements & SCE_SNAP_MODE_GEOM) { float prev_co[3] = {0.0f}; if (state->prevpoint) { copy_v3_v3(prev_co, state->prevpoint); @@ -647,7 +645,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, v3d, snap_elements, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, .edit_mode_type = edit_mode_type, .use_occlusion_test = use_occlusion_test, }, @@ -668,7 +666,8 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, if (calc_plane_omat) { RegionView3D *rv3d = region->regiondata; - bool orient_surface = snap_elem && (state->plane_orient == V3D_PLACE_ORIENT_SURFACE); + bool orient_surface = (snap_elem != SCE_SNAP_MODE_NONE) && + (state->plane_orient == V3D_PLACE_ORIENT_SURFACE); if (orient_surface) { copy_m3_m4(omat, obmat); } @@ -699,7 +698,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, } } - float *co_depth = snap_elem ? co : scene->cursor.location; + float *co_depth = (snap_elem != SCE_SNAP_MODE_NONE) ? co : scene->cursor.location; snap_elem &= ~data_intern->snap_elem_hidden; if (snap_elem == 0) { RegionView3D *rv3d = region->regiondata; @@ -815,7 +814,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust } const bool draw_plane = state->draw_plane || state->draw_box; - if (!snap_data->snap_elem && !draw_plane) { + if (snap_data->snap_elem == SCE_SNAP_MODE_NONE && !draw_plane) { return; } @@ -833,7 +832,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust v3d_cursor_plane_draw(rv3d, state->plane_axis, matrix); } - if (snap_data->snap_elem && (state->draw_point || state->draw_box)) { + if (snap_data->snap_elem != SCE_SNAP_MODE_NONE && (state->draw_point || state->draw_box)) { const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ? state->prevpoint : NULL; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 5b068750d76..b9e4c19295d 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1786,11 +1786,13 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph, } /* Disable other overlays (set all available _HIDE_ flags). */ v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT | - V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES | - V3D_OVERLAY_HIDE_OBJECT_ORIGINS; + V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS; if ((draw_flags & V3D_OFSDRAW_SHOW_OBJECT_EXTRAS) == 0) { v3d.overlay.flag |= V3D_OVERLAY_HIDE_OBJECT_XTRAS; } + if ((object_type_exclude_viewport_override & (1 << OB_ARMATURE)) != 0) { + v3d.overlay.flag |= V3D_OVERLAY_HIDE_BONES; + } v3d.flag |= V3D_HIDE_HELPLINES; } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index a65e9a8d506..5fbdbef676c 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -910,7 +910,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, v3d, SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, .edit_mode_type = SNAP_GEOM_FINAL, .use_occlusion_test = true, }, diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 567022cc9d1..9aae30c4a7e 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -359,7 +359,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, v3d, SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, .edit_mode_type = SNAP_GEOM_CAGE, }, mval_fl, @@ -374,7 +374,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, depsgraph, v3d, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, .edit_mode_type = SNAP_GEOM_CAGE, }, ray_start, @@ -1228,11 +1228,7 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup) gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); - RNA_enum_set(gizmo->ptr, - "snap_elements_force", - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */ - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)); + RNA_enum_set(gizmo->ptr, "snap_elements_force", SCE_SNAP_MODE_GEOM); ED_gizmotypes_snap_3d_flag_set(gizmo, V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE); WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c index 19e064438fc..c4eff01375b 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_walk.c +++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c @@ -412,7 +412,7 @@ static bool walk_floor_distance_get(RegionView3D *rv3d, walk->depsgraph, walk->v3d, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, /* Avoid having to convert the edit-mesh to a regular mesh. */ .edit_mode_type = SNAP_GEOM_EDIT, }, @@ -454,7 +454,7 @@ static bool walk_ray_cast(RegionView3D *rv3d, walk->depsgraph, walk->v3d, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, }, ray_start, ray_normal, diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index eefc085bdf8..d3b82476d09 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -695,7 +695,7 @@ static bool view3d_interactive_add_calc_snap(bContext *UNUSED(C), if (r_is_snap_invert) { *r_is_snap_invert = snap_data->is_snap_invert; } - return snap_data->snap_elem != 0; + return snap_data->snap_elem != SCE_SNAP_MODE_NONE; } /** \} */ @@ -1303,7 +1303,7 @@ static int idp_rna_snap_target_get_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop)) { V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get(); - if (!snap_state->snap_elem_force) { + if (snap_state->snap_elem_force == SCE_SNAP_MODE_NONE) { return PLACE_SNAP_TO_DEFAULT; } @@ -1316,7 +1316,7 @@ static void idp_rna_snap_target_set_fn(struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), int value) { - short snap_mode = 0; /* #toolsettings->snap_mode. */ + eSnapMode snap_mode = SCE_SNAP_MODE_NONE; /* #toolsettings->snap_mode. */ const enum ePlace_SnapTo snap_to = value; if (snap_to == PLACE_SNAP_TO_GEOMETRY) { snap_mode = SCE_SNAP_MODE_GEOM; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index efe89621e7b..8eff9ee472f 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -57,8 +57,6 @@ #include "BKE_tracking.h" #include "BKE_workspace.h" -#include "DEG_depsgraph.h" - #include "WM_api.h" #include "WM_toolsystem.h" #include "WM_types.h" @@ -2878,6 +2876,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) struct SelectPick_Params params = {0}; ED_select_pick_params_from_operator(op->ptr, ¶ms); + const bool vert_without_handles = RNA_boolean_get(op->ptr, "vert_without_handles"); bool center = RNA_boolean_get(op->ptr, "center"); bool enumerate = RNA_boolean_get(op->ptr, "enumerate"); /* Only force object select for edit-mode to support vertex parenting, @@ -2932,7 +2931,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op) changed = ED_lattice_select_pick(C, mval, ¶ms); } else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) { - changed = ED_curve_editnurb_select_pick(C, mval, ED_view3d_select_dist_px(), ¶ms); + changed = ED_curve_editnurb_select_pick( + C, mval, ED_view3d_select_dist_px(), vert_without_handles, ¶ms); } else if (obedit->type == OB_MBALL) { changed = ED_mball_select_pick(C, mval, ¶ms); @@ -3009,6 +3009,15 @@ void VIEW3D_OT_select(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit mode only)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* Needed for select-through to usefully drag handles, see: T98254. + * NOTE: this option may be removed and become default behavior, see design task: T98552. */ + prop = RNA_def_boolean(ot->srna, + "vert_without_handles", + 0, + "Control Point Without Handles", + "Only select the curve control point, not it's handles"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_int_vector(ot->srna, "location", 2, diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index a7e2f616c9e..960d9a25ca7 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1425,9 +1425,6 @@ static void drawTransformView(const struct bContext *C, ARegion *region, void *a /* edge slide, vert slide */ drawEdgeSlide(t); drawVertSlide(t); - - /* Rotation */ - drawDial3d(t); } } @@ -1579,6 +1576,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) /* do we check for parameter? */ if (transformModeUseSnap(t)) { if (!(t->modifiers & MOD_SNAP) != !(t->tsnap.flag & SCE_SNAP)) { + /* Type is #eSnapFlag, but type must match various snap attributes in #ToolSettings. */ char *snap_flag_ptr; wmMsgParams_RNA msg_key_params = {{0}}; @@ -1786,13 +1784,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1; t->is_launch_event_drag = event ? (event->val == KM_CLICK_DRAG) : false; - /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate - * (which can have type = 0) */ - /* For gizmo only, so assume LEFTMOUSE. */ - if (t->launch_event == 0) { - t->launch_event = LEFTMOUSE; - } - unit_m3(t->spacemtx); initTransInfo(C, t, op, event); @@ -2061,3 +2052,17 @@ bool checkUseAxisMatrix(TransInfo *t) return false; } + +bool transform_apply_matrix(TransInfo *t, float mat[4][4]) +{ + if (t->transform_matrix != NULL) { + t->transform_matrix(t, mat); + return true; + } + return false; +} + +void transform_final_value_get(const TransInfo *t, float *value, const int value_num) +{ + memcpy(value, t->values_final, sizeof(float) * value_num); +} diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index a3df6a44682..a35942aedec 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -13,6 +13,7 @@ #include "DNA_listBase.h" #include "DNA_object_enums.h" +#include "DNA_scene_types.h" #include "DEG_depsgraph.h" @@ -153,7 +154,8 @@ typedef enum { } eTModifier; /** #TransSnap.status */ -typedef enum { +typedef enum eTSnap { + SNAP_RESETTED = 0, SNAP_FORCED = 1 << 0, TARGET_INIT = 1 << 1, /* Special flag for snap to grid. */ @@ -294,11 +296,14 @@ typedef struct TransSnapPoint { } TransSnapPoint; typedef struct TransSnap { - char flag; - char mode; - short target; - short modePoint; - short modeSelect; + /* Snapping options stored as flags */ + eSnapFlag flag; + /* Method(s) used for snapping source to target */ + eSnapMode mode; + /* Part of source to snap to target */ + eSnapSourceSelect source_select; + /* Determines which objects are possible target */ + eSnapTargetSelect target_select; bool align; bool project; bool snap_self; @@ -306,7 +311,7 @@ typedef struct TransSnap { bool use_backface_culling; eTSnap status; /* Snapped Element Type (currently for objects only). */ - char snapElem; + eSnapMode snapElem; /** snapping from this point (in global-space). */ float snapTarget[3]; /** to this point (in global-space). */ @@ -533,6 +538,13 @@ typedef struct TransInfo { /* Event handler function that determines whether the viewport needs to be redrawn. */ eRedrawFlag (*handleEvent)(struct TransInfo *, const struct wmEvent *); + /** + * Optional callback to transform a single matrix. + * + * \note used by the gizmo to transform the matrix used to position it. + */ + void (*transform_matrix)(struct TransInfo *t, float mat_xform[4][4]); + /** Constraint Data. */ TransCon con; @@ -713,6 +725,12 @@ void removeAspectRatio(TransInfo *t, float vec[2]); */ struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf); +/** + * Transform a single matrix using the current `t->final_values`. + */ +bool transform_apply_matrix(TransInfo *t, float mat[4][4]); +void transform_final_value_get(const TransInfo *t, float *value, int value_num); + /** \} */ /* -------------------------------------------------------------------- */ @@ -725,7 +743,6 @@ struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf); bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]); bool gimbal_axis_object(struct Object *ob, float gmat[3][3]); -void drawDial3d(const TransInfo *t); /** \} */ diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 018468dcd03..d9b971c5478 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1607,10 +1607,9 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc) } } -void animrecord_check_state(TransInfo *t, struct Object *ob) +void animrecord_check_state(TransInfo *t, struct ID *id) { Scene *scene = t->scene; - ID *id = &ob->id; wmTimer *animtimer = t->animtimer; ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL; diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 7080deaec66..037fbe26c77 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -95,7 +95,7 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc); /** * For the realtime animation recording feature, handle overlapping data. */ -void animrecord_check_state(TransInfo *t, struct Object *ob); +void animrecord_check_state(TransInfo *t, struct ID *id); /* transform_convert_action.c */ diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 3c1101d48a5..e1b25acb21e 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -1471,7 +1471,7 @@ void recalcData_pose(TransInfo *t) /* XXX: this currently doesn't work, since flags aren't set yet! */ int targetless_ik = (t->flag & T_AUTOIK); - animrecord_check_state(t, ob); + animrecord_check_state(t, &ob->id); autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik); } diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c index 54222fbb117..2039daee386 100644 --- a/source/blender/editors/transform/transform_convert_graph.c +++ b/source/blender/editors/transform/transform_convert_graph.c @@ -24,12 +24,9 @@ #include "UI_view2d.h" #include "transform.h" -#include "transform_snap.h" - #include "transform_convert.h" -#include "transform_snap.h" - #include "transform_mode.h" +#include "transform_snap.h" typedef struct TransDataGraph { float unit_scale; diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c index 5255cc4412e..b07d2bda0c5 100644 --- a/source/blender/editors/transform/transform_convert_mask.c +++ b/source/blender/editors/transform/transform_convert_mask.c @@ -261,18 +261,10 @@ void createTransMaskingData(bContext *C, TransInfo *t) tc->data_len = 0; - if (!mask) { + if (!ED_maskedit_mask_visible_splines_poll(C)) { return; } - if (t->spacetype == SPACE_CLIP) { - SpaceClip *sc = t->area->spacedata.first; - MovieClip *clip = ED_space_clip_get_clip(sc); - if (!clip) { - return; - } - } - /* count */ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index d2585493679..5879a65eb4b 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -884,7 +884,7 @@ void recalcData_objects(TransInfo *t) /* TODO: autokeyframe calls need some setting to specify to add samples * (FPoints) instead of keyframes? */ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) { - animrecord_check_state(t, ob); + animrecord_check_state(t, &ob->id); autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode); } diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 3735ff0727c..226b0f84f14 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -278,76 +278,7 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips if (SEQ_transform_test_overlap(seqbase, seq)) { SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene); } - - SEQ_time_update_sequence(t->scene, seqbase, seq); - } -} - -static bool seq_transform_check_overlap(SeqCollection *transformed_strips) -{ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - if (seq->flag & SEQ_OVERLAP) { - return true; - } - } - return false; -} - -static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips) -{ - SeqCollection *collection = SEQ_collection_create(__func__); - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) { - SEQ_collection_append_strip(seq, collection); - } - } - return collection; -} - -/* Query strips positioned after left edge of transformed strips bound-box. */ -static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips) -{ - int minframe = MAXFRAME; - { - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - minframe = min_ii(minframe, seq->startdisp); - } } - - SeqCollection *collection = SEQ_collection_create(__func__); - LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if ((seq->flag & SELECT) == 0 && seq->startdisp >= minframe) { - SEQ_collection_append_strip(seq, collection); - } - } - return collection; -} - -static void seq_transform_update_effects(Scene *scene, - ListBase *seqbasep, - SeqCollection *collection) -{ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, collection) { - if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) { - SEQ_time_update_sequence(scene, seqbasep, seq); - } - } -} - -/* Check if effect strips with input are transformed. */ -static bool seq_transform_check_strip_effects(SeqCollection *transformed_strips) -{ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) { - return true; - } - } - return false; } static ListBase *seqbase_active_get(const TransInfo *t) @@ -356,241 +287,15 @@ static ListBase *seqbase_active_get(const TransInfo *t) return SEQ_active_seqbase_get(ed); } -/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal - * to overlap of transformed strips. */ -static void seq_transform_handle_expand_to_fit(Scene *scene, - ListBase *seqbasep, - SeqCollection *transformed_strips, - bool use_sync_markers) -{ - ListBase *markers = &scene->markers; - - SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips); - - /* Temporarily move right side strips beyond timeline boundary. */ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, right_side_strips) { - seq->machine += MAXSEQ * 2; - } - - /* Shuffle transformed standalone strips. This is because transformed strips can overlap with - * strips on left side. */ - SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips); - SEQ_transform_seqbase_shuffle_time( - standalone_strips, seqbasep, scene, markers, use_sync_markers); - SEQ_collection_free(standalone_strips); - - /* Move temporarily moved strips back to their original place and tag for shuffling. */ - SEQ_ITERATOR_FOREACH (seq, right_side_strips) { - seq->machine -= MAXSEQ * 2; - } - /* Shuffle again to displace strips on right side. Final effect shuffling is done in - * SEQ_transform_handle_overlap. */ - SEQ_transform_seqbase_shuffle_time( - right_side_strips, seqbasep, scene, markers, use_sync_markers); - seq_transform_update_effects(scene, seqbasep, right_side_strips); - SEQ_collection_free(right_side_strips); -} - -static SeqCollection *query_overwrite_targets(ListBase *seqbasep, - SeqCollection *transformed_strips) -{ - SeqCollection *collection = SEQ_query_unselected_strips(seqbasep); - - Sequence *seq, *seq_transformed; - SEQ_ITERATOR_FOREACH (seq, collection) { - bool does_overlap = false; - - SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) { - /* Effects of transformed strips can be unselected. These must not be included. */ - if (seq == seq_transformed) { - SEQ_collection_remove_strip(seq, collection); - } - if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) { - does_overlap = true; - } - } - - if (!does_overlap) { - SEQ_collection_remove_strip(seq, collection); - } - } - - return collection; -} - -typedef enum eOvelapDescrition { - /* No overlap. */ - STRIP_OVERLAP_NONE, - /* Overlapping strip covers overlapped completely. */ - STRIP_OVERLAP_IS_FULL, - /* Overlapping strip is inside overlapped. */ - STRIP_OVERLAP_IS_INSIDE, - /* Partial overlap between 2 strips. */ - STRIP_OVERLAP_LEFT_SIDE, - STRIP_OVERLAP_RIGHT_SIDE, -} eOvelapDescrition; - -static eOvelapDescrition overlap_description_get(const Sequence *transformed, - const Sequence *target) -{ - if (transformed->startdisp <= target->startdisp && transformed->enddisp >= target->enddisp) { - return STRIP_OVERLAP_IS_FULL; - } - if (transformed->startdisp > target->startdisp && transformed->enddisp < target->enddisp) { - return STRIP_OVERLAP_IS_INSIDE; - } - if (transformed->startdisp <= target->startdisp && target->startdisp <= transformed->enddisp) { - return STRIP_OVERLAP_LEFT_SIDE; - } - if (transformed->startdisp <= target->enddisp && target->enddisp <= transformed->enddisp) { - return STRIP_OVERLAP_RIGHT_SIDE; - } - return STRIP_OVERLAP_NONE; -} - -/* Split strip in 3 parts, remove middle part and fit transformed inside. */ -static void seq_transform_handle_overwrite_split(Scene *scene, - ListBase *seqbasep, - const Sequence *transformed, - Sequence *target) -{ - /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass - * NULL here. */ - Main *bmain = NULL; - - Sequence *split_strip = SEQ_edit_strip_split( - bmain, scene, seqbasep, target, transformed->startdisp, SEQ_SPLIT_SOFT, NULL); - SEQ_edit_strip_split( - bmain, scene, seqbasep, split_strip, transformed->enddisp, SEQ_SPLIT_SOFT, NULL); - SEQ_edit_flag_for_removal(scene, seqbasep, split_strip); - SEQ_edit_remove_flagged_sequences(scene, seqbasep); -} - -/* Trim strips by adjusting handle position. - * This is bit more complicated in case overlap happens on effect. */ -static void seq_transform_handle_overwrite_trim(Scene *scene, - ListBase *seqbasep, - const Sequence *transformed, - Sequence *target, - const eOvelapDescrition overlap) -{ - SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain); - - /* Expand collection by adding all target's children, effects and their children. */ - if ((target->type & SEQ_TYPE_EFFECT) != 0) { - SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain); - } - - /* Trim all non effects, that have influence on effect length which is overlapping. */ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, targets) { - if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) { - continue; - } - if (overlap == STRIP_OVERLAP_LEFT_SIDE) { - SEQ_time_left_handle_frame_set(seq, transformed->enddisp); - } - else { - BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE); - SEQ_time_right_handle_frame_set(seq, transformed->startdisp); - } - - SEQ_time_update_sequence(scene, seqbasep, seq); - } - SEQ_collection_free(targets); -} - -static void seq_transform_handle_overwrite(Scene *scene, - ListBase *seqbasep, - SeqCollection *transformed_strips) -{ - SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips); - SeqCollection *strips_to_delete = SEQ_collection_create(__func__); - - Sequence *target; - Sequence *transformed; - SEQ_ITERATOR_FOREACH (target, targets) { - SEQ_ITERATOR_FOREACH (transformed, transformed_strips) { - if (transformed->machine != target->machine) { - continue; - } - - const eOvelapDescrition overlap = overlap_description_get(transformed, target); - - if (overlap == STRIP_OVERLAP_IS_FULL) { - SEQ_collection_append_strip(target, strips_to_delete); - } - else if (overlap == STRIP_OVERLAP_IS_INSIDE) { - seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target); - } - else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) { - seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap); - } - } - } - - SEQ_collection_free(targets); - - /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()` - * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */ - if (SEQ_collection_len(strips_to_delete) > 0) { - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, strips_to_delete) { - SEQ_edit_flag_for_removal(scene, seqbasep, seq); - } - SEQ_edit_remove_flagged_sequences(scene, seqbasep); - } - SEQ_collection_free(strips_to_delete); -} - -static void seq_transform_handle_overlap_shuffle(Scene *scene, - ListBase *seqbasep, - SeqCollection *transformed_strips, - bool use_sync_markers) -{ - ListBase *markers = &scene->markers; - - /* Shuffle non strips with no effects attached. */ - SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips); - SEQ_transform_seqbase_shuffle_time( - standalone_strips, seqbasep, scene, markers, use_sync_markers); - SEQ_collection_free(standalone_strips); -} - -void SEQ_transform_handle_overlap(Scene *scene, - ListBase *seqbasep, - SeqCollection *transformed_strips, - bool use_sync_markers) +static bool seq_transform_check_overlap(SeqCollection *transformed_strips) { - const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene); - - switch (overlap_mode) { - case SEQ_OVERLAP_EXPAND: - seq_transform_handle_expand_to_fit(scene, seqbasep, transformed_strips, use_sync_markers); - break; - case SEQ_OVERLAP_OVERWRITE: - seq_transform_handle_overwrite(scene, seqbasep, transformed_strips); - break; - case SEQ_OVERLAP_SHUFFLE: - seq_transform_handle_overlap_shuffle(scene, seqbasep, transformed_strips, use_sync_markers); - break; - } - - if (seq_transform_check_strip_effects(transformed_strips)) { - /* Update effect strips based on strips just moved in time. */ - seq_transform_update_effects(scene, seqbasep, transformed_strips); - } - - /* If any effects still overlap, we need to move them up. - * In some cases other strips can be overlapping still, see T90646. */ Sequence *seq; SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - if (SEQ_transform_test_overlap(seqbasep, seq)) { - SEQ_transform_seqbase_shuffle(seqbasep, seq, scene); + if (seq->flag & SEQ_OVERLAP) { + return true; } - seq->flag &= ~SEQ_OVERLAP; } + return false; } static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer *tc) @@ -627,18 +332,17 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c return; } + TransSeq *ts = tc->custom.type.data; ListBase *seqbasep = seqbase_active_get(t); Scene *scene = t->scene; const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag & SEQ_MARKER_TRANS) != 0; if (seq_transform_check_overlap(transformed_strips)) { - SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, use_sync_markers); + SEQ_transform_handle_overlap( + scene, seqbasep, transformed_strips, ts->time_dependent_strips, use_sync_markers); } - seq_transform_update_effects(scene, seqbasep, transformed_strips); SEQ_collection_free(transformed_strips); - - SEQ_sort(ed->seqbasep); DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS); free_transform_custom_data(custom_data); } @@ -662,7 +366,10 @@ typedef enum SeqInputSide { static Sequence *effect_input_get(Sequence *effect, SeqInputSide side) { Sequence *input = effect->seq1; - if (effect->seq2 && (effect->seq2->startdisp - effect->seq1->startdisp) * side > 0) { + if (effect->seq2 && (SEQ_time_left_handle_frame_get(effect->seq2) - + SEQ_time_left_handle_frame_get(effect->seq1)) * + side > + 0) { input = effect->seq2; } return input; @@ -825,23 +532,6 @@ void createTransSeqData(TransInfo *t) /** \name UVs Transform Flush * \{ */ -/* commented _only_ because the meta may have animation data which - * needs moving too T28158. */ - -BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag) -{ - /* Calculate this strip and all nested strips. - * Children are ALWAYS transformed first so we don't need to do this in another loop. - */ - - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(sce)); - SEQ_time_update_sequence(sce, seqbase, seq); - - if (sel_flag == SELECT) { - SEQ_offset_animdata(sce, seq, seq->start - old_start); - } -} - static void view2d_edge_pan_loc_compensate(TransInfo *t, float loc_in[2], float r_loc[2]) { TransSeq *ts = (TransSeq *)TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data; @@ -914,24 +604,24 @@ static void flushTransSeq(TransInfo *t) break; } case SEQ_LEFTSEL: { /* No vertical transform. */ - int old_startdisp = seq->startdisp; - SEQ_time_left_handle_frame_set(seq, new_frame); - SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); - SEQ_time_update_sequence(t->scene, seqbasep, seq); - if (abs(seq->startdisp - old_startdisp) > abs(max_offset)) { - max_offset = seq->startdisp - old_startdisp; + int old_startdisp = SEQ_time_left_handle_frame_get(seq); + SEQ_time_left_handle_frame_set(t->scene, seq, new_frame); + SEQ_transform_handle_xlimits( + t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(t->scene, seq); + if (abs(SEQ_time_left_handle_frame_get(seq) - old_startdisp) > abs(max_offset)) { + max_offset = SEQ_time_left_handle_frame_get(seq) - old_startdisp; } break; } case SEQ_RIGHTSEL: { /* No vertical transform. */ - int old_enddisp = seq->enddisp; - SEQ_time_right_handle_frame_set(seq, new_frame); - SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); - SEQ_time_update_sequence(t->scene, seqbasep, seq); - if (abs(seq->enddisp - old_enddisp) > abs(max_offset)) { - max_offset = seq->enddisp - old_enddisp; + int old_enddisp = SEQ_time_right_handle_frame_get(seq); + SEQ_time_right_handle_frame_set(t->scene, seq, new_frame); + SEQ_transform_handle_xlimits( + t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(t->scene, seq); + if (abs(SEQ_time_right_handle_frame_get(seq) - old_enddisp) > abs(max_offset)) { + max_offset = SEQ_time_right_handle_frame_get(seq) - old_enddisp; } break; } @@ -945,15 +635,6 @@ static void flushTransSeq(TransInfo *t) SEQ_offset_animdata(t->scene, seq, max_offset); } - /* Update effect length and position. */ - if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) { - for (seq = seqbasep->first; seq; seq = seq->next) { - if (seq->seq1 || seq->seq2 || seq->seq3) { - SEQ_time_update_sequence(t->scene, seqbasep, seq); - } - } - } - /* need to do the overlap check in a new loop otherwise adjacent strips * will not be updated and we'll get false positives */ SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc); diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c index deae51a1149..76c6632039a 100644 --- a/source/blender/editors/transform/transform_convert_sequencer_image.c +++ b/source/blender/editors/transform/transform_convert_sequencer_image.c @@ -154,6 +154,42 @@ void createTransSeqImageData(TransInfo *t) SEQ_collection_free(strips); } +static bool autokeyframe_sequencer_image(bContext *C, + Scene *scene, + StripTransform *transform, + const int tmode) +{ + PointerRNA ptr; + PropertyRNA *prop; + RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr); + + const bool around_cursor = scene->toolsettings->sequencer_tool_settings->pivot_point == + V3D_AROUND_CURSOR; + const bool do_loc = tmode == TFM_TRANSLATION || around_cursor; + const bool do_rot = tmode == TFM_ROTATION; + const bool do_scale = tmode == TFM_RESIZE; + + bool changed = false; + if (do_rot) { + prop = RNA_struct_find_property(&ptr, "rotation"); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + } + if (do_loc) { + prop = RNA_struct_find_property(&ptr, "offset_x"); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + prop = RNA_struct_find_property(&ptr, "offset_y"); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + } + if (do_scale) { + prop = RNA_struct_find_property(&ptr, "scale_x"); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + prop = RNA_struct_find_property(&ptr, "scale_y"); + changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, CFRA, false); + } + + return changed; +} + void recalcData_sequencer_image(TransInfo *t) { TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); @@ -187,6 +223,7 @@ void recalcData_sequencer_image(TransInfo *t) copy_v2_v2(translation, tdseq->orig_origin_position); sub_v2_v2(translation, origin); mul_v2_v2(translation, mirror); + translation[0] *= t->scene->r.yasp / t->scene->r.xasp; transform->xofs = tdseq->orig_translation[0] - translation[0]; transform->yofs = tdseq->orig_translation[1] - translation[1]; @@ -199,6 +236,12 @@ void recalcData_sequencer_image(TransInfo *t) if (t->mode == TFM_ROTATION) { transform->rotation = tdseq->orig_rotation - t->values_final[0]; } + + if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) { + animrecord_check_state(t, &t->scene->id); + autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode); + } + SEQ_relations_invalidate_cache_preprocessed(t->scene, seq); } } @@ -211,9 +254,6 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo * TransData2D *td2d = NULL; int i; - PointerRNA ptr; - PropertyRNA *prop; - for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) { TransDataSeq *tdseq = td->extra; Sequence *seq = tdseq->seq; @@ -225,24 +265,8 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo * continue; } - Scene *scene = t->scene; - RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr); - - if (t->mode == TFM_ROTATION) { - prop = RNA_struct_find_property(&ptr, "rotation"); - ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); - } - if (t->mode == TFM_TRANSLATION) { - prop = RNA_struct_find_property(&ptr, "offset_x"); - ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); - prop = RNA_struct_find_property(&ptr, "offset_y"); - ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); - } - if (t->mode == TFM_RESIZE) { - prop = RNA_struct_find_property(&ptr, "scale_x"); - ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); - prop = RNA_struct_find_property(&ptr, "scale_y"); - ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + if (IS_AUTOKEY_ON(t->scene)) { + autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode); } } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 975dbc2e986..e45cac36736 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -358,6 +358,10 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) { t->options |= CTX_SEQUENCER_IMAGE; + + /* Needed for autokeying transforms in preview during playback. */ + bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C)); + t->animtimer = (animscreen) ? animscreen->animtimer : NULL; } setTransformViewAspect(t, t->aspect); diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index aa8dad2b95f..5b749e05052 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -45,7 +45,6 @@ #include "WM_api.h" #include "WM_message.h" #include "WM_types.h" -#include "wm.h" #include "ED_armature.h" #include "ED_gizmo_library.h" @@ -71,6 +70,10 @@ #include "GPU_state.h" +static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup, + const float twmat[4][4], + const float scale[3]); + /* return codes for select, and drawing flags */ #define MAN_TRANS_X (1 << 0) @@ -155,6 +158,9 @@ typedef struct GizmoGroup { float viewinv_m3[3][3]; } prev; + /* Only for Rotate operator. */ + float rotation; + struct wmGizmo *gizmos[MAN_AXIS_LAST]; } GizmoGroup; @@ -1269,103 +1275,31 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh); } -void drawDial3d(const TransInfo *t) +static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region, + float axis[3], + float center_global[3], + float mval_init[2], + float r_mat_basis[4][4]) { - if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) { - if (t->options & CTX_PAINT_CURVE) { - /* Matrices are in the screen space. Not supported. */ - return; - } - - wmGizmo *gz = wm_gizmomap_modal_get(t->region->gizmo_map); - if (gz == NULL) { - /* We only draw Dial3d if the operator has been called by a gizmo. */ - return; - } - - float mat_basis[4][4]; - float mat_final[4][4]; - float color[4]; - float increment = 0.0f; - float line_with = GIZMO_AXIS_LINE_WIDTH + 1.0f; - float scale = UI_DPI_FAC * U.gizmo_size; - - int axis_idx; - - const TransCon *tc = &(t->con); - if (tc->mode & CON_APPLY) { - if (tc->mode & CON_AXIS0) { - axis_idx = MAN_AXIS_ROT_X; - negate_v3_v3(mat_basis[2], t->spacemtx[0]); - } - else if (tc->mode & CON_AXIS1) { - axis_idx = MAN_AXIS_ROT_Y; - negate_v3_v3(mat_basis[2], t->spacemtx[1]); - } - else { - BLI_assert((tc->mode & CON_AXIS2) != 0); - axis_idx = MAN_AXIS_ROT_Z; - negate_v3_v3(mat_basis[2], t->spacemtx[2]); - } - } - else { - axis_idx = MAN_AXIS_ROT_C; - copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]); - scale *= 1.2f; - line_with -= 1.0f; - } - - copy_v3_v3(mat_basis[3], t->center_global); - mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]); - - if (ED_view3d_win_to_3d_on_plane( - t->region, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) { - sub_v3_v3(mat_basis[1], mat_basis[3]); - normalize_v3(mat_basis[1]); - cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]); - } - else { - /* The plane and the mouse direction are parallel. - * Calculate a matrix orthogonal to the axis. */ - ortho_basis_v3v3_v3(mat_basis[0], mat_basis[1], mat_basis[2]); - } - - mat_basis[0][3] = 0.0f; - mat_basis[1][3] = 0.0f; - mat_basis[2][3] = 0.0f; - mat_basis[3][3] = 1.0f; - - copy_m4_m4(mat_final, mat_basis); - scale *= ED_view3d_pixel_size_no_ui_scale(t->region->regiondata, mat_final[3]); - mul_mat3_m4_fl(mat_final, scale); + copy_v3_v3(r_mat_basis[2], axis); + copy_v3_v3(r_mat_basis[3], center_global); + r_mat_basis[2][3] = -dot_v3v3(axis, center_global); - if (activeSnap(t) && (!transformModeUseSnap(t) || - (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { - increment = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0]; - } - - BLI_assert(axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END); - gizmo_get_axis_color(axis_idx, NULL, color, color); - - GPU_depth_test(GPU_DEPTH_NONE); - GPU_blend(GPU_BLEND_ALPHA); - GPU_line_smooth(true); - - ED_gizmotypes_dial_3d_draw_util(mat_basis, - mat_final, - line_with, - color, - false, - &(struct Dial3dParams){ - .draw_options = ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE, - .angle_delta = t->values_final[0], - .angle_increment = increment, - }); - - GPU_line_smooth(false); - GPU_depth_test(GPU_DEPTH_LESS_EQUAL); - GPU_blend(GPU_BLEND_NONE); + if (ED_view3d_win_to_3d_on_plane(region, axis, mval_init, false, r_mat_basis[1])) { + sub_v3_v3(r_mat_basis[1], center_global); + normalize_v3(r_mat_basis[1]); + cross_v3_v3v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]); + } + else { + /* The plane and the mouse direction are parallel. + * Calculate a matrix orthogonal to the axis. */ + ortho_basis_v3v3_v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]); } + + r_mat_basis[0][3] = 0.0f; + r_mat_basis[1][3] = 0.0f; + r_mat_basis[2][3] = 0.0f; + r_mat_basis[3][3] = 1.0f; } /** \} */ @@ -1374,6 +1308,23 @@ void drawDial3d(const TransInfo *t) /** \name Transform Gizmo * \{ */ +/** Scale of the two-axis planes. */ +#define MAN_AXIS_SCALE_PLANE_SCALE 0.07f +/** Offset of the two-axis planes, depends on the gizmos scale. Define to avoid repeating. */ +#define MAN_AXIS_SCALE_PLANE_OFFSET 7.0f + +static void rotation_get_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value) +{ + const GizmoGroup *ggd = (const GizmoGroup *)gz_prop->custom_func.user_data; + *(float *)value = ggd->rotation; +} + +static void rotation_set_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value) +{ + GizmoGroup *ggd = (GizmoGroup *)gz_prop->custom_func.user_data; + ggd->rotation = *(const float *)value; +} + static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup) { GizmoGroup *ggd; @@ -1384,6 +1335,9 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup) const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); const wmGizmoType *gzt_prim = WM_gizmotype_find("GIZMO_GT_primitive_3d", true); + wmGizmoPropertyFnParams params = { + .value_get_fn = rotation_get_fn, .value_set_fn = rotation_set_fn, .user_data = ggd}; + #define GIZMO_NEW_ARROW(v, draw_style) \ { \ ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); \ @@ -1394,6 +1348,7 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup) { \ ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); \ RNA_enum_set(ggd->gizmos[v]->ptr, "draw_options", draw_options); \ + WM_gizmo_target_property_def_func(ggd->gizmos[v], "offset", ¶ms); \ } \ ((void)0) #define GIZMO_NEW_PRIM(v, draw_style) \ @@ -1461,18 +1416,104 @@ static int gizmo_modal(bContext *C, ARegion *region = CTX_wm_region(C); RegionView3D *rv3d = region->regiondata; - struct TransformBounds tbounds; - - if (ED_transform_calc_gizmo_stats(C, - &(struct TransformCalcParams){ - .use_only_center = true, - }, - &tbounds)) { - gizmo_prepare_mat(C, rv3d, &tbounds); - WM_gizmo_set_matrix_location(widget, rv3d->twmat[3]); + wmGizmoGroup *gzgroup = widget->parent_gzgroup; + + /* Recalculating the orientation has two problems. + * - The matrix calculated based on the transformed selection may not match the matrix + * that was set when transform started. + * - Inspecting the selection for every update is expensive (for *every* redraw). + * + * Instead, use #transform_apply_matrix to transform `rv3d->twmat` or the final scale value + * when scaling. + */ + if (false) { + struct TransformBounds tbounds; + + if (ED_transform_calc_gizmo_stats(C, + &(struct TransformCalcParams){ + .use_only_center = true, + }, + &tbounds)) { + gizmo_prepare_mat(C, rv3d, &tbounds); + for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]); + } + } } + else { + GizmoGroup *ggd = gzgroup->customdata; + + short axis_type = 0; + MAN_ITER_AXES_BEGIN (axis, axis_idx) { + if (axis == widget) { + axis_type = gizmo_get_axis_type(axis_idx); + break; + } + } + MAN_ITER_AXES_END; + + /* Showing axes which aren't being manipulated doesn't always work so well. + * + * For rotate: global axis will reset after finish. + * Also, gimbal axis isn't properly recalculated while transforming. + */ + if (axis_type == MAN_AXES_ROTATE) { + MAN_ITER_AXES_BEGIN (axis, axis_idx) { + if (axis == widget) { + continue; + } + + bool is_plane_dummy; + const uint aidx_norm = gizmo_orientation_axis(axis_idx, &is_plane_dummy); + /* Always show the axis-aligned handle as it's distracting when it's disabled. */ + if (aidx_norm == 3) { + continue; + } + WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true); + } + MAN_ITER_AXES_END; + } - ED_region_tag_redraw_editor_overlays(region); + wmWindow *win = CTX_wm_window(C); + wmOperator *op = NULL; + for (int i = 0; i < widget->op_data_len; i++) { + wmGizmoOpElem *gzop = WM_gizmo_operator_get(widget, i); + op = WM_operator_find_modal_by_type(win, gzop->type); + if (op != NULL) { + break; + } + } + + if (op != NULL) { + float twmat[4][4]; + float scale_buf[3]; + float *scale = NULL; + bool update = false; + copy_m4_m4(twmat, rv3d->twmat); + + if (axis_type == MAN_AXES_SCALE) { + scale = scale_buf; + transform_final_value_get(op->customdata, scale, 3); + update = true; + } + else if (axis_type == MAN_AXES_ROTATE) { + transform_final_value_get(op->customdata, &ggd->rotation, 1); + if (widget != ggd->gizmos[MAN_AXIS_ROT_C]) { + ggd->rotation *= -1; + } + RNA_float_set( + widget->ptr, "incremental_angle", transform_snap_increment_get(op->customdata)); + } + else if (transform_apply_matrix(op->customdata, twmat)) { + update = true; + } + + if (update) { + gizmo_refresh_from_matrix(gzgroup, twmat, scale); + ED_region_tag_redraw_editor_overlays(region); + } + } + } return OPERATOR_RUNNING_MODAL; } @@ -1524,9 +1565,8 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup) case MAN_AXIS_SCALE_XY: case MAN_AXIS_SCALE_YZ: case MAN_AXIS_SCALE_ZX: { - const float ofs_ax = 7.0f; - const float ofs[3] = {ofs_ax, ofs_ax, 0.0f}; - WM_gizmo_set_scale(axis, 0.07f); + const float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f}; + WM_gizmo_set_scale(axis, MAN_AXIS_SCALE_PLANE_SCALE); WM_gizmo_set_matrix_offset_location(axis, ofs); WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true); break; @@ -1638,46 +1678,23 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup) gizmogroup_init_properties_from_twtype(gzgroup); } -static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) +/** + * Set properties for axes. + * + * \param twmat: The transform matrix (typically #RegionView3D.twmat). + * \param scale: Optional scale, to show scale while modally dragging the scale handles. + */ +static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup, + const float twmat[4][4], + const float scale[3]) { GizmoGroup *ggd = gzgroup->customdata; - Scene *scene = CTX_data_scene(C); - ScrArea *area = CTX_wm_area(C); - View3D *v3d = area->spacedata.first; - ARegion *region = CTX_wm_region(C); - RegionView3D *rv3d = region->regiondata; - struct TransformBounds tbounds; - - if (ggd->use_twtype_refresh) { - ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init; - if (ggd->twtype != ggd->twtype_prev) { - ggd->twtype_prev = ggd->twtype; - gizmogroup_init_properties_from_twtype(gzgroup); - } - } - - const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init); - - /* skip, we don't draw anything anyway */ - if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C, - &(struct TransformCalcParams){ - .use_only_center = true, - .orientation_index = orient_index + 1, - }, - &tbounds) == 0))) { - return; - } - - gizmo_prepare_mat(C, rv3d, &tbounds); - - /* *** set properties for axes *** */ MAN_ITER_AXES_BEGIN (axis, axis_idx) { const short axis_type = gizmo_get_axis_type(axis_idx); const int aidx_norm = gizmo_orientation_axis(axis_idx, NULL); - WM_gizmo_set_matrix_location(axis, rv3d->twmat[3]); - + WM_gizmo_set_matrix_location(axis, twmat[3]); switch (axis_idx) { case MAN_AXIS_TRANS_X: case MAN_AXIS_TRANS_Y: @@ -1690,8 +1707,17 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) gizmo_line_range(ggd->twtype, axis_type, &start_co[2], &len); - WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); - RNA_float_set(axis->ptr, "length", len); + const float *z_axis = twmat[aidx_norm]; + if (axis_type == MAN_AXES_SCALE) { + /* Scale handles are cubes that don't look right when not aligned with other axes. + * This is noticeable when the axis is rotated to something besides the global-axis. */ + const int aidx_norm_y = (aidx_norm + 2) % 3; + const float *y_axis = twmat[aidx_norm_y]; + WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis); + } + else { + WM_gizmo_set_matrix_rotation_from_z_axis(axis, z_axis); + } if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { if (ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) { @@ -1699,24 +1725,56 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) start_co[2] += 0.215f; } } + + if (scale) { + if (axis_type == MAN_AXES_SCALE) { + len = ((start_co[2] + len) * scale[aidx_norm]) - start_co[2]; + } + } + + RNA_float_set(axis->ptr, "length", len); + WM_gizmo_set_matrix_offset_location(axis, start_co); + WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true); + break; } case MAN_AXIS_ROT_X: case MAN_AXIS_ROT_Y: case MAN_AXIS_ROT_Z: - WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); - break; + case MAN_AXIS_ROT_C: { + if (axis_idx != MAN_AXIS_ROT_C) { + WM_gizmo_set_matrix_rotation_from_z_axis(axis, twmat[aidx_norm]); + } + + /* Remove #ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE. It is used only for modal drawing. */ + PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options"); + RNA_property_enum_set(axis->ptr, + prop, + RNA_property_enum_get(axis->ptr, prop) & + ~ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE); + } break; case MAN_AXIS_TRANS_XY: case MAN_AXIS_TRANS_YZ: case MAN_AXIS_TRANS_ZX: case MAN_AXIS_SCALE_XY: case MAN_AXIS_SCALE_YZ: case MAN_AXIS_SCALE_ZX: { - const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]; - const float *z_axis = rv3d->twmat[aidx_norm]; + const int aidx_norm_x = (aidx_norm + 1) % 3; + const int aidx_norm_y = (aidx_norm + 2) % 3; + const float *y_axis = twmat[aidx_norm_y]; + const float *z_axis = twmat[aidx_norm]; WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis); + + if (axis_type == MAN_AXES_SCALE) { + float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f}; + if (scale) { + ofs[0] *= scale[aidx_norm_x]; + ofs[1] *= scale[aidx_norm_y]; + } + WM_gizmo_set_matrix_offset_location(axis, ofs); + } break; } } @@ -1733,6 +1791,49 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) } } +static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + ARegion *region = CTX_wm_region(C); + + { + wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map); + if (gz && gz->parent_gzgroup == gzgroup) { + return; + } + } + + GizmoGroup *ggd = gzgroup->customdata; + Scene *scene = CTX_data_scene(C); + ScrArea *area = CTX_wm_area(C); + View3D *v3d = area->spacedata.first; + RegionView3D *rv3d = region->regiondata; + struct TransformBounds tbounds; + + if (ggd->use_twtype_refresh) { + ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init; + if (ggd->twtype != ggd->twtype_prev) { + ggd->twtype_prev = ggd->twtype; + gizmogroup_init_properties_from_twtype(gzgroup); + } + } + + const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init); + + /* skip, we don't draw anything anyway */ + if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C, + &(struct TransformCalcParams){ + .use_only_center = true, + .orientation_index = orient_index + 1, + }, + &tbounds) == 0))) { + return; + } + + gizmo_prepare_mat(C, rv3d, &tbounds); + + gizmo_refresh_from_matrix(gzgroup, rv3d->twmat, NULL); +} + static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus) @@ -1756,11 +1857,22 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr copy_m3_m4(viewinv_m3, rv3d->viewinv); float idot[3]; + /* Re-calculate hidden unless modal. */ + bool is_modal = false; + { + wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map); + if (gz && gz->parent_gzgroup == gzgroup) { + is_modal = true; + } + } + /* when looking through a selected camera, the gizmo can be at the * exact same position as the view, skip so we don't break selection */ if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) { MAN_ITER_AXES_BEGIN (axis, axis_idx) { - WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true); + if (!is_modal) { + WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true); + } } MAN_ITER_AXES_END; return; @@ -1771,12 +1883,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr MAN_ITER_AXES_BEGIN (axis, axis_idx) { const short axis_type = gizmo_get_axis_type(axis_idx); /* XXX maybe unset _HIDDEN flag on redraw? */ - if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) { - WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false); + if (!is_modal) { + WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false); + } } else { - WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true); + if (!is_modal) { + WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true); + } continue; } @@ -1785,13 +1900,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr WM_gizmo_set_color(axis, color); WM_gizmo_set_color_highlight(axis, color_hi); - switch (axis_idx) { - case MAN_AXIS_TRANS_C: - case MAN_AXIS_ROT_C: - case MAN_AXIS_SCALE_C: - case MAN_AXIS_ROT_T: - WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]); - break; + if (!is_modal) { + switch (axis_idx) { + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]); + break; + } } } MAN_ITER_AXES_END; @@ -1879,6 +1996,17 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C, } } } + else if (ELEM(axis_idx, MAN_AXIS_ROT_X, MAN_AXIS_ROT_Y, MAN_AXIS_ROT_Z, MAN_AXIS_ROT_C)) { + gizmo_3d_dial_matrixbasis_calc(CTX_wm_region(C), + gz->matrix_basis[2], + gz->matrix_basis[3], + (float[2]){UNPACK2(event->mval)}, + gz->matrix_basis); + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "draw_options"); + RNA_property_enum_set( + gz->ptr, prop, RNA_property_enum_get(gz->ptr, prop) | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE); + RNA_float_set(gz->ptr, "incremental_angle", 0.0f); + } } static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d) @@ -1944,8 +2072,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt) gzgt->name = "3D View: Transform Gizmo"; gzgt->idname = "VIEW3D_GGT_xform_gizmo"; - gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | - WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK; + gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | + WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK; gzgt->gzmap_params.spaceid = SPACE_VIEW3D; gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 2fd81486bb6..83f1bd35f81 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -35,7 +35,7 @@ /* Own include. */ #include "transform_mode.h" -int transform_mode_really_used(bContext *C, int mode) +eTfmMode transform_mode_really_used(bContext *C, eTfmMode mode) { if (mode == TFM_BONESIZE) { Object *ob = CTX_data_active_object(C); diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 6930b87090c..eac6734ed88 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -25,7 +25,7 @@ typedef struct TransDataGenericSlideVert { /* transform_mode.c */ -int transform_mode_really_used(struct bContext *C, int mode); +eTfmMode transform_mode_really_used(struct bContext *C, eTfmMode mode); bool transdata_check_local_center(const TransInfo *t, short around); /** * Informs if the mode can be switched during modal. diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 4b86adc4f46..94caaa288e5 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -322,10 +322,30 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } +static void applyRotationMatrix(TransInfo *t, float mat_xform[4][4]) +{ + float axis_final[3]; + const float angle_final = t->values_final[0]; + if ((t->con.mode & CON_APPLY) && t->con.applyRot) { + t->con.applyRot(t, NULL, NULL, axis_final, NULL); + } + else { + negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]); + } + + float mat3[3][3]; + float mat4[4][4]; + axis_angle_normalized_to_mat3(mat3, axis_final, angle_final); + copy_m4_m3(mat4, mat3); + transform_pivot_set_m4(mat4, t->center_global); + mul_m4_m4m4(mat_xform, mat4, mat_xform); +} + void initRotation(TransInfo *t) { t->mode = TFM_ROTATION; t->transform = applyRotation; + t->transform_matrix = applyRotationMatrix; t->tsnap.applySnap = ApplySnapRotation; t->tsnap.distance = RotationBetween; diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c index 2e405449bc3..3716826800b 100644 --- a/source/blender/editors/transform/transform_mode_trackball.c +++ b/source/blender/editors/transform/transform_mode_trackball.c @@ -75,19 +75,25 @@ static void transdata_elem_trackball_fn(void *__restrict iter_data_v, /** \name Transform (Rotation - Trackball) * \{ */ -static void applyTrackballValue(TransInfo *t, - const float axis1[3], - const float axis2[3], - const float angles[2]) +static void applyTrackballValue_calc_axis_angle(const TransInfo *t, + const float phi[2], + float r_axis[3], + float *r_angle) +{ + float axis1[3], axis2[3]; + normalize_v3_v3(axis1, t->persinv[0]); + normalize_v3_v3(axis2, t->persinv[1]); + + mul_v3_v3fl(r_axis, axis1, phi[0]); + madd_v3_v3fl(r_axis, axis2, phi[1]); + *r_angle = normalize_v3(r_axis); +} + +static void applyTrackballValue(TransInfo *t, const float axis[3], const float angle) { float mat_final[3][3]; - float axis[3]; - float angle; int i; - mul_v3_v3fl(axis, axis1, angles[0]); - madd_v3_v3fl(axis, axis2, angles[1]); - angle = normalize_v3(axis); axis_angle_normalized_to_mat3(mat_final, axis, angle); FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -120,17 +126,8 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; size_t ofs = 0; - float axis1[3], axis2[3]; -#if 0 /* UNUSED */ - float mat[3][3], totmat[3][3], smat[3][3]; -#endif float phi[2]; - copy_v3_v3(axis1, t->persinv[0]); - copy_v3_v3(axis2, t->persinv[1]); - normalize_v3(axis1); - normalize_v3(axis2); - copy_v2_v2(phi, t->values); transform_snap_increment(t, phi); @@ -165,27 +162,35 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); } -#if 0 /* UNUSED */ - axis_angle_normalized_to_mat3(smat, axis1, phi[0]); - axis_angle_normalized_to_mat3(totmat, axis2, phi[1]); + float axis_final[3], angle_final; + applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final); + applyTrackballValue(t, axis_final, angle_final); - mul_m3_m3m3(mat, smat, totmat); + recalcData(t); - /* TRANSFORM_FIX_ME */ - // copy_m3_m3(t->mat, mat); /* used in gizmo. */ -#endif + ED_area_status_text(t->area, str); +} - applyTrackballValue(t, axis1, axis2, phi); +static void applyTrackballMatrix(TransInfo *t, float mat_xform[4][4]) +{ + const float phi[2] = {UNPACK2(t->values_final)}; - recalcData(t); + float axis_final[3], angle_final; + applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final); - ED_area_status_text(t->area, str); + float mat3[3][3], mat4[4][4]; + axis_angle_normalized_to_mat3(mat3, axis_final, angle_final); + + copy_m4_m3(mat4, mat3); + transform_pivot_set_m4(mat4, t->center_global); + mul_m4_m4m4(mat_xform, mat4, mat_xform); } void initTrackball(TransInfo *t) { t->mode = TFM_TRACKBALL; t->transform = applyTrackball; + t->transform_matrix = applyTrackballMatrix; initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL); diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index c881cde351e..3c6b6ea4117 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -469,7 +469,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) add_v3_v3(global_dir, values_ofs); } - t->tsnap.snapElem = 0; + t->tsnap.snapElem = SCE_SNAP_MODE_NONE; applySnapping(t, global_dir); transform_snap_grid(t, global_dir); @@ -486,7 +486,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) /* Test for mixed snap with grid. */ float snap_dist_sq = FLT_MAX; - if (t->tsnap.snapElem != 0) { + if (t->tsnap.snapElem != SCE_SNAP_MODE_NONE) { snap_dist_sq = len_squared_v3v3(t->values, global_dir); } if ((snap_dist_sq == FLT_MAX) || (len_squared_v3v3(global_dir, incr_dir) < snap_dist_sq)) { @@ -518,6 +518,13 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } +static void applyTranslationMatrix(TransInfo *t, float mat_xform[4][4]) +{ + float delta[3]; + mul_v3_m3v3(delta, t->spacemtx, t->values_final); + add_v3_v3(mat_xform[3], delta); +} + void initTranslation(TransInfo *t) { if (t->spacetype == SPACE_ACTION) { @@ -530,6 +537,7 @@ void initTranslation(TransInfo *t) } t->transform = applyTranslation; + t->transform_matrix = applyTranslationMatrix; t->tsnap.applySnap = ApplySnapTranslation; t->tsnap.distance = transform_snap_distance_len_squared_fn; diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 600f525b428..cd8a2f17554 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -419,7 +419,7 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event) /* XXX, workaround: active needs to be calculated before transforming, * since we're not reading from 'td->center' in this case. see: T40241 */ - if (t->tsnap.target == SCE_SNAP_TARGET_ACTIVE) { + if (t->tsnap.source_select == SCE_SNAP_SOURCE_ACTIVE) { /* In camera view, tsnap callback is not set * (see #initSnappingMode() in transform_snap.c, and T40348). */ if (t->tsnap.targetSnap && ((t->tsnap.status & TARGET_INIT) == 0)) { @@ -648,7 +648,11 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) RNA_def_property_flag(prop, PROP_HIDDEN); if (flags & P_GEO_SNAP) { - prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_target_items, 0, "Target", ""); + /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid + * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is + * geometry to which moved geometry is snapped). Use "Source snap point" and "Point on + * source that will snap to target" for name and description, respectively. */ + prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Target", ""); RNA_def_property_flag(prop, PROP_HIDDEN); prop = RNA_def_float_vector( ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 769fd28c57b..649217092aa 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -79,8 +79,8 @@ static void TargetSnapActive(TransInfo *t); /** \name Implementations * \{ */ -static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select); -static NodeBorder snapNodeBorder(int snap_node_mode); +static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select); +static NodeBorder snapNodeBorder(eSnapMode snap_node_mode); #if 0 int BIF_snappingSupported(Object *obedit) @@ -377,56 +377,59 @@ void applyProject(TransInfo *t) if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - if (ED_transform_snap_object_project_view3d( - t->tsnap.object_context, - t->depsgraph, - t->region, - t->view, - SCE_SNAP_MODE_FACE, - &(const struct SnapObjectParams){ - .snap_select = t->tsnap.modeSelect, - .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, - .use_occlusion_test = false, - .use_backface_culling = t->tsnap.use_backface_culling, - }, - mval_fl, - NULL, - 0, - loc, - no)) { + eSnapMode hit = ED_transform_snap_object_project_view3d( + t->tsnap.object_context, + t->depsgraph, + t->region, + t->view, + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_target_select = t->tsnap.target_select, + .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, + .use_occlusion_test = false, + .use_backface_culling = t->tsnap.use_backface_culling, + }, + mval_fl, + NULL, + 0, + loc, + no); + if (hit != SCE_SNAP_MODE_FACE) { + return; + } + #if 0 - if (tc->use_local_mat) { - mul_m4_v3(tc->imat, loc); - } + if (tc->use_local_mat) { + mul_m4_v3(tc->imat, loc); + } #endif - sub_v3_v3v3(tvec, loc, iloc); + sub_v3_v3v3(tvec, loc, iloc); - mul_m3_v3(td->smtx, tvec); + mul_m3_v3(td->smtx, tvec); - add_v3_v3(td->loc, tvec); + add_v3_v3(td->loc, tvec); - if (t->tsnap.align && (t->options & CTX_OBJECT)) { - /* handle alignment as well */ - const float *original_normal; - float mat[3][3]; + if (t->tsnap.align && (t->options & CTX_OBJECT)) { + /* handle alignment as well */ + const float *original_normal; + float mat[3][3]; - /* In pose mode, we want to align normals with Y axis of bones... */ - original_normal = td->axismtx[2]; + /* In pose mode, we want to align normals with Y axis of bones... */ + original_normal = td->axismtx[2]; - rotation_between_vecs_to_mat3(mat, original_normal, no); + rotation_between_vecs_to_mat3(mat, original_normal, no); - transform_data_ext_rotate(td, mat, true); + transform_data_ext_rotate(td, mat, true); - /* TODO: support constraints for rotation too? see #ElementRotation. */ - } + /* TODO: support constraints for rotation too? see #ElementRotation. */ } } + } #if 0 /* TODO: support this? */ - constraintTransLim(t, td); + constraintTransLim(t, td); #endif - } } } @@ -522,13 +525,13 @@ void applySnapping(TransInfo *t, float *vec) void resetSnapping(TransInfo *t) { - t->tsnap.status = 0; - t->tsnap.snapElem = 0; + t->tsnap.status = SNAP_RESETTED; + t->tsnap.snapElem = SCE_SNAP_MODE_NONE; t->tsnap.align = false; - t->tsnap.project = 0; - t->tsnap.mode = 0; - t->tsnap.modeSelect = 0; - t->tsnap.target = 0; + t->tsnap.project = false; + t->tsnap.mode = SCE_SNAP_MODE_NONE; + t->tsnap.target_select = SCE_SNAP_TARGET_ALL; + t->tsnap.source_select = SCE_SNAP_SOURCE_CLOSEST; t->tsnap.last = 0; t->tsnap.snapNormal[0] = 0; @@ -581,7 +584,7 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) return true; } -static char snap_flag_from_spacetype(TransInfo *t) +static eSnapFlag snap_flag_from_spacetype(TransInfo *t) { ToolSettings *ts = t->settings; if (t->spacetype == SPACE_NODE) { @@ -596,7 +599,7 @@ static char snap_flag_from_spacetype(TransInfo *t) return ts->snap_flag; } -static short snap_mode_from_spacetype(TransInfo *t) +static eSnapMode snap_mode_from_spacetype(TransInfo *t) { ToolSettings *ts = t->settings; @@ -605,7 +608,7 @@ static short snap_mode_from_spacetype(TransInfo *t) } if (t->spacetype == SPACE_IMAGE) { - short snap_mode = ts->snap_uv_mode; + eSnapMode snap_mode = ts->snap_uv_mode; if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && (t->mode == TFM_TRANSLATION)) { snap_mode &= ~SCE_SNAP_MODE_INCREMENT; @@ -623,7 +626,7 @@ static short snap_mode_from_spacetype(TransInfo *t) return SCE_SNAP_MODE_INCREMENT; } - short snap_mode = ts->snap_mode; + eSnapMode snap_mode = ts->snap_mode; if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && (t->mode == TFM_TRANSLATION)) { /* Special case in which snap to increments is transformed to snap to grid. */ @@ -641,7 +644,7 @@ static short snap_mode_from_spacetype(TransInfo *t) return SCE_SNAP_MODE_INCREMENT; } -static short snap_select_type_get(TransInfo *t) +static eSnapTargetSelect snap_select_type_get(TransInfo *t) { ViewLayer *view_layer = t->view_layer; Base *base_act = view_layer->basact; @@ -652,7 +655,7 @@ static short snap_select_type_get(TransInfo *t) * TODO: perform self snap in gpencil_strokes. * * When we're moving the origins, allow snapping onto our own geometry (see T69132). */ - return SNAP_ALL; + return SCE_SNAP_TARGET_ALL; } const int obedit_type = t->obedit_type; @@ -669,44 +672,44 @@ static short snap_select_type_get(TransInfo *t) if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { /* Exclude editmesh if using proportional edit */ - return SNAP_NOT_EDITED; + return SCE_SNAP_TARGET_NOT_EDITED; } if (!t->tsnap.snap_self) { - return SNAP_NOT_ACTIVE; + return SCE_SNAP_TARGET_NOT_ACTIVE; } - return SNAP_NOT_SELECTED; + return SCE_SNAP_TARGET_NOT_SELECTED; } - return SNAP_ALL; + return SCE_SNAP_TARGET_ALL; } if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { /* Particles edit mode. */ - return SNAP_ALL; + return SCE_SNAP_TARGET_ALL; } /* Object or pose mode. */ - return SNAP_NOT_SELECTED; + return SCE_SNAP_TARGET_NOT_SELECTED; } if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { - return SNAP_NOT_SELECTED; + return SCE_SNAP_TARGET_NOT_SELECTED; } - return SNAP_ALL; + return SCE_SNAP_TARGET_ALL; } static void initSnappingMode(TransInfo *t) { ToolSettings *ts = t->settings; t->tsnap.mode = snap_mode_from_spacetype(t); - t->tsnap.modeSelect = snap_select_type_get(t); + t->tsnap.target_select = snap_select_type_get(t); if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) { /* Force project off when not supported. */ - t->tsnap.project = 0; + t->tsnap.project = false; } if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) { @@ -752,7 +755,7 @@ void initSnapping(TransInfo *t, wmOperator *op) { resetSnapping(t); t->tsnap.flag = snap_flag_from_spacetype(t); - short snap_target = t->settings->snap_target; + eSnapSourceSelect snap_source = t->settings->snap_target; /* if snap property exists */ PropertyRNA *prop; @@ -763,7 +766,10 @@ void initSnapping(TransInfo *t, wmOperator *op) if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) && RNA_property_is_set(op->ptr, prop)) { - snap_target = RNA_property_enum_get(op->ptr, prop); + /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid + * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is + * geometry to which moved geometry is snapped). */ + snap_source = RNA_property_enum_get(op->ptr, prop); } if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) && @@ -803,7 +809,7 @@ void initSnapping(TransInfo *t, wmOperator *op) t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0); } - t->tsnap.target = snap_target; + t->tsnap.source_select = snap_source; initSnappingMode(t); } @@ -844,11 +850,11 @@ static void setSnappingCallback(TransInfo *t) return; } - switch (t->tsnap.target) { - case SCE_SNAP_TARGET_CLOSEST: + switch (t->tsnap.source_select) { + case SCE_SNAP_SOURCE_CLOSEST: t->tsnap.targetSnap = TargetSnapClosest; break; - case SCE_SNAP_TARGET_CENTER: + case SCE_SNAP_SOURCE_CENTER: if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) { t->tsnap.targetSnap = TargetSnapCenter; break; @@ -856,10 +862,10 @@ static void setSnappingCallback(TransInfo *t) /* Can't do TARGET_CENTER with these modes, * use TARGET_MEDIAN instead. */ ATTR_FALLTHROUGH; - case SCE_SNAP_TARGET_MEDIAN: + case SCE_SNAP_SOURCE_MEDIAN: t->tsnap.targetSnap = TargetSnapMedian; break; - case SCE_SNAP_TARGET_ACTIVE: + case SCE_SNAP_SOURCE_ACTIVE: t->tsnap.targetSnap = TargetSnapActive; break; } @@ -973,7 +979,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) float no[3]; float mval[2]; bool found = false; - short snap_elem = 0; + eSnapMode snap_elem = SCE_SNAP_MODE_NONE; float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */ mval[0] = t->mval[0]; @@ -982,7 +988,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) { zero_v3(no); /* objects won't set this */ snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no); - found = snap_elem != 0; + found = (snap_elem != SCE_SNAP_MODE_NONE); } if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) { found = peelObjectsTransform( @@ -1003,7 +1009,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) t->tsnap.status &= ~POINT_INIT; } - t->tsnap.snapElem = (char)snap_elem; + t->tsnap.snapElem = snap_elem; } static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec)) @@ -1020,7 +1026,7 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec)) objects, objects_len, t->mval, - t->tsnap.modeSelect == SNAP_NOT_SELECTED, + t->tsnap.target_select == SCE_SNAP_TARGET_NOT_SELECTED, &dist_sq, t->tsnap.snapPoint)) { t->tsnap.snapPoint[0] *= t->aspect[0]; @@ -1190,7 +1196,7 @@ static void TargetSnapActive(TransInfo *t) } /* No active, default to median */ else { - t->tsnap.target = SCE_SNAP_TARGET_MEDIAN; + t->tsnap.source_select = SCE_SNAP_SOURCE_MEDIAN; t->tsnap.targetSnap = TargetSnapMedian; TargetSnapMedian(t); } @@ -1302,7 +1308,7 @@ static void TargetSnapClosest(TransInfo *t) /** \name Snap Objects * \{ */ -short snapObjectsTransform( +eSnapMode snapObjectsTransform( TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3]) { float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global; @@ -1313,7 +1319,7 @@ short snapObjectsTransform( t->view, t->tsnap.mode, &(const struct SnapObjectParams){ - .snap_select = t->tsnap.modeSelect, + .snap_target_select = t->tsnap.target_select, .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE, .use_backface_culling = t->tsnap.use_backface_culling, @@ -1346,7 +1352,7 @@ bool peelObjectsTransform(TransInfo *t, t->region, t->view, &(const struct SnapObjectParams){ - .snap_select = t->tsnap.modeSelect, + .snap_target_select = t->tsnap.target_select, .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, }, mval, @@ -1414,16 +1420,16 @@ bool peelObjectsTransform(TransInfo *t, /** \name snap Nodes * \{ */ -static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select) +static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select) { /* node is use for snapping only if a) snap mode matches and b) node is inside the view */ - return ((snap_select == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) || - (snap_select == SNAP_ALL && !(node->flag & NODE_ACTIVE))) && + return ((snap_target_select == SCE_SNAP_TARGET_NOT_SELECTED && !(node->flag & NODE_SELECT)) || + (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) && (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin && node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin); } -static NodeBorder snapNodeBorder(int snap_node_mode) +static NodeBorder snapNodeBorder(eSnapMode snap_node_mode) { NodeBorder flag = 0; if (snap_node_mode & SCE_SNAP_MODE_NODE_X) { @@ -1499,7 +1505,7 @@ static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *region, const int mval[2], - eSnapSelect snap_select, + eSnapTargetSelect snap_target_select, float r_loc[2], float *r_dist_px, char *r_node_border) @@ -1511,7 +1517,7 @@ static bool snapNodes(ToolSettings *ts, *r_node_border = 0; for (node = ntree->nodes.first; node; node = node->next) { - if (snapNodeTest(®ion->v2d, node, snap_select)) { + if (snapNodeTest(®ion->v2d, node, snap_target_select)) { retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border); } } @@ -1526,7 +1532,7 @@ bool snapNodesTransform( t->area->spacedata.first, t->region, mval, - t->tsnap.modeSelect, + t->tsnap.target_select, r_loc, r_dist_px, r_node_border); @@ -1548,7 +1554,7 @@ static void snap_grid_apply( float in[3]; if (t->con.mode & CON_APPLY) { - BLI_assert(t->tsnap.snapElem == 0); + BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); t->con.applyVec(t, NULL, NULL, loc, in); } else { @@ -1676,6 +1682,16 @@ bool transform_snap_increment(const TransInfo *t, float *r_val) return transform_snap_increment_ex(t, false, r_val); } +float transform_snap_increment_get(const TransInfo *t) +{ + if (activeSnap(t) && (!transformModeUseSnap(t) || + (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { + return (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0]; + } + + return 0.0f; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index cde97d14be4..6db027df067 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -19,12 +19,12 @@ bool peelObjectsTransform(struct TransInfo *t, float r_no[3], float *r_thickness); -short snapObjectsTransform(struct TransInfo *t, - const float mval[2], - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3]); +eSnapMode snapObjectsTransform(struct TransInfo *t, + const float mval[2], + float *dist_px, + /* return args */ + float r_loc[3], + float r_no[3]); bool snapNodesTransform(struct TransInfo *t, const int mval[2], /* return args */ @@ -36,6 +36,7 @@ bool transformModeUseSnap(const TransInfo *t); bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val); bool transform_snap_increment(const TransInfo *t, float *val); +float transform_snap_increment_get(const TransInfo *t); bool transform_snap_grid(TransInfo *t, float *val); bool activeSnap(const TransInfo *t); diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 6beae690b12..cf99d4b2ef3 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -157,7 +157,7 @@ struct SnapObjectContext { enum eViewProj view_proj; float clip_plane[MAX_CLIPPLANE_LEN][4]; short clip_plane_len; - short snap_to_flag; + eSnapMode snap_to_flag; bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */ } runtime; }; @@ -283,8 +283,10 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, } } else { - /* Any existing #SnapData_EditMesh is now invalid. */ - sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval)); + if (ob_eval->type == OB_MESH) { + /* Any existing #SnapData_EditMesh is now invalid. */ + sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval)); + } std::unique_ptr<SnapData_Mesh> sod_ptr = std::make_unique<SnapData_Mesh>(); sod = sod_ptr.get(); @@ -417,7 +419,7 @@ using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx, void *data); static bool snap_object_is_snappable(const SnapObjectContext *sctx, - const eSnapSelect snap_select, + const eSnapTargetSelect snap_select, const Base *base_act, const Base *base, const bool is_in_object_mode) @@ -426,7 +428,7 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, return false; } - if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) { + if ((snap_select == SCE_SNAP_TARGET_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) { return true; } @@ -434,15 +436,15 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, return false; } - if (snap_select == SNAP_NOT_ACTIVE) { + if (snap_select == SCE_SNAP_TARGET_NOT_ACTIVE) { return base_act != base; } - if (snap_select == SNAP_NOT_EDITED) { + if (snap_select == SCE_SNAP_TARGET_NOT_EDITED) { return base->object->mode != OB_MODE_EDIT; } - if (snap_select == SNAP_NOT_SELECTED) { + if (snap_select == SCE_SNAP_TARGET_NOT_SELECTED) { if (is_in_object_mode) { return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)); } @@ -451,7 +453,7 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, return true; } - if (snap_select == SNAP_SELECTABLE) { + if (snap_select == SCE_SNAP_TARGET_ONLY_SELECTABLE) { return (base->flag & BASE_SELECTABLE) != 0; } @@ -467,12 +469,12 @@ static void iter_snap_objects(SnapObjectContext *sctx, void *data) { ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph); - const eSnapSelect snap_select = params->snap_select; + const eSnapTargetSelect snap_target_select = params->snap_target_select; Base *base_act = view_layer->basact; const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT; LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) { + if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base, is_in_object_mode)) { continue; } @@ -1533,18 +1535,18 @@ static void nearest2d_data_init_editmesh(SnapData_EditMesh *sod, /** \name Internal Object Snapping API * \{ */ -static short snap_mesh_polygon(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index) +static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + const float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float r_no[3], + int *r_index) { - short elem = 0; + eSnapMode elem = SCE_SNAP_MODE_NONE; float lpmat[4][4]; mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat); @@ -1663,23 +1665,23 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, return elem; } - return 0; + return SCE_SNAP_MODE_NONE; } -static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - float original_dist_px, - const float prev_co[3], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index) +static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + const float obmat[4][4], + float original_dist_px, + const float prev_co[3], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float r_no[3], + int *r_index) { - short elem = SCE_SNAP_MODE_EDGE; + eSnapMode elem = SCE_SNAP_MODE_EDGE; if (ob_eval->type != OB_MESH) { return elem; @@ -1826,19 +1828,19 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, return elem; } -static short snapArmature(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - bool is_object_active, - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float *UNUSED(r_no), - int *r_index) +static eSnapMode snapArmature(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + const float obmat[4][4], + bool is_object_active, + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float *UNUSED(r_no), + int *r_index) { - short retval = 0; + eSnapMode retval = SCE_SNAP_MODE_NONE; if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */ return retval; @@ -1875,7 +1877,7 @@ static short snapArmature(SnapObjectContext *sctx, const bool is_posemode = is_object_active && (ob_eval->mode & OB_MODE_POSE); const bool skip_selected = (is_editmode || is_posemode) && - (params->snap_select == SNAP_NOT_SELECTED); + (params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED); const bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP; if (arm->edbo) { @@ -1990,25 +1992,25 @@ static short snapArmature(SnapObjectContext *sctx, return retval; } - return 0; + return SCE_SNAP_MODE_NONE; } -static short snapCurve(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float *UNUSED(r_no), - int *r_index) +static eSnapMode snapCurve(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + const float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float *UNUSED(r_no), + int *r_index) { bool has_snap = false; /* only vertex snapping mode (eg control points and handles) supported for now) */ if ((sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) { - return 0; + return SCE_SNAP_MODE_NONE; } Curve *cu = static_cast<Curve *>(ob_eval->data); @@ -2032,7 +2034,7 @@ static short snapCurve(SnapObjectContext *sctx, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) { - return 0; + return SCE_SNAP_MODE_NONE; } } @@ -2054,7 +2056,7 @@ static short snapCurve(SnapObjectContext *sctx, } bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP; - bool skip_selected = params->snap_select == SNAP_NOT_SELECTED; + bool skip_selected = params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED; LISTBASE_FOREACH (Nurb *, nu, (use_obedit ? &cu->editnurb->nurbs : &cu->nurb)) { for (int u = 0; u < nu->pntsu; u++) { @@ -2160,21 +2162,21 @@ static short snapCurve(SnapObjectContext *sctx, return SCE_SNAP_MODE_VERTEX; } - return 0; + return SCE_SNAP_MODE_NONE; } /* may extend later (for now just snaps to empty center) */ -static short snap_object_center(const SnapObjectContext *sctx, - Object *ob_eval, - const float obmat[4][4], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float *UNUSED(r_no), - int *r_index) +static eSnapMode snap_object_center(const SnapObjectContext *sctx, + Object *ob_eval, + const float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float *UNUSED(r_no), + int *r_index) { - short retval = 0; + eSnapMode retval = SCE_SNAP_MODE_NONE; if (ob_eval->transflag & OB_DUPLI) { return retval; @@ -2216,20 +2218,20 @@ static short snap_object_center(const SnapObjectContext *sctx, return retval; } - return 0; + return SCE_SNAP_MODE_NONE; } -static short snapCamera(const SnapObjectContext *sctx, - Object *object, - const float obmat[4][4], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float *r_no, - int *r_index) +static eSnapMode snapCamera(const SnapObjectContext *sctx, + Object *object, + const float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float *r_no, + int *r_index) { - short retval = 0; + eSnapMode retval = SCE_SNAP_MODE_NONE; Scene *scene = sctx->scene; @@ -2310,28 +2312,28 @@ static short snapCamera(const SnapObjectContext *sctx, return retval; } - return 0; + return SCE_SNAP_MODE_NONE; } -static short snapMesh(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const Mesh *me_eval, - const float obmat[4][4], - bool use_hide, - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index) +static eSnapMode snapMesh(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + const Mesh *me_eval, + const float obmat[4][4], + bool use_hide, + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float r_no[3], + int *r_index) { BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE); if (me_eval->totvert == 0) { - return 0; + return SCE_SNAP_MODE_NONE; } if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) { - return 0; + return SCE_SNAP_MODE_NONE; } float lpmat[4][4]; @@ -2344,7 +2346,7 @@ static short snapMesh(SnapObjectContext *sctx, if (bb && !snap_bound_box_check_dist( bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) { - return 0; + return SCE_SNAP_MODE_NONE; } SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); @@ -2385,7 +2387,7 @@ static short snapMesh(SnapObjectContext *sctx, nearest.dist_sq = dist_px_sq; int last_index = nearest.index; - short elem = SCE_SNAP_MODE_VERTEX; + eSnapMode elem = SCE_SNAP_MODE_VERTEX; float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; transpose_m4_m4(tobmat, obmat); @@ -2489,31 +2491,31 @@ static short snapMesh(SnapObjectContext *sctx, return elem; } - return 0; + return SCE_SNAP_MODE_NONE; } -static short snapEditMesh(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - BMEditMesh *em, - const float obmat[4][4], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index) +static eSnapMode snapEditMesh(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + BMEditMesh *em, + const float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float r_no[3], + int *r_index) { BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE); if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) { if (em->bm->totvert == 0) { - return 0; + return SCE_SNAP_MODE_NONE; } } else { if (em->bm->totedge == 0) { - return 0; + return SCE_SNAP_MODE_NONE; } } @@ -2529,7 +2531,7 @@ static short snapEditMesh(SnapObjectContext *sctx, /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ if (!snap_bound_box_check_dist( sod->min, sod->max, lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) { - return 0; + return SCE_SNAP_MODE_NONE; } if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) { @@ -2604,7 +2606,7 @@ static short snapEditMesh(SnapObjectContext *sctx, nearest.index = -1; nearest.dist_sq = dist_px_sq; - short elem = SCE_SNAP_MODE_VERTEX; + eSnapMode elem = SCE_SNAP_MODE_VERTEX; float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; transpose_m4_m4(tobmat, obmat); @@ -2670,7 +2672,7 @@ static short snapEditMesh(SnapObjectContext *sctx, return elem; } - return 0; + return SCE_SNAP_MODE_NONE; } struct SnapObjUserData { @@ -2682,7 +2684,7 @@ struct SnapObjUserData { int *r_index; Object **r_ob; float (*r_obmat)[4]; - short ret; + eSnapMode ret; }; /** @@ -2696,7 +2698,7 @@ static void snap_obj_fn(SnapObjectContext *sctx, void *data) { SnapObjUserData *dt = static_cast<SnapObjUserData *>(data); - short retval = 0; + eSnapMode retval = SCE_SNAP_MODE_NONE; switch (ob_eval->type) { case OB_MESH: { @@ -2743,11 +2745,8 @@ static void snap_obj_fn(SnapObjectContext *sctx, dt->r_index); break; case OB_CURVES_LEGACY: - retval = snapCurve( - sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); - break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */ case OB_SURF: - if (BKE_object_is_in_editmode(ob_eval)) { + if (ob_eval->type == OB_CURVES_LEGACY || BKE_object_is_in_editmode(ob_eval)) { retval = snapCurve( sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); if (params->edit_mode_type != SNAP_GEOM_FINAL) { @@ -2816,18 +2815,18 @@ static void snap_obj_fn(SnapObjectContext *sctx, * \param r_ob: Hit object. * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). */ -static short snapObjectsRay(SnapObjectContext *sctx, - const SnapObjectParams *params, - /* read/write args */ - /* Parameters below cannot be const, because they are assigned to a - * non-const variable (readability-non-const-parameter). */ - float *dist_px /* NOLINT */, - /* return args */ - float r_loc[3] /* NOLINT */, - float r_no[3] /* NOLINT */, - int *r_index /* NOLINT */, - Object **r_ob, - float r_obmat[4][4]) +static eSnapMode snapObjectsRay(SnapObjectContext *sctx, + const SnapObjectParams *params, + /* read/write args */ + /* Parameters below cannot be const, because they are assigned to a + * non-const variable (readability-non-const-parameter). */ + float *dist_px /* NOLINT */, + /* return args */ + float r_loc[3] /* NOLINT */, + float r_no[3] /* NOLINT */, + int *r_index /* NOLINT */, + Object **r_ob, + float r_obmat[4][4]) { SnapObjUserData data = {}; data.dist_px = dist_px; @@ -2836,7 +2835,7 @@ static short snapObjectsRay(SnapObjectContext *sctx, data.r_ob = r_ob; data.r_index = r_index; data.r_obmat = r_obmat; - data.ret = 0; + data.ret = SCE_SNAP_MODE_NONE; iter_snap_objects(sctx, params, snap_obj_fn, &data); @@ -3009,31 +3008,29 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx, sctx, depsgraph, v3d, params, ray_origin, ray_direction, ray_depth, r_co, r_no); } -static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx, - Depsgraph *depsgraph, - const ARegion *region, - const View3D *v3d, - const ushort snap_to_flag, - const SnapObjectParams *params, - const float mval[2], - const float prev_co[3], - float *dist_px, - float r_loc[3], - float r_no[3], - int *r_index, - Object **r_ob, - float r_obmat[4][4], - float r_face_nor[3]) +static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx, + Depsgraph *depsgraph, + const ARegion *region, + const View3D *v3d, + const eSnapMode snap_to_flag, + const SnapObjectParams *params, + const float mval[2], + const float prev_co[3], + float *dist_px, + float r_loc[3], + float r_no[3], + int *r_index, + Object **r_ob, + float r_obmat[4][4], + float r_face_nor[3]) { sctx->runtime.depsgraph = depsgraph; sctx->runtime.region = region; sctx->runtime.v3d = v3d; - BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) != - 0); + BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0); - short retval = 0; + eSnapMode retval = SCE_SNAP_MODE_NONE; bool has_hit = false; Object *ob_eval = nullptr; @@ -3052,7 +3049,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext float ray_start[3], ray_normal[3]; if (!ED_view3d_win_to_ray_clipped_ex( depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) { - return 0; + return SCE_SNAP_MODE_NONE; } float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; @@ -3096,7 +3093,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { - short elem_test, elem = 0; + eSnapMode elem_test, elem = SCE_SNAP_MODE_NONE; float dist_px_tmp = *dist_px; copy_m4_m4(sctx->runtime.pmat, rv3d->persmat); @@ -3106,9 +3103,11 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext sctx->runtime.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; /* First snap to edge instead of middle or perpendicular. */ - sctx->runtime.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE); + sctx->runtime.snap_to_flag = static_cast<eSnapMode>( + snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE)); if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { - sctx->runtime.snap_to_flag |= SCE_SNAP_MODE_EDGE; + sctx->runtime.snap_to_flag = static_cast<eSnapMode>(sctx->runtime.snap_to_flag | + SCE_SNAP_MODE_EDGE); } planes_from_projmat(sctx->runtime.pmat, @@ -3192,21 +3191,21 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext return retval; } -short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, - Depsgraph *depsgraph, - const ARegion *region, - const View3D *v3d, - const ushort snap_to, - const SnapObjectParams *params, - const float mval[2], - const float prev_co[3], - float *dist_px, - float r_loc[3], - float r_no[3], - int *r_index, - Object **r_ob, - float r_obmat[4][4], - float r_face_nor[3]) +eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, + Depsgraph *depsgraph, + const ARegion *region, + const View3D *v3d, + const eSnapMode snap_to, + const SnapObjectParams *params, + const float mval[2], + const float prev_co[3], + float *dist_px, + float r_loc[3], + float r_no[3], + int *r_index, + Object **r_ob, + float r_obmat[4][4], + float r_face_nor[3]) { return transform_snap_context_project_view3d_mixed_impl(sctx, depsgraph, @@ -3225,17 +3224,17 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, r_face_nor); } -short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, - Depsgraph *depsgraph, - const ARegion *region, - const View3D *v3d, - const ushort snap_to, - const SnapObjectParams *params, - const float mval[2], - const float prev_co[3], - float *dist_px, - float r_loc[3], - float r_no[3]) +eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, + Depsgraph *depsgraph, + const ARegion *region, + const View3D *v3d, + const eSnapMode snap_to, + const SnapObjectParams *params, + const float mval[2], + const float prev_co[3], + float *dist_px, + float r_loc[3], + float r_no[3]) { return ED_transform_snap_object_project_view3d_ex(sctx, depsgraph, diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c index 7dc361ff5bb..dbcae2b6320 100644 --- a/source/blender/editors/transform/transform_snap_sequencer.c +++ b/source/blender/editors/transform/transform_snap_sequencer.c @@ -25,6 +25,7 @@ #include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "transform.h" #include "transform_snap.h" @@ -65,14 +66,14 @@ static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollect SEQ_ITERATOR_FOREACH (seq, snap_sources) { int left = 0, right = 0; if (seq->flag & SEQ_LEFTSEL) { - left = right = seq->startdisp; + left = right = SEQ_time_left_handle_frame_get(seq); } else if (seq->flag & SEQ_RIGHTSEL) { - left = right = seq->enddisp; + left = right = SEQ_time_right_handle_frame_get(seq); } else { - left = seq->startdisp; - right = seq->enddisp; + left = SEQ_time_left_handle_frame_get(seq); + right = SEQ_time_right_handle_frame_get(seq); } snap_data->source_snap_points[i] = left; @@ -193,21 +194,24 @@ static void seq_snap_target_points_build(Scene *scene, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, snap_targets) { - snap_data->target_snap_points[i] = seq->startdisp; - snap_data->target_snap_points[i + 1] = seq->enddisp; + snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(seq); + snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(seq); i += 2; if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) { - int content_start = min_ii(seq->enddisp, seq->start); - int content_end = max_ii(seq->startdisp, seq->start + seq->len); + int content_start = min_ii(SEQ_time_right_handle_frame_get(seq), seq->start); + int content_end = max_ii(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len); /* Effects and single image strips produce incorrect content length. Skip these strips. */ if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->len == 1) { - content_start = seq->startdisp; - content_end = seq->enddisp; + content_start = SEQ_time_left_handle_frame_get(seq); + content_end = SEQ_time_right_handle_frame_get(seq); } - CLAMP(content_start, seq->startdisp, seq->enddisp); - CLAMP(content_end, seq->startdisp, seq->enddisp); + CLAMP(content_start, + SEQ_time_left_handle_frame_get(seq), + SEQ_time_right_handle_frame_get(seq)); + CLAMP( + content_end, SEQ_time_left_handle_frame_get(seq), SEQ_time_right_handle_frame_get(seq)); snap_data->target_snap_points[i] = content_start; snap_data->target_snap_points[i + 1] = content_end; diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 89d80d582f8..5c2a3374aa1 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -91,6 +91,7 @@ set(SRC ../include/ED_uvedit.h ../include/ED_view3d.h ../include/ED_view3d_offscreen.h + ../include/UI_grid_view.hh ../include/UI_icons.h ../include/UI_interface.h ../include/UI_interface.hh diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c index 263ef06718f..660afa4c3d7 100644 --- a/source/blender/editors/util/select_utils.c +++ b/source/blender/editors/util/select_utils.c @@ -66,15 +66,18 @@ eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first) return sel_op; } -int ED_select_similar_compare_float(const float delta, const float thresh, const int compare) +bool ED_select_similar_compare_float(const float delta, + const float thresh, + const eSimilarCmp compare) { + BLI_assert(thresh >= 0.0f); switch (compare) { case SIM_CMP_EQ: return (fabsf(delta) <= thresh); case SIM_CMP_GT: - return ((delta + thresh) >= 0.0); + return ((delta + thresh) >= 0.0f); case SIM_CMP_LT: - return ((delta - thresh) <= 0.0); + return ((delta - thresh) <= 0.0f); default: BLI_assert_unreachable(); return 0; @@ -84,8 +87,10 @@ int ED_select_similar_compare_float(const float delta, const float thresh, const bool ED_select_similar_compare_float_tree(const KDTree_1d *tree, const float length, const float thresh, - const int compare) + const eSimilarCmp compare) { + BLI_assert(compare == SIM_CMP_EQ || length >= 0.0f); /* See precision note below. */ + /* Length of the edge we want to compare against. */ float nearest_edge_length; @@ -112,6 +117,7 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree, KDTreeNearest_1d nearest; if (BLI_kdtree_1d_find_nearest(tree, &nearest_edge_length, &nearest) != -1) { + BLI_assert(compare == SIM_CMP_EQ || nearest.co[0] >= 0.0f); /* See precision note above. */ float delta = length - nearest.co[0]; return ED_select_similar_compare_float(delta, thresh, compare); } diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 181982f0b2c..04128cf378c 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -182,5 +182,6 @@ void UV_OT_select_circle(struct wmOperatorType *ot); void UV_OT_select_more(struct wmOperatorType *ot); void UV_OT_select_less(struct wmOperatorType *ot); void UV_OT_select_overlap(struct wmOperatorType *ot); +void UV_OT_select_similar(struct wmOperatorType *ot); /* Used only when UV sync select is disabled. */ void UV_OT_select_mode(struct wmOperatorType *ot); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index fe6f9f0d513..0b5d6592426 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -2044,6 +2044,7 @@ void ED_operatortypes_uvedit(void) WM_operatortype_append(UV_OT_select_pinned); WM_operatortype_append(UV_OT_select_box); WM_operatortype_append(UV_OT_select_lasso); + WM_operatortype_append(UV_OT_select_similar); WM_operatortype_append(UV_OT_select_circle); WM_operatortype_append(UV_OT_select_more); WM_operatortype_append(UV_OT_select_less); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index ead017a91bf..964ac5f650b 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -12,6 +12,7 @@ #include "MEM_guardedalloc.h" #include "DNA_image_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -22,6 +23,7 @@ #include "BLI_blenlib.h" #include "BLI_hash.h" #include "BLI_kdopbvh.h" +#include "BLI_kdtree.h" #include "BLI_lasso_2d.h" #include "BLI_math.h" #include "BLI_polyfill_2d.h" @@ -31,6 +33,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_layer.h" +#include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_report.h" @@ -75,6 +78,16 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit); +typedef enum { + UV_SSIM_AREA_UV = 1000, + UV_SSIM_AREA_3D, + UV_SSIM_LENGTH_UV, + UV_SSIM_LENGTH_3D, + UV_SSIM_SIDES, + UV_SSIM_PIN, + UV_SSIM_MATERIAL, +} eUVSelectSimilar; + /* -------------------------------------------------------------------- */ /** \name Active Selection Tracking * @@ -586,12 +599,25 @@ bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_lo if (ts->selectmode & SCE_SELECT_FACE) { return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); } + if (ts->selectmode & SCE_SELECT_EDGE) { + /* Are you looking for `uvedit_edge_select_test(...)` instead? */ + } return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); } MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (ts->selectmode & SCE_SELECT_FACE) { + /* Are you looking for `uvedit_face_select_test(...)` instead? */ + } + + if (ts->selectmode & SCE_SELECT_EDGE) { + /* Are you looking for `uvedit_edge_select_test(...)` instead? */ + } + return (luv->flag & MLOOPUV_VERTSEL) != 0; } + bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) { return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); @@ -699,6 +725,10 @@ void uvedit_uv_select_enable(const Scene *scene, { const ToolSettings *ts = scene->toolsettings; + if (ts->selectmode & SCE_SELECT_EDGE) { + /* Are you looking for `uvedit_edge_select_set(...)` instead? */ + } + if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { BM_face_select_set(em->bm, l->f, true); @@ -2425,7 +2455,7 @@ static bool uv_mouse_select_multi(bContext *C, UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(®ion->v2d, 75.0f); int selectmode, sticky; bool found_item = false; - /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */ int flush = 0; /* Penalty (in pixels) applied to elements that are already selected @@ -2514,8 +2544,15 @@ static bool uv_mouse_select_multi(bContext *C, else if (selectmode == UV_SELECT_EDGE) { is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset); } - else { /* Vertex or island. */ - is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + else { + /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above), + * `hit.l` is NULL, use `hit.efa` instead. */ + if (hit.l != NULL) { + is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + } + else { + is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset); + } } } @@ -2728,7 +2765,7 @@ static int uv_mouse_select_loop_generic_multi(bContext *C, const ToolSettings *ts = scene->toolsettings; UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); bool found_item = false; - /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */ int flush = 0; /* Find edge. */ @@ -3282,8 +3319,6 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (select) { @@ -3353,8 +3388,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co /* now select tagged verts */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - 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); @@ -3373,8 +3406,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co } BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l, BM_ELEM_TAG)) { uv_select_flush_from_tag_sticky_loc_internal( @@ -4411,6 +4442,550 @@ void UV_OT_select_overlap(wmOperatorType *ot) } /** \} */ +/** \name Select Similar Operator + * \{ */ + +static float get_uv_vert_needle(const eUVSelectSimilar type, + BMVert *vert, + const float ob_m3[3][3], + MLoopUV *luv, + const int cd_loop_uv_offset) +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { + result += BM_face_calc_area_uv(f, cd_loop_uv_offset); + } + } break; + case UV_SSIM_AREA_3D: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { + result += BM_face_calc_area_with_mat3(f, ob_m3); + } + } break; + case UV_SSIM_SIDES: { + BMEdge *e; + BMIter iter; + BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) { + result += 1.0f; + } + } break; + case UV_SSIM_PIN: + return (luv->flag & MLOOPUV_PINNED) ? 1.0f : 0.0f; + default: + BLI_assert_unreachable(); + return false; + } + + return result; +} + +static float get_uv_edge_needle(const eUVSelectSimilar type, + BMEdge *edge, + const float ob_m3[3][3], + MLoopUV *luv_a, + MLoopUV *luv_b, + const int cd_loop_uv_offset) +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { + result += BM_face_calc_area_uv(f, cd_loop_uv_offset); + } + } break; + case UV_SSIM_AREA_3D: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { + result += BM_face_calc_area_with_mat3(f, ob_m3); + } + } break; + case UV_SSIM_LENGTH_UV: + return len_v2v2(luv_a->uv, luv_b->uv); + case UV_SSIM_LENGTH_3D: + return len_v3v3(edge->v1->co, edge->v2->co); + case UV_SSIM_SIDES: { + BMEdge *e; + BMIter iter; + BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) { + result += 1.0f; + } + } break; + case UV_SSIM_PIN: + if (luv_a->flag & MLOOPUV_PINNED) { + result += 1.0f; + } + if (luv_b->flag & MLOOPUV_PINNED) { + result += 1.0f; + } + break; + default: + BLI_assert_unreachable(); + return false; + } + + return result; +} + +static float get_uv_face_needle(const eUVSelectSimilar type, + BMFace *face, + const float ob_m3[3][3], + const int cd_loop_uv_offset) +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: + return BM_face_calc_area_uv(face, cd_loop_uv_offset); + case UV_SSIM_AREA_3D: + return BM_face_calc_area_with_mat3(face, ob_m3); + case UV_SSIM_SIDES: + return face->len; + case UV_SSIM_PIN: { + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_PINNED) { + result += 1.0f; + } + } + } break; + case UV_SSIM_MATERIAL: + return face->mat_nr; + default: + BLI_assert_unreachable(); + return false; + } + return result; +} + +static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + int max_verts_selected_all = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + max_verts_selected_all += face->len; + } + /* TODO: Get a tighter bounds */ + } + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_verts_selected_all); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + continue; + } + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset); + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + bool changed = false; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + continue; /* Already selected. */ + } + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + 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); + changed = true; + } + } + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, ob); + } + } + } + + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + return OPERATOR_FINISHED; +} + +static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + int max_edges_selected_all = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + max_edges_selected_all += face->len; + } + /* TODO: Get a tighter bounds. */ + } + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_edges_selected_all); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { + continue; + } + + MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset); + if (tree_1d) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + bool changed = false; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { + continue; /* Already selected. */ + } + + MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + 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); + changed = true; + } + } + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, ob); + } + } + } + + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + return OPERATOR_FINISHED; +} + +static int uv_select_similar_face_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + int max_faces_selected_all = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + max_faces_selected_all += em->bm->totfacesel; + /* TODO: Get a tighter bounds */ + } + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_faces_selected_all); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + if (!uvedit_face_select_test(scene, face, cd_loop_uv_offset)) { + continue; + } + + float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset); + if (tree_1d) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + bool changed = false; + bool do_history = false; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + if (uvedit_face_select_test(scene, face, cd_loop_uv_offset)) { + continue; + } + + float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset); + + 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); + changed = true; + } + } + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, ob); + } + } + + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + return OPERATOR_FINISHED; +} + +/* Select similar UV faces/edges/verts based on current selection. */ +static int uv_select_similar_exec(bContext *C, wmOperator *op) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold"); + + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set(op->ptr, prop, ts->select_thresh); + } + else { + ts->select_thresh = RNA_property_float_get(op->ptr, prop); + } + + int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode; + if (selectmode & UV_SELECT_EDGE) { + return uv_select_similar_edge_exec(C, op); + } + if (selectmode & UV_SELECT_FACE) { + return uv_select_similar_face_exec(C, op); + } + if (selectmode & UV_SELECT_ISLAND) { + // return uv_select_similar_island_exec(C, op); + } + + return uv_select_similar_vert_exec(C, op); +} + +static EnumPropertyItem prop_vert_similar_types[] = {{UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, {0}}; + +static EnumPropertyItem prop_edge_similar_types[] = { + {UV_SSIM_LENGTH_UV, "LENGTH", 0, "Length", ""}, + {UV_SSIM_LENGTH_3D, "LENGTH_3D", 0, "Length 3D", ""}, + {UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, + {0}}; + +static EnumPropertyItem prop_face_similar_types[] = { + {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""}, + {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""}, + {UV_SSIM_SIDES, "SIDES", 0, "Polygon Sides", ""}, + {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""}, + {0}}; + +static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, + {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, + {SIM_CMP_LT, "LESS", 0, "Less", ""}, + {0}}; + +static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *UNUSED(r_free)) +{ + const ToolSettings *ts = CTX_data_tool_settings(C); + if (ts) { + int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode; + if (selectmode & UV_SELECT_EDGE) { + return prop_edge_similar_types; + } + if (selectmode & UV_SELECT_FACE) { + return prop_face_similar_types; + } + } + + return prop_vert_similar_types; +} +void UV_OT_select_similar(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Similar"; + ot->description = "Select similar UVs by property types"; + ot->idname = "UV_OT_select_similar"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = uv_select_similar_exec; + ot->poll = ED_operator_uvedit_space_image; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop = ot->prop = RNA_def_enum( + ot->srna, "type", prop_vert_similar_types, SIMVERT_NORMAL, "Type", ""); + RNA_def_enum_funcs(prop, uv_select_similar_type_itemf); + RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", ""); + RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); +} + +/** \} */ /* -------------------------------------------------------------------- */ /** \name Selected Elements as Arrays (Vertex, Edge & Faces) diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index bacf321fce1..55e44607f6f 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1716,7 +1716,7 @@ static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float GPU_batch_discard(batch); } -/* TODO: make things pretier : store batches inside StitchPreviewer instead of the bare verts pos +/* TODO: make things prettier : store batches inside StitchPreviewer instead of the bare verts pos */ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) { diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 84dca352c9f..3618286ec01 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -298,38 +298,73 @@ void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy) ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy); } +static bool uvedit_is_face_affected(const Scene *scene, + BMFace *efa, + const UnwrapOptions *options, + const int cd_loop_uv_offset) +{ + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + return false; + } + + if (options->only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + return false; + } + + if (options->topology_from_uvs && options->only_selected_uvs && + !uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + return false; + } + + return true; +} + +/* Prepare unique indices for each unique pinned UV, even if it shares a BMVert. + */ +static void uvedit_prepare_pinned_indices(ParamHandle *handle, + BMFace *efa, + const int cd_loop_uv_offset) +{ + BMIter liter; + BMLoop *l; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_PINNED) { + int bmvertindex = BM_elem_index_get(l->v); + GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv); + } + } +} + static void construct_param_handle_face_add(ParamHandle *handle, const Scene *scene, BMFace *efa, - int face_index, + ParamKey face_index, const int cd_loop_uv_offset) { - ParamKey key; ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len); - ParamBool *pin = BLI_array_alloca(pin, efa->len); - ParamBool *select = BLI_array_alloca(select, efa->len); - float **co = BLI_array_alloca(co, efa->len); + bool *pin = BLI_array_alloca(pin, efa->len); + bool *select = BLI_array_alloca(select, efa->len); + const float **co = BLI_array_alloca(co, efa->len); float **uv = BLI_array_alloca(uv, efa->len); int i; BMIter liter; BMLoop *l; - key = (ParamKey)face_index; - /* let parametrizer split the ngon, it can make better decisions * about which split is best for unwrapping than poly-fill. */ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - vkeys[i] = (ParamKey)BM_elem_index_get(l->v); + vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv); co[i] = l->v->co; uv[i] = luv->uv; pin[i] = (luv->flag & MLOOPUV_PINNED) != 0; select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); } - GEO_uv_parametrizer_face_add(handle, key, i, vkeys, co, uv, pin, select); + GEO_uv_parametrizer_face_add(handle, face_index, i, vkeys, co, uv, pin, select); } /* See: construct_param_handle_multi to handle multiple objects at once. */ @@ -340,13 +375,10 @@ static ParamHandle *construct_param_handle(const Scene *scene, UnwrapResultInfo *result_info) { BMFace *efa; - BMLoop *l; BMEdge *eed; - BMIter iter, liter; + BMIter iter; int i; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - ParamHandle *handle = GEO_uv_parametrizer_construct_begin(); if (options->correct_aspect) { @@ -362,30 +394,17 @@ static ParamHandle *construct_param_handle(const Scene *scene, /* we need the vert indices */ BM_mesh_elem_index_ensure(bm, BM_VERT); + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) || - (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) { - continue; + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset); } + } - if (options->topology_from_uvs) { - bool is_loopsel = false; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (options->only_selected_uvs && - (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) { - continue; - } - is_loopsel = true; - break; - } - if (is_loopsel == false) { - continue; - } + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset); } - - construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset); } if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) { @@ -417,9 +436,8 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene, int *count_fail) { BMFace *efa; - BMLoop *l; BMEdge *eed; - BMIter iter, liter; + BMIter iter; int i; ParamHandle *handle = GEO_uv_parametrizer_construct_begin(); @@ -451,29 +469,15 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene, } BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) || - (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) { - continue; + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset); } + } - if (options->topology_from_uvs) { - bool is_loopsel = false; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (options->only_selected_uvs && - (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) { - continue; - } - is_loopsel = true; - break; - } - if (is_loopsel == false) { - continue; - } + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset); } - - construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset); } if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) { @@ -500,8 +504,8 @@ static void texface_from_original_index(const Scene *scene, BMFace *efa, int index, float **r_uv, - ParamBool *r_pin, - ParamBool *r_select) + bool *r_pin, + bool *r_select) { BMLoop *l; BMIter liter; @@ -633,8 +637,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, /* Prepare and feed faces to the solver */ for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) { ParamKey key, vkeys[4]; - ParamBool pin[4], select[4]; - float *co[4]; + bool pin[4], select[4]; + const float *co[4]; float *uv[4]; BMFace *origFace = faceMap[i]; @@ -652,7 +656,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, mloop = &subsurfedLoops[mpoly->loopstart]; - /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ + /* We will not check for v4 here. Sub-surface faces always have 4 vertices. */ BLI_assert(mpoly->totloop == 4); key = (ParamKey)i; vkeys[0] = (ParamKey)mloop[0].v; @@ -1245,7 +1249,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) handle = construct_param_handle(scene, obedit, em->bm, &options, NULL); } - GEO_uv_parametrizer_lscm_begin(handle, PARAM_TRUE, abf); + GEO_uv_parametrizer_lscm_begin(handle, true, abf); /* Create or increase size of g_live_unwrap.handles array */ if (g_live_unwrap.handles == NULL) { @@ -1796,7 +1800,7 @@ static void uvedit_unwrap(const Scene *scene, handle = construct_param_handle(scene, obedit, em->bm, options, result_info); } - GEO_uv_parametrizer_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); + GEO_uv_parametrizer_lscm_begin(handle, false, scene->toolsettings->unwrapper == 0); GEO_uv_parametrizer_lscm_solve(handle, result_info ? &result_info->count_changed : NULL, result_info ? &result_info->count_failed : NULL); diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 46051a58e8b..a8136d06c5f 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -476,6 +476,8 @@ template<typename T> T evaluate_constant_field(const Field<T> &field) return value; } +Field<bool> invert_boolean_field(const Field<bool> &field); + GField make_constant_field(const CPPType &type, const void *value); template<typename T> Field<T> make_constant_field(T value) diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index 9d09378ab63..16a33c9cda7 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -41,6 +41,10 @@ class MFParamsBuilder { MFParamsBuilder(const MFSignature &signature, const IndexMask mask) : signature_(&signature), mask_(mask), min_array_size_(mask.min_array_size()) { + virtual_arrays_.reserve(signature.virtual_array_num); + mutable_spans_.reserve(signature.span_num); + virtual_vector_arrays_.reserve(signature.virtual_vector_array_num); + vector_arrays_.reserve(signature.vector_array_num); } public: @@ -53,28 +57,33 @@ class MFParamsBuilder { template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "") { - this->add_readonly_single_input(VArray<T>::ForSingle(std::move(value), min_array_size_), - expected_name); + this->assert_current_param_type(MFParamType::ForSingleInput(CPPType::get<T>()), expected_name); + virtual_arrays_.append_unchecked_as( + varray_tag::single{}, CPPType::get<T>(), min_array_size_, &value); } template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "") { - this->add_readonly_single_input( - GVArray::ForSingleRef(CPPType::get<T>(), min_array_size_, value), expected_name); + this->assert_current_param_type(MFParamType::ForSingleInput(CPPType::get<T>()), expected_name); + virtual_arrays_.append_unchecked_as( + varray_tag::single_ref{}, CPPType::get<T>(), min_array_size_, value); } void add_readonly_single_input(const GSpan span, StringRef expected_name = "") { - this->add_readonly_single_input(GVArray::ForSpan(span), expected_name); + this->assert_current_param_type(MFParamType::ForSingleInput(span.type()), expected_name); + BLI_assert(span.size() >= min_array_size_); + virtual_arrays_.append_unchecked_as(varray_tag::span{}, span); } void add_readonly_single_input(GPointer value, StringRef expected_name = "") { - this->add_readonly_single_input( - GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name); + this->assert_current_param_type(MFParamType::ForSingleInput(*value.type()), expected_name); + virtual_arrays_.append_unchecked_as( + varray_tag::single_ref{}, *value.type(), min_array_size_, value.get()); } void add_readonly_single_input(GVArray varray, StringRef expected_name = "") { this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name); BLI_assert(varray.size() >= min_array_size_); - virtual_arrays_.append(varray); + virtual_arrays_.append_unchecked_as(std::move(varray)); } void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "") @@ -92,7 +101,7 @@ class MFParamsBuilder { { this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()), expected_name); BLI_assert(ref.size() >= min_array_size_); - virtual_vector_arrays_.append(&ref); + virtual_vector_arrays_.append_unchecked(&ref); } template<typename T> void add_uninitialized_single_output(T *value, StringRef expected_name = "") @@ -104,7 +113,7 @@ class MFParamsBuilder { { this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type()), expected_name); BLI_assert(ref.size() >= min_array_size_); - mutable_spans_.append(ref); + mutable_spans_.append_unchecked(ref); } void add_ignored_single_output(StringRef expected_name = "") { @@ -115,7 +124,7 @@ class MFParamsBuilder { const CPPType &type = param_type.data_type().single_type(); /* An empty span indicates that this is ignored. */ const GMutableSpan dummy_span{type}; - mutable_spans_.append(dummy_span); + mutable_spans_.append_unchecked(dummy_span); } void add_vector_output(GVectorArray &vector_array, StringRef expected_name = "") @@ -123,14 +132,14 @@ class MFParamsBuilder { this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type()), expected_name); BLI_assert(vector_array.size() >= min_array_size_); - vector_arrays_.append(&vector_array); + vector_arrays_.append_unchecked(&vector_array); } void add_single_mutable(GMutableSpan ref, StringRef expected_name = "") { this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type()), expected_name); BLI_assert(ref.size() >= min_array_size_); - mutable_spans_.append(ref); + mutable_spans_.append_unchecked(ref); } void add_vector_mutable(GVectorArray &vector_array, StringRef expected_name = "") @@ -138,7 +147,7 @@ class MFParamsBuilder { this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type()), expected_name); BLI_assert(vector_array.size() >= min_array_size_); - vector_arrays_.append(&vector_array); + vector_arrays_.append_unchecked(&vector_array); } GMutableSpan computed_array(int param_index) diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh index 75a54992a48..da269b08155 100644 --- a/source/blender/functions/FN_multi_function_procedure.hh +++ b/source/blender/functions/FN_multi_function_procedure.hh @@ -87,7 +87,7 @@ class MFVariable : NonCopyable, NonMovable { MFDataType data_type_; Vector<MFInstruction *> users_; std::string name_; - int id_; + int index_in_graph_; friend MFProcedure; friend MFCallInstruction; @@ -101,7 +101,7 @@ class MFVariable : NonCopyable, NonMovable { StringRefNull name() const; void set_name(std::string name); - int id() const; + int index_in_procedure() const; }; /** Base class for all instruction types. */ @@ -376,9 +376,9 @@ inline StringRefNull MFVariable::name() const return name_; } -inline int MFVariable::id() const +inline int MFVariable::index_in_procedure() const { - return id_; + return index_in_graph_; } /** \} */ diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh index 62c491609a4..6181555dbd1 100644 --- a/source/blender/functions/FN_multi_function_signature.hh +++ b/source/blender/functions/FN_multi_function_signature.hh @@ -29,6 +29,15 @@ struct MFSignature { Vector<int> param_data_indices; bool depends_on_context = false; + /** + * Number of elements of each of these types that has to be passed into the multi-function as an + * input or output. + */ + int span_num = 0; + int virtual_array_num = 0; + int virtual_vector_array_num = 0; + int vector_array_num = 0; + int data_index(int param_index) const { return param_data_indices[param_index]; @@ -38,10 +47,6 @@ struct MFSignature { class MFSignatureBuilder { private: MFSignature signature_; - int span_count_ = 0; - int virtual_array_count_ = 0; - int virtual_vector_array_count_ = 0; - int vector_array_count_ = 0; public: MFSignatureBuilder(const char *function_name) @@ -79,10 +84,10 @@ class MFSignatureBuilder { switch (data_type.category()) { case MFDataType::Single: - signature_.param_data_indices.append(virtual_array_count_++); + signature_.param_data_indices.append(signature_.virtual_array_num++); break; case MFDataType::Vector: - signature_.param_data_indices.append(virtual_vector_array_count_++); + signature_.param_data_indices.append(signature_.virtual_vector_array_num++); break; } } @@ -112,10 +117,10 @@ class MFSignatureBuilder { switch (data_type.category()) { case MFDataType::Single: - signature_.param_data_indices.append(span_count_++); + signature_.param_data_indices.append(signature_.span_num++); break; case MFDataType::Vector: - signature_.param_data_indices.append(vector_array_count_++); + signature_.param_data_indices.append(signature_.vector_array_num++); break; } } @@ -145,10 +150,10 @@ class MFSignatureBuilder { switch (data_type.category()) { case MFDataType::Single: - signature_.param_data_indices.append(span_count_++); + signature_.param_data_indices.append(signature_.span_num++); break; case MFDataType::Vector: - signature_.param_data_indices.append(vector_array_count_++); + signature_.param_data_indices.append(signature_.vector_array_num++); break; } } diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index a53da717606..fd5eab57d33 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -518,6 +518,14 @@ GField make_field_constant_if_possible(GField field) return new_field; } +Field<bool> invert_boolean_field(const Field<bool> &field) +{ + static CustomMF_SI_SO<bool, bool> not_fn{ + "Not", [](bool a) { return !a; }, CustomMF_presets::AllSpanOrSingle()}; + auto not_op = std::make_shared<FieldOperation>(FieldOperation(not_fn, {field})); + return Field<bool>(not_op); +} + GField make_constant_field(const CPPType &type, const void *value) { auto constant_node = std::make_shared<FieldConstant>(type, value); @@ -700,20 +708,11 @@ GPointer FieldConstant::value() const */ static IndexMask index_mask_from_selection(const IndexMask full_mask, - VArray<bool> &selection, + const VArray<bool> &selection, ResourceScope &scope) { - if (selection.is_span()) { - Span<bool> span = selection.get_internal_span(); - return index_mask_ops::find_indices_based_on_predicate( - full_mask, 4096, scope.construct<Vector<int64_t>>(), [&](const int curve_index) { - return span[curve_index]; - }); - } - return index_mask_ops::find_indices_based_on_predicate( - full_mask, 1024, scope.construct<Vector<int64_t>>(), [&](const int curve_index) { - return selection[curve_index]; - }); + return index_mask_ops::find_indices_from_virtual_array( + full_mask, selection, 1024, scope.construct<Vector<int64_t>>()); } int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst) @@ -756,12 +755,6 @@ static IndexMask evaluate_selection(const Field<bool> &selection_field, if (selection_field) { VArray<bool> selection = evaluate_fields(scope, {selection_field}, full_mask, context)[0].typed<bool>(); - if (selection.is_single()) { - if (selection.get_internal_single()) { - return full_mask; - } - return IndexRange(0); - } return index_mask_from_selection(full_mask, selection, scope); } return full_mask; diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc index bc045bfd44b..7ad324a9574 100644 --- a/source/blender/functions/intern/multi_function_procedure.cc +++ b/source/blender/functions/intern/multi_function_procedure.cc @@ -173,7 +173,7 @@ MFVariable &MFProcedure::new_variable(MFDataType data_type, std::string name) MFVariable &variable = *allocator_.construct<MFVariable>().release(); variable.name_ = std::move(name); variable.data_type_ = data_type; - variable.id_ = variables_.size(); + variable.index_in_graph_ = variables_.size(); variables_.append(&variable); return variable; } @@ -753,7 +753,7 @@ class MFProcedureDotExport { ss << "null"; } else { - ss << "$" << variable->id(); + ss << "$" << variable->index_in_procedure(); if (!variable->name().is_empty()) { ss << "(" << variable->name() << ")"; } diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc index d852fe19924..a45240dad55 100644 --- a/source/blender/functions/intern/multi_function_procedure_executor.cc +++ b/source/blender/functions/intern/multi_function_procedure_executor.cc @@ -157,10 +157,6 @@ class ValueAllocator : NonCopyable, NonMovable { { } - template<typename... Args> VariableState *obtain_variable_state(Args &&...args); - - void release_variable_state(VariableState *state); - VariableValue_GVArray *obtain_GVArray(const GVArray &varray) { return this->obtain<VariableValue_GVArray>(varray); @@ -294,32 +290,27 @@ class ValueAllocator : NonCopyable, NonMovable { * This class keeps track of a single variable during evaluation. */ class VariableState : NonCopyable, NonMovable { - private: + public: /** The current value of the variable. The storage format may change over time. */ - VariableValue *value_; + VariableValue *value_ = nullptr; /** Number of indices that are currently initialized in this variable. */ - int tot_initialized_; + int tot_initialized_ = 0; /* This a non-owning pointer to either span buffer or #GVectorArray or null. */ void *caller_provided_storage_ = nullptr; - public: - VariableState(VariableValue &value, int tot_initialized, void *caller_provided_storage = nullptr) - : value_(&value), - tot_initialized_(tot_initialized), - caller_provided_storage_(caller_provided_storage) - { - } - - void destruct_self(ValueAllocator &value_allocator, const MFDataType &data_type) + void destruct_value(ValueAllocator &value_allocator, const MFDataType &data_type) { value_allocator.release_value(value_, data_type); - value_allocator.release_variable_state(this); + value_ = nullptr; } /* True if this contains only one value for all indices, i.e. the value for all indices is * the same. */ bool is_one() const { + if (value_ == nullptr) { + return true; + } switch (value_->type) { case ValueType::GVArray: return this->value_as<VariableValue_GVArray>()->data.is_single(); @@ -353,6 +344,7 @@ class VariableState : NonCopyable, NonMovable { { /* Sanity check to make sure that enough values are initialized. */ BLI_assert(mask.size() <= tot_initialized_); + BLI_assert(value_ != nullptr); switch (value_->type) { case ValueType::GVArray: { @@ -391,7 +383,7 @@ class VariableState : NonCopyable, NonMovable { const MFDataType &data_type, ValueAllocator &value_allocator) { - if (ELEM(value_->type, ValueType::Span, ValueType::GVectorArray)) { + if (value_ != nullptr && ELEM(value_->type, ValueType::Span, ValueType::GVectorArray)) { return; } @@ -408,22 +400,24 @@ class VariableState : NonCopyable, NonMovable { /* Reuse the storage provided caller when possible. */ new_value = value_allocator.obtain_Span_not_owned(caller_provided_storage_); } - if (value_->type == ValueType::GVArray) { - /* Fill new buffer with data from virtual array. */ - this->value_as<VariableValue_GVArray>()->data.materialize_to_uninitialized( - full_mask, new_value->data); - } - else if (value_->type == ValueType::OneSingle) { - auto *old_value_typed_ = this->value_as<VariableValue_OneSingle>(); - if (old_value_typed_->is_initialized) { - /* Fill the buffer with a single value. */ - type.fill_construct_indices(old_value_typed_->data, new_value->data, full_mask); + if (value_ != nullptr) { + if (value_->type == ValueType::GVArray) { + /* Fill new buffer with data from virtual array. */ + this->value_as<VariableValue_GVArray>()->data.materialize_to_uninitialized( + full_mask, new_value->data); } + else if (value_->type == ValueType::OneSingle) { + auto *old_value_typed_ = this->value_as<VariableValue_OneSingle>(); + if (old_value_typed_->is_initialized) { + /* Fill the buffer with a single value. */ + type.fill_construct_indices(old_value_typed_->data, new_value->data, full_mask); + } + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); } - else { - BLI_assert_unreachable(); - } - value_allocator.release_value(value_, data_type); value_ = new_value; break; } @@ -437,19 +431,21 @@ class VariableState : NonCopyable, NonMovable { new_value = value_allocator.obtain_GVectorArray_not_owned( *(GVectorArray *)caller_provided_storage_); } - if (value_->type == ValueType::GVVectorArray) { - /* Fill new vector array with data from virtual vector array. */ - new_value->data.extend(full_mask, this->value_as<VariableValue_GVVectorArray>()->data); - } - else if (value_->type == ValueType::OneVector) { - /* Fill all indices with the same value. */ - const GSpan vector = this->value_as<VariableValue_OneVector>()->data[0]; - new_value->data.extend(full_mask, GVVectorArray_For_SingleGSpan{vector, array_size}); - } - else { - BLI_assert_unreachable(); + if (value_ != nullptr) { + if (value_->type == ValueType::GVVectorArray) { + /* Fill new vector array with data from virtual vector array. */ + new_value->data.extend(full_mask, this->value_as<VariableValue_GVVectorArray>()->data); + } + else if (value_->type == ValueType::OneVector) { + /* Fill all indices with the same value. */ + const GSpan vector = this->value_as<VariableValue_OneVector>()->data[0]; + new_value->data.extend(full_mask, GVVectorArray_For_SingleGSpan{vector, array_size}); + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); } - value_allocator.release_value(value_, data_type); value_ = new_value; break; } @@ -466,6 +462,7 @@ class VariableState : NonCopyable, NonMovable { BLI_assert(mask.size() <= tot_initialized_); this->ensure_is_mutable(full_mask, data_type, value_allocator); + BLI_assert(value_ != nullptr); switch (value_->type) { case ValueType::Span: { @@ -497,6 +494,7 @@ class VariableState : NonCopyable, NonMovable { /* Sanity check to make sure that enough values are not initialized. */ BLI_assert(mask.size() <= full_mask.size() - tot_initialized_); this->ensure_is_mutable(full_mask, data_type, value_allocator); + BLI_assert(value_ != nullptr); switch (value_->type) { case ValueType::Span: { @@ -524,6 +522,7 @@ class VariableState : NonCopyable, NonMovable { void add_as_input__one(MFParamsBuilder ¶ms, const MFDataType &data_type) const { BLI_assert(this->is_one()); + BLI_assert(value_ != nullptr); switch (value_->type) { case ValueType::GVArray: { @@ -556,7 +555,7 @@ class VariableState : NonCopyable, NonMovable { void ensure_is_mutable__one(const MFDataType &data_type, ValueAllocator &value_allocator) { BLI_assert(this->is_one()); - if (ELEM(value_->type, ValueType::OneSingle, ValueType::OneVector)) { + if (value_ != nullptr && ELEM(value_->type, ValueType::OneSingle, ValueType::OneVector)) { return; } @@ -564,38 +563,42 @@ class VariableState : NonCopyable, NonMovable { case MFDataType::Single: { const CPPType &type = data_type.single_type(); VariableValue_OneSingle *new_value = value_allocator.obtain_OneSingle(type); - if (value_->type == ValueType::GVArray) { - this->value_as<VariableValue_GVArray>()->data.get_internal_single_to_uninitialized( - new_value->data); - new_value->is_initialized = true; - } - else if (value_->type == ValueType::Span) { - BLI_assert(tot_initialized_ == 0); - /* Nothing to do, the single value is uninitialized already. */ - } - else { - BLI_assert_unreachable(); + if (value_ != nullptr) { + if (value_->type == ValueType::GVArray) { + this->value_as<VariableValue_GVArray>()->data.get_internal_single_to_uninitialized( + new_value->data); + new_value->is_initialized = true; + } + else if (value_->type == ValueType::Span) { + BLI_assert(tot_initialized_ == 0); + /* Nothing to do, the single value is uninitialized already. */ + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); } - value_allocator.release_value(value_, data_type); value_ = new_value; break; } case MFDataType::Vector: { const CPPType &type = data_type.vector_base_type(); VariableValue_OneVector *new_value = value_allocator.obtain_OneVector(type); - if (value_->type == ValueType::GVVectorArray) { - const GVVectorArray &old_vector_array = - this->value_as<VariableValue_GVVectorArray>()->data; - new_value->data.extend(IndexRange(1), old_vector_array); - } - else if (value_->type == ValueType::GVectorArray) { - BLI_assert(tot_initialized_ == 0); - /* Nothing to do. */ - } - else { - BLI_assert_unreachable(); + if (value_ != nullptr) { + if (value_->type == ValueType::GVVectorArray) { + const GVVectorArray &old_vector_array = + this->value_as<VariableValue_GVVectorArray>()->data; + new_value->data.extend(IndexRange(1), old_vector_array); + } + else if (value_->type == ValueType::GVectorArray) { + BLI_assert(tot_initialized_ == 0); + /* Nothing to do. */ + } + else { + BLI_assert_unreachable(); + } + value_allocator.release_value(value_, data_type); } - value_allocator.release_value(value_, data_type); value_ = new_value; break; } @@ -608,6 +611,7 @@ class VariableState : NonCopyable, NonMovable { { BLI_assert(this->is_one()); this->ensure_is_mutable__one(data_type, value_allocator); + BLI_assert(value_ != nullptr); switch (value_->type) { case ValueType::OneSingle: { @@ -637,6 +641,7 @@ class VariableState : NonCopyable, NonMovable { { BLI_assert(this->is_one()); this->ensure_is_mutable__one(data_type, value_allocator); + BLI_assert(value_ != nullptr); switch (value_->type) { case ValueType::OneSingle: { @@ -676,6 +681,7 @@ class VariableState : NonCopyable, NonMovable { const MFDataType &data_type, ValueAllocator &value_allocator) { + BLI_assert(value_ != nullptr); int new_tot_initialized = tot_initialized_ - mask.size(); /* Sanity check to make sure that enough indices can be destructed. */ @@ -743,6 +749,7 @@ class VariableState : NonCopyable, NonMovable { void indices_split(IndexMask mask, IndicesSplitVectors &r_indices) { BLI_assert(mask.size() <= tot_initialized_); + BLI_assert(value_ != nullptr); switch (value_->type) { case ValueType::GVArray: { @@ -778,51 +785,47 @@ class VariableState : NonCopyable, NonMovable { template<typename T> T *value_as() { + BLI_assert(value_ != nullptr); BLI_assert(value_->type == T::static_type); return static_cast<T *>(value_); } template<typename T> const T *value_as() const { + BLI_assert(value_ != nullptr); BLI_assert(value_->type == T::static_type); return static_cast<T *>(value_); } }; -template<typename... Args> VariableState *ValueAllocator::obtain_variable_state(Args &&...args) -{ - if (variable_state_free_list_.is_empty()) { - void *buffer = linear_allocator_.allocate(sizeof(VariableState), alignof(VariableState)); - return new (buffer) VariableState(std::forward<Args>(args)...); - } - return new (variable_state_free_list_.pop()) VariableState(std::forward<Args>(args)...); -} - -void ValueAllocator::release_variable_state(VariableState *state) -{ - state->~VariableState(); - variable_state_free_list_.push(state); -} - /** Keeps track of the states of all variables during evaluation. */ class VariableStates { private: ValueAllocator value_allocator_; - Map<const MFVariable *, VariableState *> variable_states_; + const MFProcedure &procedure_; + /** The state of every variable, indexed by #MFVariable::index_in_procedure(). */ + Array<VariableState> variable_states_; IndexMask full_mask_; public: - VariableStates(LinearAllocator<> &linear_allocator, IndexMask full_mask) - : value_allocator_(linear_allocator), full_mask_(full_mask) + VariableStates(LinearAllocator<> &linear_allocator, + const MFProcedure &procedure, + IndexMask full_mask) + : value_allocator_(linear_allocator), + procedure_(procedure), + variable_states_(procedure.variables().size()), + full_mask_(full_mask) { } ~VariableStates() { - for (auto &&item : variable_states_.items()) { - const MFVariable *variable = item.key; - VariableState *state = item.value; - state->destruct_self(value_allocator_, variable->data_type()); + for (const int variable_i : procedure_.variables().index_range()) { + VariableState &state = variable_states_[variable_i]; + if (state.value_ != nullptr) { + const MFVariable *variable = procedure_.variables()[variable_i]; + state.destruct_value(value_allocator_, variable->data_type()); + } } } @@ -848,9 +851,12 @@ class VariableStates { bool input_is_initialized, void *caller_provided_storage = nullptr) { const int tot_initialized = input_is_initialized ? full_mask_.size() : 0; - variable_states_.add_new(variable, - value_allocator_.obtain_variable_state( - *value, tot_initialized, caller_provided_storage)); + const int variable_i = variable->index_in_procedure(); + VariableState &variable_state = variable_states_[variable_i]; + BLI_assert(variable_state.value_ == nullptr); + variable_state.value_ = value; + variable_state.tot_initialized_ = tot_initialized; + variable_state.caller_provided_storage_ = caller_provided_storage; }; switch (param_type.category()) { @@ -936,32 +942,15 @@ class VariableStates { { VariableState &variable_state = this->get_variable_state(variable); if (variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_)) { - variable_state.destruct_self(value_allocator_, variable.data_type()); - variable_states_.remove_contained(&variable); + variable_state.destruct_value(value_allocator_, variable.data_type()); } } VariableState &get_variable_state(const MFVariable &variable) { - return *variable_states_.lookup_or_add_cb( - &variable, [&]() { return this->create_new_state_for_variable(variable); }); - } - - VariableState *create_new_state_for_variable(const MFVariable &variable) - { - MFDataType data_type = variable.data_type(); - switch (data_type.category()) { - case MFDataType::Single: { - const CPPType &type = data_type.single_type(); - return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneSingle(type), 0); - } - case MFDataType::Vector: { - const CPPType &type = data_type.vector_base_type(); - return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneVector(type), 0); - } - } - BLI_assert_unreachable(); - return nullptr; + const int variable_i = variable.index_in_procedure(); + VariableState &variable_state = variable_states_[variable_i]; + return variable_state; } }; @@ -977,49 +966,82 @@ static bool evaluate_as_one(const MultiFunction &fn, return false; } for (VariableState *state : param_variable_states) { - if (state != nullptr && !state->is_one()) { + if (state != nullptr && state->value_ != nullptr && !state->is_one()) { return false; } } return true; } -static void execute_call_instruction(const MFCallInstruction &instruction, - IndexMask mask, - VariableStates &variable_states, - const MFContext &context) +static void gather_parameter_variable_states(const MultiFunction &fn, + const MFCallInstruction &instruction, + VariableStates &variable_states, + MutableSpan<VariableState *> r_param_variable_states) { - const MultiFunction &fn = instruction.fn(); - - Vector<VariableState *> param_variable_states; - param_variable_states.resize(fn.param_amount()); - for (const int param_index : fn.param_indices()) { const MFVariable *variable = instruction.params()[param_index]; if (variable == nullptr) { - param_variable_states[param_index] = nullptr; + r_param_variable_states[param_index] = nullptr; } else { VariableState &variable_state = variable_states.get_variable_state(*variable); - param_variable_states[param_index] = &variable_state; + r_param_variable_states[param_index] = &variable_state; + } + } +} + +static void fill_params__one(const MultiFunction &fn, + const IndexMask mask, + MFParamsBuilder ¶ms, + VariableStates &variable_states, + const Span<VariableState *> param_variable_states) +{ + for (const int param_index : fn.param_indices()) { + const MFParamType param_type = fn.param_type(param_index); + VariableState *variable_state = param_variable_states[param_index]; + if (variable_state == nullptr) { + params.add_ignored_single_output(); + } + else { + variable_states.add_as_param__one(*variable_state, params, param_type, mask); } } +} + +static void fill_params(const MultiFunction &fn, + const IndexMask mask, + MFParamsBuilder ¶ms, + VariableStates &variable_states, + const Span<VariableState *> param_variable_states) +{ + for (const int param_index : fn.param_indices()) { + const MFParamType param_type = fn.param_type(param_index); + VariableState *variable_state = param_variable_states[param_index]; + if (variable_state == nullptr) { + params.add_ignored_single_output(); + } + else { + variable_states.add_as_param(*variable_state, params, param_type, mask); + } + } +} + +static void execute_call_instruction(const MFCallInstruction &instruction, + const IndexMask mask, + VariableStates &variable_states, + const MFContext &context) +{ + const MultiFunction &fn = instruction.fn(); + + Vector<VariableState *> param_variable_states; + param_variable_states.resize(fn.param_amount()); + gather_parameter_variable_states(fn, instruction, variable_states, param_variable_states); /* If all inputs to the function are constant, it's enough to call the function only once instead * of for every index. */ if (evaluate_as_one(fn, param_variable_states, mask, variable_states.full_mask())) { MFParamsBuilder params(fn, 1); - - for (const int param_index : fn.param_indices()) { - const MFParamType param_type = fn.param_type(param_index); - VariableState *variable_state = param_variable_states[param_index]; - if (variable_state == nullptr) { - params.add_ignored_single_output(); - } - else { - variable_states.add_as_param__one(*variable_state, params, param_type, mask); - } - } + fill_params__one(fn, mask, params, variable_states, param_variable_states); try { fn.call(IndexRange(1), params, context); @@ -1031,17 +1053,7 @@ static void execute_call_instruction(const MFCallInstruction &instruction, } else { MFParamsBuilder params(fn, &mask); - - for (const int param_index : fn.param_indices()) { - const MFParamType param_type = fn.param_type(param_index); - VariableState *variable_state = param_variable_states[param_index]; - if (variable_state == nullptr) { - params.add_ignored_single_output(); - } - else { - variable_states.add_as_param(*variable_state, params, param_type, mask); - } - } + fill_params(fn, mask, params, variable_states, param_variable_states); try { fn.call_auto(mask, params, context); @@ -1090,7 +1102,7 @@ struct NextInstructionInfo { */ class InstructionScheduler { private: - Map<const MFInstruction *, Vector<InstructionIndices>> indices_by_instruction_; + Stack<NextInstructionInfo> next_instructions_; public: InstructionScheduler() = default; @@ -1103,7 +1115,7 @@ class InstructionScheduler { InstructionIndices new_indices; new_indices.is_owned = false; new_indices.referenced_indices = mask; - indices_by_instruction_.lookup_or_add_default(&instruction).append(std::move(new_indices)); + next_instructions_.push({&instruction, std::move(new_indices)}); } void add_owned_indices(const MFInstruction &instruction, Vector<int64_t> indices) @@ -1116,43 +1128,28 @@ class InstructionScheduler { InstructionIndices new_indices; new_indices.is_owned = true; new_indices.owned_indices = std::move(indices); - indices_by_instruction_.lookup_or_add_default(&instruction).append(std::move(new_indices)); + next_instructions_.push({&instruction, std::move(new_indices)}); } - void add_previous_instruction_indices(const MFInstruction &instruction, - NextInstructionInfo &instr_info) + bool is_done() const { - indices_by_instruction_.lookup_or_add_default(&instruction) - .append(std::move(instr_info.indices)); + return next_instructions_.is_empty(); } - NextInstructionInfo pop_next() + const NextInstructionInfo &peek() const { - if (indices_by_instruction_.is_empty()) { - return {}; - } - /* TODO: Implement better mechanism to determine next instruction. */ - const MFInstruction *instruction = *indices_by_instruction_.keys().begin(); + BLI_assert(!this->is_done()); + return next_instructions_.peek(); + } - NextInstructionInfo next_instruction_info; - next_instruction_info.instruction = instruction; - next_instruction_info.indices = this->pop_indices_array(instruction); - return next_instruction_info; + void update_instruction_pointer(const MFInstruction &instruction) + { + next_instructions_.peek().instruction = &instruction; } - private: - InstructionIndices pop_indices_array(const MFInstruction *instruction) + NextInstructionInfo pop() { - Vector<InstructionIndices> *indices = indices_by_instruction_.lookup_ptr(instruction); - if (indices == nullptr) { - return {}; - } - InstructionIndices r_indices = (*indices).pop_last(); - BLI_assert(!r_indices.mask().is_empty()); - if (indices->is_empty()) { - indices_by_instruction_.remove_contained(instruction); - } - return r_indices; + return next_instructions_.pop(); } }; @@ -1160,23 +1157,26 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c { BLI_assert(procedure_.validate()); + AlignedBuffer<512, 64> local_buffer; LinearAllocator<> linear_allocator; + linear_allocator.provide_buffer(local_buffer); - VariableStates variable_states{linear_allocator, full_mask}; + VariableStates variable_states{linear_allocator, procedure_, full_mask}; variable_states.add_initial_variable_states(*this, procedure_, params); InstructionScheduler scheduler; scheduler.add_referenced_indices(*procedure_.entry(), full_mask); /* Loop until all indices got to a return instruction. */ - while (NextInstructionInfo instr_info = scheduler.pop_next()) { + while (!scheduler.is_done()) { + const NextInstructionInfo &instr_info = scheduler.peek(); const MFInstruction &instruction = *instr_info.instruction; switch (instruction.type()) { case MFInstructionType::Call: { const MFCallInstruction &call_instruction = static_cast<const MFCallInstruction &>( instruction); execute_call_instruction(call_instruction, instr_info.mask(), variable_states, context); - scheduler.add_previous_instruction_indices(*call_instruction.next(), instr_info); + scheduler.update_instruction_pointer(*call_instruction.next()); break; } case MFInstructionType::Branch: { @@ -1187,6 +1187,7 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c IndicesSplitVectors new_indices; variable_state.indices_split(instr_info.mask(), new_indices); + scheduler.pop(); scheduler.add_owned_indices(*branch_instruction.branch_false(), new_indices[false]); scheduler.add_owned_indices(*branch_instruction.branch_true(), new_indices[true]); break; @@ -1196,17 +1197,18 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c static_cast<const MFDestructInstruction &>(instruction); const MFVariable *variable = destruct_instruction.variable(); variable_states.destruct(*variable, instr_info.mask()); - scheduler.add_previous_instruction_indices(*destruct_instruction.next(), instr_info); + scheduler.update_instruction_pointer(*destruct_instruction.next()); break; } case MFInstructionType::Dummy: { const MFDummyInstruction &dummy_instruction = static_cast<const MFDummyInstruction &>( instruction); - scheduler.add_previous_instruction_indices(*dummy_instruction.next(), instr_info); + scheduler.update_instruction_pointer(*dummy_instruction.next()); break; } case MFInstructionType::Return: { /* Don't insert the indices back into the scheduler. */ + scheduler.pop(); break; } } diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt index 010c327d482..531487a45e2 100644 --- a/source/blender/geometry/CMakeLists.txt +++ b/source/blender/geometry/CMakeLists.txt @@ -15,20 +15,24 @@ set(INC ) set(SRC + intern/add_curves_on_mesh.cc intern/mesh_merge_by_distance.cc intern/mesh_primitive_cuboid.cc intern/mesh_to_curve_convert.cc intern/point_merge_by_distance.cc intern/realize_instances.cc intern/resample_curves.cc + intern/reverse_uv_sampler.cc intern/uv_parametrizer.c + GEO_add_curves_on_mesh.hh GEO_mesh_merge_by_distance.hh GEO_mesh_primitive_cuboid.hh GEO_mesh_to_curve.hh GEO_point_merge_by_distance.hh GEO_realize_instances.hh GEO_resample_curves.hh + GEO_reverse_uv_sampler.hh GEO_uv_parametrizer.h ) diff --git a/source/blender/geometry/GEO_add_curves_on_mesh.hh b/source/blender/geometry/GEO_add_curves_on_mesh.hh new file mode 100644 index 00000000000..cf60a8e8ace --- /dev/null +++ b/source/blender/geometry/GEO_add_curves_on_mesh.hh @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "BLI_float4x4.hh" +#include "BLI_kdtree.h" +#include "BLI_math_vector.hh" +#include "BLI_span.hh" + +#include "BKE_bvhutils.h" +#include "BKE_curves.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +namespace blender::geometry { + +struct AddCurvesOnMeshInputs { + /** Information about the root points where new curves should be generated. */ + Span<float3> root_positions_cu; + Span<float3> bary_coords; + Span<int> looptri_indices; + + /** Determines shape of new curves. */ + bool interpolate_length = false; + bool interpolate_shape = false; + bool interpolate_point_count = false; + float fallback_curve_length = 0.0f; + int fallback_point_count = 0; + + /** Information about the surface that the new curves are attached to. */ + const Mesh *surface = nullptr; + BVHTreeFromMesh *surface_bvh = nullptr; + Span<MLoopTri> surface_looptris; + Span<float2> surface_uv_map; + Span<float3> corner_normals_su; + + /** Transformation matrices. */ + float4x4 curves_to_surface_mat; + float4x4 surface_to_curves_normal_mat; + + /** + * KD-Tree that contains the root points of existing curves. This is only necessary when + * interpolation is used. + */ + KDTree_3d *old_roots_kdtree = nullptr; +}; + +/** + * Generate new curves on a mesh surface with the given inputs. Existing curves stay intact. + */ +void add_curves_on_mesh(bke::CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs); + +} // namespace blender::geometry diff --git a/source/blender/geometry/GEO_reverse_uv_sampler.hh b/source/blender/geometry/GEO_reverse_uv_sampler.hh new file mode 100644 index 00000000000..d392b65eaf4 --- /dev/null +++ b/source/blender/geometry/GEO_reverse_uv_sampler.hh @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include <optional> + +#include "BLI_math_vector.hh" +#include "BLI_span.hh" + +#include "DNA_meshdata_types.h" + +namespace blender::geometry { + +/** + * Can find the polygon/triangle that maps to a specific uv coordinate. + * + * \note this uses a trivial implementation currently that has to be replaced. + */ +class ReverseUVSampler { + private: + const Span<float2> uv_map_; + const Span<MLoopTri> looptris_; + + public: + ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris); + + enum class ResultType { + None, + Ok, + Multiple, + }; + + struct Result { + ResultType type = ResultType::None; + const MLoopTri *looptri = nullptr; + float3 bary_weights; + }; + + Result sample(const float2 &query_uv) const; +}; + +} // namespace blender::geometry diff --git a/source/blender/geometry/GEO_uv_parametrizer.h b/source/blender/geometry/GEO_uv_parametrizer.h index 624b0695aa3..2181f95945e 100644 --- a/source/blender/geometry/GEO_uv_parametrizer.h +++ b/source/blender/geometry/GEO_uv_parametrizer.h @@ -14,10 +14,7 @@ extern "C" { typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */ typedef intptr_t ParamKey; /* Key (hash) for identifying verts and faces. */ -typedef enum ParamBool { - PARAM_TRUE = 1, - PARAM_FALSE = 0, -} ParamBool; +#define PARAM_KEY_MAX INTPTR_MAX /* -------------------------------------------------------------------- */ /** \name Chart Construction: @@ -38,20 +35,24 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void); void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy); +void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]); + +ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]); + void GEO_uv_parametrizer_face_add(ParamHandle *handle, - ParamKey key, - int nverts, - ParamKey *vkeys, - float *co[4], - float *uv[4], - ParamBool *pin, - ParamBool *select); + const ParamKey key, + const int nverts, + const ParamKey *vkeys, + const float **co, + float **uv, /* Output will eventually be written to `uv`. */ + const bool *pin, + const bool *select); void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys); void GEO_uv_parametrizer_construct_end(ParamHandle *handle, - ParamBool fill, - ParamBool topology_from_uvs, + bool fill, + bool topology_from_uvs, int *count_fail); void GEO_uv_parametrizer_delete(ParamHandle *handle); @@ -70,7 +71,7 @@ void GEO_uv_parametrizer_delete(ParamHandle *handle); * * \{ */ -void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf); +void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf); void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed); void GEO_uv_parametrizer_lscm_end(ParamHandle *handle); @@ -88,14 +89,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *handle); /** \} */ /* -------------------------------------------------------------------- */ -/** \name Area Smooth - * \{ */ - -void GEO_uv_parametrizer_smooth_area(ParamHandle *handle); - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Packing * \{ */ diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc new file mode 100644 index 00000000000..34551bd474f --- /dev/null +++ b/source/blender/geometry/intern/add_curves_on_mesh.cc @@ -0,0 +1,354 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_mesh_sample.hh" +#include "BKE_spline.hh" + +#include "GEO_add_curves_on_mesh.hh" + +/** + * The code below uses a suffix naming convention to indicate the coordinate space: + * cu: Local space of the curves object that is being edited. + * su: Local space of the surface object. + */ + +namespace blender::geometry { + +using bke::CurvesGeometry; + +struct NeighborCurve { + /* Curve index of the neighbor. */ + int index; + /* The weights of all neighbors of a new curve add up to 1. */ + float weight; +}; + +static constexpr int max_neighbors = 5; +using NeighborCurves = Vector<NeighborCurve, max_neighbors>; + +static float3 compute_surface_point_normal(const MLoopTri &looptri, + const float3 &bary_coord, + const Span<float3> corner_normals) +{ + const int l0 = looptri.tri[0]; + const int l1 = looptri.tri[1]; + const int l2 = looptri.tri[2]; + + const float3 &l0_normal = corner_normals[l0]; + const float3 &l1_normal = corner_normals[l1]; + const float3 &l2_normal = corner_normals[l2]; + + const float3 normal = math::normalize( + attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal)); + return normal; +} + +static void initialize_straight_curve_positions(const float3 &p1, + const float3 &p2, + MutableSpan<float3> r_positions) +{ + const float step = 1.0f / (float)(r_positions.size() - 1); + for (const int i : r_positions.index_range()) { + r_positions[i] = math::interpolate(p1, p2, i * step); + } +} + +static Array<NeighborCurves> find_curve_neighbors(const Span<float3> root_positions, + const KDTree_3d &old_roots_kdtree) +{ + const int tot_added_curves = root_positions.size(); + Array<NeighborCurves> neighbors_per_curve(tot_added_curves); + threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) { + for (const int i : range) { + const float3 root = root_positions[i]; + std::array<KDTreeNearest_3d, max_neighbors> nearest_n; + const int found_neighbors = BLI_kdtree_3d_find_nearest_n( + &old_roots_kdtree, root, nearest_n.data(), max_neighbors); + float tot_weight = 0.0f; + for (const int neighbor_i : IndexRange(found_neighbors)) { + KDTreeNearest_3d &nearest = nearest_n[neighbor_i]; + const float weight = 1.0f / std::max(nearest.dist, 0.00001f); + tot_weight += weight; + neighbors_per_curve[i].append({nearest.index, weight}); + } + /* Normalize weights. */ + for (NeighborCurve &neighbor : neighbors_per_curve[i]) { + neighbor.weight /= tot_weight; + } + } + }); + return neighbors_per_curve; +} + +template<typename T, typename GetValueF> +void interpolate_from_neighbors(const Span<NeighborCurves> neighbors_per_curve, + const T &fallback, + const GetValueF &get_value_from_neighbor, + MutableSpan<T> r_interpolated_values) +{ + attribute_math::DefaultMixer<T> mixer{r_interpolated_values}; + threading::parallel_for(r_interpolated_values.index_range(), 512, [&](const IndexRange range) { + for (const int i : range) { + const NeighborCurves &neighbors = neighbors_per_curve[i]; + if (neighbors.is_empty()) { + mixer.mix_in(i, fallback, 1.0f); + } + else { + for (const NeighborCurve &neighbor : neighbors) { + const T neighbor_value = get_value_from_neighbor(neighbor.index); + mixer.mix_in(i, neighbor_value, neighbor.weight); + } + } + } + }); + mixer.finalize(); +} + +static void interpolate_position_without_interpolation( + CurvesGeometry &curves, + const int old_curves_num, + const Span<float3> root_positions_cu, + const Span<float> new_lengths_cu, + const Span<float3> new_normals_su, + const float4x4 &surface_to_curves_normal_mat) +{ + const int added_curves_num = root_positions_cu.size(); + MutableSpan<float3> positions_cu = curves.positions_for_write(); + threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) { + for (const int i : range) { + const int curve_i = old_curves_num + i; + const IndexRange points = curves.points_for_curve(curve_i); + const float3 &root_cu = root_positions_cu[i]; + const float length = new_lengths_cu[i]; + const float3 &normal_su = new_normals_su[i]; + const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su); + const float3 tip_cu = root_cu + length * normal_cu; + + initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points)); + } + }); +} + +static void interpolate_position_with_interpolation(CurvesGeometry &curves, + const Span<float3> root_positions_cu, + const Span<NeighborCurves> neighbors_per_curve, + const int old_curves_num, + const Span<float> new_lengths_cu, + const Span<float3> new_normals_su, + const float4x4 &surface_to_curves_normal_mat, + const float4x4 &curves_to_surface_mat, + const BVHTreeFromMesh &surface_bvh, + const Span<MLoopTri> surface_looptris, + const Mesh &surface, + const Span<float3> corner_normals_su) +{ + MutableSpan<float3> positions_cu = curves.positions_for_write(); + const int added_curves_num = root_positions_cu.size(); + + threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) { + for (const int i : range) { + const NeighborCurves &neighbors = neighbors_per_curve[i]; + const int curve_i = old_curves_num + i; + const IndexRange points = curves.points_for_curve(curve_i); + + const float length_cu = new_lengths_cu[i]; + const float3 &normal_su = new_normals_su[i]; + const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su); + + const float3 &root_cu = root_positions_cu[i]; + + if (neighbors.is_empty()) { + /* If there are no neighbors, just make a straight line. */ + const float3 tip_cu = root_cu + length_cu * normal_cu; + initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points)); + continue; + } + + positions_cu.slice(points).fill(root_cu); + + for (const NeighborCurve &neighbor : neighbors) { + const int neighbor_curve_i = neighbor.index; + const float3 &neighbor_first_pos_cu = positions_cu[curves.offsets()[neighbor_curve_i]]; + const float3 neighbor_first_pos_su = curves_to_surface_mat * neighbor_first_pos_cu; + + BVHTreeNearest nearest; + nearest.dist_sq = FLT_MAX; + BLI_bvhtree_find_nearest(surface_bvh.tree, + neighbor_first_pos_su, + &nearest, + surface_bvh.nearest_callback, + const_cast<BVHTreeFromMesh *>(&surface_bvh)); + const int neighbor_looptri_index = nearest.index; + const MLoopTri &neighbor_looptri = surface_looptris[neighbor_looptri_index]; + + const float3 neighbor_bary_coord = + bke::mesh_surface_sample::compute_bary_coord_in_triangle( + surface, neighbor_looptri, nearest.co); + + const float3 neighbor_normal_su = compute_surface_point_normal( + surface_looptris[neighbor_looptri_index], neighbor_bary_coord, corner_normals_su); + const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat * + neighbor_normal_su); + + /* The rotation matrix used to transform relative coordinates of the neighbor curve + * to the new curve. */ + float normal_rotation_cu[3][3]; + rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu); + + const IndexRange neighbor_points = curves.points_for_curve(neighbor_curve_i); + const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]]; + + /* Use a temporary #PolySpline, because that's the easiest way to resample an + * existing curve right now. Resampling is necessary if the length of the new curve + * does not match the length of the neighbors or the number of handle points is + * different. */ + PolySpline neighbor_spline; + neighbor_spline.resize(neighbor_points.size()); + neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points)); + neighbor_spline.mark_cache_invalid(); + + const float neighbor_length_cu = neighbor_spline.length(); + const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu); + + const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor; + for (const int j : IndexRange(points.size())) { + const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor( + j * resample_factor); + const float index_factor = lookup.evaluated_index + lookup.factor; + float3 p; + neighbor_spline.sample_with_index_factors<float3>( + neighbor_spline.positions(), {&index_factor, 1}, {&p, 1}); + const float3 relative_coord = p - neighbor_root_cu; + float3 rotated_relative_coord = relative_coord; + mul_m3_v3(normal_rotation_cu, rotated_relative_coord); + positions_cu[points[j]] += neighbor.weight * rotated_relative_coord; + } + } + } + }); +} + +void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs) +{ + const bool use_interpolation = inputs.interpolate_length || inputs.interpolate_point_count || + inputs.interpolate_shape; + + Array<NeighborCurves> neighbors_per_curve; + if (use_interpolation) { + BLI_assert(inputs.old_roots_kdtree != nullptr); + neighbors_per_curve = find_curve_neighbors(inputs.root_positions_cu, *inputs.old_roots_kdtree); + } + + const int added_curves_num = inputs.root_positions_cu.size(); + const int old_points_num = curves.points_num(); + const int old_curves_num = curves.curves_num(); + const int new_curves_num = old_curves_num + added_curves_num; + + /* Grow number of curves first, so that the offsets array can be filled. */ + curves.resize(old_points_num, new_curves_num); + + /* Compute new curve offsets. */ + MutableSpan<int> curve_offsets = curves.offsets_for_write(); + MutableSpan<int> new_point_counts_per_curve = curve_offsets.take_back(added_curves_num); + if (inputs.interpolate_point_count) { + interpolate_from_neighbors<int>( + neighbors_per_curve, + inputs.fallback_point_count, + [&](const int curve_i) { return curves.points_for_curve(curve_i).size(); }, + new_point_counts_per_curve); + } + else { + new_point_counts_per_curve.fill(inputs.fallback_point_count); + } + for (const int i : IndexRange(added_curves_num)) { + curve_offsets[old_curves_num + i + 1] += curve_offsets[old_curves_num + i]; + } + + const int new_points_num = curves.offsets().last(); + curves.resize(new_points_num, new_curves_num); + MutableSpan<float3> positions_cu = curves.positions_for_write(); + + /* Determine length of new curves. */ + Array<float> new_lengths_cu(added_curves_num); + if (inputs.interpolate_length) { + interpolate_from_neighbors<float>( + neighbors_per_curve, + inputs.fallback_curve_length, + [&](const int curve_i) { + const IndexRange points = curves.points_for_curve(curve_i); + float length = 0.0f; + for (const int segment_i : points.drop_back(1)) { + const float3 &p1 = positions_cu[segment_i]; + const float3 &p2 = positions_cu[segment_i + 1]; + length += math::distance(p1, p2); + } + return length; + }, + new_lengths_cu); + } + else { + new_lengths_cu.fill(inputs.fallback_curve_length); + } + + /* Find surface normal at root points. */ + Array<float3> new_normals_su(added_curves_num); + threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) { + for (const int i : range) { + const int looptri_index = inputs.looptri_indices[i]; + const float3 &bary_coord = inputs.bary_coords[i]; + new_normals_su[i] = compute_surface_point_normal( + inputs.surface_looptris[looptri_index], bary_coord, inputs.corner_normals_su); + } + }); + + /* Propagate attachment information. */ + if (!inputs.surface_uv_map.is_empty()) { + MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write(); + bke::mesh_surface_sample::sample_corner_attribute( + *inputs.surface, + inputs.looptri_indices, + inputs.bary_coords, + GVArray::ForSpan(inputs.surface_uv_map), + IndexRange(added_curves_num), + surface_uv_coords.take_back(added_curves_num)); + } + + /* Update selection arrays when available. */ + const VArray<float> points_selection = curves.selection_point_float(); + if (points_selection.is_span()) { + MutableSpan<float> points_selection_span = curves.selection_point_float_for_write(); + points_selection_span.drop_front(old_points_num).fill(1.0f); + } + const VArray<float> curves_selection = curves.selection_curve_float(); + if (curves_selection.is_span()) { + MutableSpan<float> curves_selection_span = curves.selection_curve_float_for_write(); + curves_selection_span.drop_front(old_curves_num).fill(1.0f); + } + + /* Initialize position attribute. */ + if (inputs.interpolate_shape) { + interpolate_position_with_interpolation(curves, + inputs.root_positions_cu, + neighbors_per_curve, + old_curves_num, + new_lengths_cu, + new_normals_su, + inputs.surface_to_curves_normal_mat, + inputs.curves_to_surface_mat, + *inputs.surface_bvh, + inputs.surface_looptris, + *inputs.surface, + inputs.corner_normals_su); + } + else { + interpolate_position_without_interpolation(curves, + old_curves_num, + inputs.root_positions_cu, + new_lengths_cu, + new_normals_su, + inputs.surface_to_curves_normal_mat); + } + + curves.update_curve_types(); +} + +} // namespace blender::geometry diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index ae07e817c67..bd4099d37f9 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -134,6 +134,12 @@ struct RealizeCurveInfo { * doesn't exist on some (but not all) of the input curves data-blocks. */ Span<float> radius; + + /** + * The resolution attribute must be filled with the default value if it does not exist on some + * curves. + */ + VArray<int> resolution; }; /** Start indices in the final output curves data-block. */ @@ -185,6 +191,7 @@ struct AllCurvesInfo { bool create_id_attribute = false; bool create_handle_postion_attributes = false; bool create_radius_attribute = false; + bool create_resolution_attribute = false; }; /** Collects all tasks that need to be executed to realize all instances. */ @@ -279,12 +286,12 @@ static void copy_generic_attributes_to_result( const Span<std::optional<GVArray_GSpan>> src_attributes, const AttributeFallbacksArray &attribute_fallbacks, const OrderedAttributes &ordered_attributes, - const FunctionRef<IndexRange(AttributeDomain)> &range_fn, + const FunctionRef<IndexRange(eAttrDomain)> &range_fn, MutableSpan<GMutableSpan> dst_attributes) { threading::parallel_for(dst_attributes.index_range(), 10, [&](const IndexRange attribute_range) { for (const int attribute_index : attribute_range) { - const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain; + const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; const IndexRange element_slice = range_fn(domain); GMutableSpan dst_span = dst_attributes[attribute_index].slice(element_slice); @@ -363,7 +370,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks( return true; } GSpan span = *attributes.get_for_read(attribute_id); - const CustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type; + const eCustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type; if (meta_data.data_type != expected_type) { const CPPType &from_type = span.type(); const CPPType &to_type = *custom_data_type_to_cpp_type(expected_type); @@ -644,8 +651,8 @@ static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set pointcloud_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; - const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type; - const AttributeDomain domain = info.attributes.kinds[attribute_index].domain; + const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; + const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; if (component.attribute_exists(attribute_id)) { GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); pointcloud_info.attributes[attribute_index].emplace(std::move(attribute)); @@ -687,7 +694,7 @@ static void execute_realize_pointcloud_task(const RealizeInstancesOptions &optio pointcloud_info.attributes, task.attribute_fallbacks, ordered_attributes, - [&](const AttributeDomain domain) { + [&](const eAttrDomain domain) { BLI_assert(domain == ATTR_DOMAIN_POINT); UNUSED_VARS_NDEBUG(domain); return point_slice; @@ -728,7 +735,7 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti Vector<GMutableSpan> dst_attribute_spans; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; - const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; + const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); dst_attribute_spans.append(dst_attribute.as_span()); @@ -835,8 +842,8 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, mesh_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; - const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type; - const AttributeDomain domain = info.attributes.kinds[attribute_index].domain; + const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; + const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; if (component.attribute_exists(attribute_id)) { GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); mesh_info.attributes[attribute_index].emplace(std::move(attribute)); @@ -927,7 +934,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, mesh_info.attributes, task.attribute_fallbacks, ordered_attributes, - [&](const AttributeDomain domain) { + [&](const eAttrDomain domain) { switch (domain) { case ATTR_DOMAIN_POINT: return IndexRange(task.start_indices.vertex, mesh.totvert); @@ -991,8 +998,8 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, Vector<GMutableSpan> dst_attribute_spans; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; - const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain; - const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; + const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; + const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, domain, data_type); dst_attribute_spans.append(dst_attribute.as_span()); @@ -1037,6 +1044,7 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate( src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate); attributes_to_propagate.remove("position"); attributes_to_propagate.remove("radius"); + attributes_to_propagate.remove("resolution"); attributes_to_propagate.remove("handle_right"); attributes_to_propagate.remove("handle_left"); r_create_id = attributes_to_propagate.pop_try("id").has_value(); @@ -1075,17 +1083,18 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set, info.realize_info.reinitialize(info.order.size()); for (const int curve_index : info.realize_info.index_range()) { RealizeCurveInfo &curve_info = info.realize_info[curve_index]; - const Curves *curves = info.order[curve_index]; - curve_info.curves = curves; + const Curves *curves_id = info.order[curve_index]; + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); + curve_info.curves = curves_id; /* Access attributes. */ CurveComponent component; - component.replace(const_cast<Curves *>(curves), GeometryOwnershipType::ReadOnly); + component.replace(const_cast<Curves *>(curves_id), GeometryOwnershipType::ReadOnly); curve_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { - const AttributeDomain domain = info.attributes.kinds[attribute_index].domain; + const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; - const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type; + const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; if (component.attribute_exists(attribute_id)) { GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); curve_info.attributes[attribute_index].emplace(std::move(attribute)); @@ -1106,6 +1115,12 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set, info.create_radius_attribute = true; } + /* Retrieve the resolution attribute, if it exists. */ + curve_info.resolution = curves.resolution(); + if (component.attribute_exists("resolution")) { + info.create_resolution_attribute = true; + } + /* Retrieve handle position attributes, if they exist. */ if (component.attribute_exists("handle_right")) { curve_info.handle_left = component @@ -1131,7 +1146,8 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, MutableSpan<int> all_dst_ids, MutableSpan<float3> all_handle_left, MutableSpan<float3> all_handle_right, - MutableSpan<float> all_radii) + MutableSpan<float> all_radii, + MutableSpan<int> all_resolutions) { const RealizeCurveInfo &curves_info = *task.curve_info; const Curves &curves_id = *curves_info.curves; @@ -1171,6 +1187,10 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, } } + if (all_curves_info.create_resolution_attribute) { + curves_info.resolution.materialize(all_resolutions.slice(dst_curve_range)); + } + /* Copy curve offsets. */ const Span<int> src_offsets = curves.offsets(); const MutableSpan<int> dst_offsets = dst_curves.offsets_for_write().slice(dst_curve_range); @@ -1189,7 +1209,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, curves_info.attributes, task.attribute_fallbacks, ordered_attributes, - [&](const AttributeDomain domain) { + [&](const eAttrDomain domain) { switch (domain) { case ATTR_DOMAIN_POINT: return IndexRange(task.start_indices.point, curves.points_num()); @@ -1238,8 +1258,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, Vector<GMutableSpan> dst_attribute_spans; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; - const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain; - const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; + const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; + const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, domain, data_type); dst_attribute_spans.append(dst_attribute.as_span()); @@ -1268,6 +1288,15 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, radius_span = radius.as_span(); } + /* Prepare resolution attribute if necessary. */ + OutputAttribute_Typed<int> resolution; + MutableSpan<int> resolution_span; + if (all_curves_info.create_resolution_attribute) { + resolution = dst_component.attribute_try_get_for_output_only<int>("resolution", + ATTR_DOMAIN_CURVE); + resolution_span = resolution.as_span(); + } + /* Actually execute all tasks. */ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) { for (const int task_index : task_range) { @@ -1281,7 +1310,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, point_ids_span, handle_left_span, handle_right_span, - radius_span); + radius_span, + resolution_span); } }); @@ -1295,6 +1325,9 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, if (radius) { radius.save(); } + if (resolution) { + resolution.save(); + } if (all_curves_info.create_handle_postion_attributes) { handle_left.save(); handle_right.save(); diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc index 7895225a189..36525e1bdf0 100644 --- a/source/blender/geometry/intern/resample_curves.cc +++ b/source/blender/geometry/intern/resample_curves.cc @@ -99,7 +99,7 @@ static void retrieve_attribute_spans(const Span<bke::AttributeIDRef> ids, BLI_assert(src_attribute); src.append(src_attribute.get_internal_span()); - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type()); + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type()); bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( ids[i], ATTR_DOMAIN_POINT, data_type); dst.append(dst_attribute.as_span()); @@ -165,38 +165,6 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com dst_curves.update_customdata_pointers(); } -/** - * Copy the provided point attribute values between all curves in the #curve_ranges index - * ranges, assuming that all curves are the same size in #src_curves and #dst_curves. - */ -template<typename T> -static void copy_between_curves(const bke::CurvesGeometry &src_curves, - const bke::CurvesGeometry &dst_curves, - const Span<IndexRange> curve_ranges, - const Span<T> src, - const MutableSpan<T> dst) -{ - threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) { - for (const IndexRange range : curve_ranges.slice(range)) { - const IndexRange src_points = src_curves.points_for_curves(range); - const IndexRange dst_points = dst_curves.points_for_curves(range); - /* The arrays might be large, so a threaded copy might make sense here too. */ - dst.slice(dst_points).copy_from(src.slice(src_points)); - } - }); -} -static void copy_between_curves(const bke::CurvesGeometry &src_curves, - const bke::CurvesGeometry &dst_curves, - const Span<IndexRange> unselected_ranges, - const GSpan src, - const GMutableSpan dst) -{ - attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { - using T = decltype(dummy); - copy_between_curves(src_curves, dst_curves, unselected_ranges, src.typed<T>(), dst.typed<T>()); - }); -} - static Curves *resample_to_uniform(const CurveComponent &src_component, const fn::Field<bool> &selection_field, const fn::Field<int> &count_field) @@ -328,20 +296,21 @@ static Curves *resample_to_uniform(const CurveComponent &src_component, /* Any attribute data from unselected curve points can be directly copied. */ for (const int i : attributes.src.index_range()) { - copy_between_curves( + bke::curves::copy_point_data( src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } for (const int i : attributes.src_no_interpolation.index_range()) { - copy_between_curves(src_curves, - dst_curves, - unselected_ranges, - attributes.src_no_interpolation[i], - attributes.dst_no_interpolation[i]); + bke::curves::copy_point_data(src_curves, + dst_curves, + unselected_ranges, + attributes.src_no_interpolation[i], + attributes.dst_no_interpolation[i]); } /* Copy positions for unselected curves. */ Span<float3> src_positions = src_curves.positions(); - copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); + bke::curves::copy_point_data( + src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); for (bke::OutputAttribute &attribute : attributes.dst_attributes) { attribute.save(); @@ -449,20 +418,21 @@ Curves *resample_to_evaluated(const CurveComponent &src_component, /* Any attribute data from unselected curve points can be directly copied. */ for (const int i : attributes.src.index_range()) { - copy_between_curves( + bke::curves::copy_point_data( src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } for (const int i : attributes.src_no_interpolation.index_range()) { - copy_between_curves(src_curves, - dst_curves, - unselected_ranges, - attributes.src_no_interpolation[i], - attributes.dst_no_interpolation[i]); + bke::curves::copy_point_data(src_curves, + dst_curves, + unselected_ranges, + attributes.src_no_interpolation[i], + attributes.dst_no_interpolation[i]); } /* Copy positions for unselected curves. */ Span<float3> src_positions = src_curves.positions(); - copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); + bke::curves::copy_point_data( + src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); for (bke::OutputAttribute &attribute : attributes.dst_attributes) { attribute.save(); diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc new file mode 100644 index 00000000000..9aa98895a86 --- /dev/null +++ b/source/blender/geometry/intern/reverse_uv_sampler.cc @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "GEO_reverse_uv_sampler.hh" + +#include "BLI_math_geom.h" + +namespace blender::geometry { + +ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris) + : uv_map_(uv_map), looptris_(looptris) +{ +} + +ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const +{ + for (const MLoopTri &looptri : looptris_) { + const float2 &uv0 = uv_map_[looptri.tri[0]]; + const float2 &uv1 = uv_map_[looptri.tri[1]]; + const float2 &uv2 = uv_map_[looptri.tri[2]]; + float3 bary_weights; + if (!barycentric_coords_v2(uv0, uv1, uv2, query_uv, bary_weights)) { + continue; + } + if (IN_RANGE_INCL(bary_weights.x, 0.0f, 1.0f) && IN_RANGE_INCL(bary_weights.y, 0.0f, 1.0f) && + IN_RANGE_INCL(bary_weights.z, 0.0f, 1.0f)) { + return Result{ResultType::Ok, &looptri, bary_weights}; + } + } + return Result{}; +} + +} // namespace blender::geometry diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.c index ad4b051a6c2..8863b9192ca 100644 --- a/source/blender/geometry/intern/uv_parametrizer.c +++ b/source/blender/geometry/intern/uv_parametrizer.c @@ -4,26 +4,18 @@ * \ingroup eduv */ +#include "GEO_uv_parametrizer.h" + #include "MEM_guardedalloc.h" #include "BLI_boxpack_2d.h" #include "BLI_convexhull_2d.h" +#include "BLI_ghash.h" #include "BLI_heap.h" -#include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_polyfill_2d.h" #include "BLI_polyfill_2d_beautify.h" #include "BLI_rand.h" -#include "BLI_utildefines.h" - -#include "GEO_uv_parametrizer.h" - -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "BLI_sys_types.h" /* for intptr_t support */ #include "eigen_capi.h" @@ -36,11 +28,6 @@ #define param_warning(message) \ {/*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/}(void)0 -typedef enum PBool { - P_TRUE = 1, - P_FALSE = 0, -} PBool; - /* Special Purpose Hash */ typedef intptr_t PHashKey; @@ -56,11 +43,6 @@ typedef struct PHash { int size, cursize, cursize_id; } PHash; -struct PChart; -struct PEdge; -struct PFace; -struct PVert; - /* Simplices */ typedef struct PVert { @@ -195,6 +177,9 @@ typedef struct ParamHandle { PHash *hash_edges; PHash *hash_faces; + struct GHash *pin_hash; + int unique_pin_count; + PChart **charts; int ncharts; @@ -319,54 +304,14 @@ static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link) /* Geometry */ -static float p_vec_angle_cos(const float v1[3], const float v2[3], const float v3[3]) -{ - float d1[3], d2[3]; - - d1[0] = v1[0] - v2[0]; - d1[1] = v1[1] - v2[1]; - d1[2] = v1[2] - v2[2]; - - d2[0] = v3[0] - v2[0]; - d2[1] = v3[1] - v2[1]; - d2[2] = v3[2] - v2[2]; - - normalize_v3(d1); - normalize_v3(d2); - - return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2]; -} - static float p_vec_angle(const float v1[3], const float v2[3], const float v3[3]) { - float dot = p_vec_angle_cos(v1, v2, v3); - - if (dot <= -1.0f) { - return (float)M_PI; - } - if (dot >= 1.0f) { - return 0.0f; - } - return acosf(dot); + return angle_v3v3v3(v1, v2, v3); } - static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2]) { - float u1[3], u2[3], u3[3]; - - u1[0] = v1[0]; - u1[1] = v1[1]; - u1[2] = 0.0f; - u2[0] = v2[0]; - u2[1] = v2[1]; - u2[2] = 0.0f; - u3[0] = v3[0]; - u3[1] = v3[1]; - u3[2] = 0.0f; - - return p_vec_angle(u1, u2, u3); + return angle_v2v2v2(v1, v2, v3); } - static void p_triangle_angles( const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3) { @@ -407,25 +352,12 @@ static float p_face_uv_area_signed(PFace *f) static float p_edge_length(PEdge *e) { - PVert *v1 = e->vert, *v2 = e->next->vert; - float d[3]; - - d[0] = v2->co[0] - v1->co[0]; - d[1] = v2->co[1] - v1->co[1]; - d[2] = v2->co[2] - v1->co[2]; - - return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + return len_v3v3(e->vert->co, e->next->vert->co); } static float p_edge_uv_length(PEdge *e) { - PVert *v1 = e->vert, *v2 = e->next->vert; - float d[3]; - - d[0] = v2->uv[0] - v1->uv[0]; - d[1] = v2->uv[1] - v1->uv[1]; - - return sqrtf(d[0] * d[0] + d[1] * d[1]); + return len_v2v2(e->vert->uv, e->next->vert->uv); } static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2]) @@ -499,63 +431,26 @@ static void p_chart_uv_to_array(PChart *chart, float (*points)[2]) } } -static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2]) -{ - PVert *v; - uint i = 0; - - for (v = chart->verts; v; v = v->nextlink) { - copy_v2_v2(v->uv, points[i++]); - } -} - -static PBool p_intersect_line_2d_dir(const float v1[2], - const float dir1[2], - const float v2[2], - const float dir2[2], - float r_isect[2]) +static bool p_intersect_line_2d_dir(const float v1[2], + const float dir1[2], + const float v2[2], + const float dir2[2], + float r_isect[2]) { float lmbda, div; div = dir2[0] * dir1[1] - dir2[1] * dir1[0]; if (div == 0.0f) { - return P_FALSE; + return false; } lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div; r_isect[0] = v1[0] + lmbda * dir2[0]; r_isect[1] = v1[1] + lmbda * dir2[1]; - return P_TRUE; -} - -#if 0 -static PBool p_intersect_line_2d(const float v1[2], - const float v2[2], - const float v3[2], - const float v4[2], - const float r_isect[2]) -{ - float dir1[2], dir2[2]; - - dir1[0] = v4[0] - v3[0]; - dir1[1] = v4[1] - v3[1]; - - dir2[0] = v2[0] - v1[0]; - dir2[1] = v2[1] - v1[1]; - - if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) { - /* parallel - should never happen in theory for polygon kernel, but - * let's give a point nearby in case things go wrong */ - isect[0] = (v1[0] + v2[0]) * 0.5f; - isect[1] = (v1[1] + v2[1]) * 0.5f; - return P_FALSE; - } - - return P_TRUE; + return true; } -#endif /* Topological Utilities */ @@ -586,9 +481,9 @@ static PEdge *p_boundary_edge_prev(PEdge *e) return last->next->next; } -static PBool p_vert_interior(PVert *v) +static bool p_vert_interior(PVert *v) { - return (v->edge->pair != NULL); + return v->edge->pair; } static void p_face_flip(PFace *f) @@ -807,7 +702,7 @@ static PEdge *p_edge_lookup(ParamHandle *handle, const PHashKey *vkeys) return NULL; } -static int p_face_exists(ParamHandle *handle, ParamKey *pvkeys, int i1, int i2, int i3) +static int p_face_exists(ParamHandle *handle, const ParamKey *pvkeys, int i1, int i2, int i3) { PHashKey *vkeys = (PHashKey *)pvkeys; PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]); @@ -816,19 +711,19 @@ static int p_face_exists(ParamHandle *handle, ParamKey *pvkeys, int i1, int i2, while (e) { if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) { if (e->next->next->vert->u.key == vkeys[i3]) { - return P_TRUE; + return true; } } else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) { if (e->next->next->vert->u.key == vkeys[i3]) { - return P_TRUE; + return true; } } e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e); } - return P_FALSE; + return false; } static PChart *p_chart_new(ParamHandle *handle) @@ -845,7 +740,7 @@ static void p_chart_delete(PChart *chart) MEM_freeN(chart); } -static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep) +static bool p_edge_implicit_seam(PEdge *e, PEdge *ep) { float *uv1, *uv2, *uvp1, *uvp2; float limit[2]; @@ -868,21 +763,18 @@ static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep) if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) { e->flag |= PEDGE_SEAM; ep->flag |= PEDGE_SEAM; - return P_TRUE; + return true; } if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) { e->flag |= PEDGE_SEAM; ep->flag |= PEDGE_SEAM; - return P_TRUE; + return true; } - return P_FALSE; + return false; } -static PBool p_edge_has_pair(ParamHandle *handle, - PEdge *e, - PBool topology_from_uvs, - PEdge **r_pair) +static bool p_edge_has_pair(ParamHandle *handle, PEdge *e, bool topology_from_uvs, PEdge **r_pair) { PHashKey key; PEdge *pe; @@ -891,7 +783,7 @@ static PBool p_edge_has_pair(ParamHandle *handle, PHashKey key2 = e->next->vert->u.key; if (e->flag & PEDGE_SEAM) { - return P_FALSE; + return false; } key = PHASH_edge(key1, key2); @@ -910,7 +802,7 @@ static PBool p_edge_has_pair(ParamHandle *handle, if ((pe->flag & PEDGE_SEAM) || *r_pair || (topology_from_uvs && p_edge_implicit_seam(e, pe))) { *r_pair = NULL; - return P_FALSE; + return false; } *r_pair = pe; @@ -924,17 +816,17 @@ static PBool p_edge_has_pair(ParamHandle *handle, if ((*r_pair)->next->pair || (*r_pair)->next->next->pair) { /* non unfoldable, maybe mobius ring or klein bottle */ *r_pair = NULL; - return P_FALSE; + return false; } } return (*r_pair != NULL); } -static PBool p_edge_connect_pair(ParamHandle *handle, - PEdge *e, - PBool topology_from_uvs, - PEdge ***stack) +static bool p_edge_connect_pair(ParamHandle *handle, + PEdge *e, + bool topology_from_uvs, + PEdge ***stack) { PEdge *pair = NULL; @@ -955,7 +847,7 @@ static PBool p_edge_connect_pair(ParamHandle *handle, return (e->pair != NULL); } -static int p_connect_pairs(ParamHandle *handle, PBool topology_from_uvs) +static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs) { PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces), "Pstackbase"); @@ -1009,7 +901,7 @@ static void p_split_vert(PChart *chart, PEdge *e) { PEdge *we, *lastwe = NULL; PVert *v = e->vert; - PBool copy = P_TRUE; + bool copy = true; if (e->flag & PEDGE_PIN) { chart->flag |= PCHART_HAS_PINS; @@ -1035,7 +927,7 @@ static void p_split_vert(PChart *chart, PEdge *e) if (we == v->edge) { /* found it, no need to copy */ - copy = P_FALSE; + copy = false; v->nextlink = chart->verts; chart->verts = v; chart->nverts++; @@ -1136,13 +1028,13 @@ static PFace *p_face_add(ParamHandle *handle) static PFace *p_face_add_construct(ParamHandle *handle, ParamKey key, const ParamKey *vkeys, - float *co[4], - float *uv[4], + const float **co, + float **uv, int i1, int i2, int i3, - const ParamBool *pin, - const ParamBool *select) + const bool *pin, + const bool *select) { PFace *f = p_face_add(handle); PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; @@ -1179,7 +1071,6 @@ static PFace *p_face_add_construct(ParamHandle *handle, } } - /* insert into hash */ f->u.key = key; phash_insert(handle->hash_faces, (PHashLink *)f); @@ -1220,14 +1111,14 @@ static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3) return f; } -static PBool p_quad_split_direction(ParamHandle *handle, float **co, PHashKey *vkeys) +static bool p_quad_split_direction(ParamHandle *handle, const float **co, const ParamKey *vkeys) { /* Slight bias to prefer one edge over the other in case they are equal, so * that in symmetric models we choose the same split direction instead of * depending on floating point errors to decide. */ float bias = 1.0f + 1e-6f; float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]); - PBool dir = (fac <= 0.0f); + bool dir = (fac <= 0.0f); /* The face exists check is there because of a special case: * when two quads share three vertices, they can each be split into two triangles, @@ -1566,22 +1457,22 @@ static float p_vert_cotan(const float v1[3], const float v2[3], const float v3[3 return dot_v3v3(a, b) / clen; } -static PBool p_vert_flipped_wheel_triangle(PVert *v) +static bool p_vert_flipped_wheel_triangle(PVert *v) { PEdge *e = v->edge; do { if (p_face_uv_area_signed(e->face) < 0.0f) { - return P_TRUE; + return true; } e = p_wheel_edge_next(e); } while (e && (e != v->edge)); - return P_FALSE; + return false; } -static PBool p_vert_map_harmonic_weights(PVert *v) +static bool p_vert_map_harmonic_weights(PVert *v) { float weightsum, positionsum[2], olduv[2]; @@ -1647,10 +1538,10 @@ static PBool p_vert_map_harmonic_weights(PVert *v) v->uv[0] = olduv[0]; v->uv[1] = olduv[1]; - return P_FALSE; + return false; } - return P_TRUE; + return true; } static void p_vert_harmonic_insert(PVert *v) @@ -1883,7 +1774,7 @@ static void p_split_vertex(PEdge *edge, PEdge *pair) } while (e && (e != newv->edge)); } -static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair) +static bool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair) { PVert *oldv, *keepv; @@ -1893,22 +1784,22 @@ static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair) if (!edge || !pair) { /* avoid collapsing chart into an edge */ if (edge && !edge->next->pair && !edge->next->next->pair) { - return P_FALSE; + return false; } else if (pair && !pair->next->pair && !pair->next->next->pair) { - return P_FALSE; + return false; } } /* avoid merging two boundaries (oldv and keepv are on the 'other side' of * the chart) */ else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) { - return P_FALSE; + return false; } - return P_TRUE; + return true; } -static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew) +static bool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew) { float nold[3], nnew[3], sub1[3], sub2[3]; @@ -1923,7 +1814,7 @@ static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float return (dot_v3v3(nold, nnew) <= 0.0f); } -static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) +static bool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) { PVert *oldv, *keepv; PEdge *e; @@ -1950,7 +1841,7 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) } if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) { - return P_FALSE; + return false; } a[0] = angle; @@ -1967,10 +1858,10 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) for (i = 0; i < 3; i++) { if ((b[i] < a[i]) && (b[i] < minangle)) { - return P_FALSE; + return false; } else if ((b[i] > a[i]) && (b[i] > maxangle)) { - return P_FALSE; + return false; } } @@ -1980,7 +1871,7 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) if (p_vert_interior(oldv)) { /* HLSCM criterion: angular defect smaller than threshold. */ if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0)) { - return P_FALSE; + return false; } } else { @@ -1989,27 +1880,27 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) /* ABF++ criterion 2: avoid collapsing verts inwards. */ if (p_vert_interior(keepv)) { - return P_FALSE; + return false; } /* Don't collapse significant boundary changes. */ angle = p_vec_angle(v1->co, oldv->co, v2->co); if (angle < (M_PI * 160.0 / 180.0)) { - return P_FALSE; + return false; } } - return P_TRUE; + return true; } -static PBool p_collapse_allowed(PEdge *edge, PEdge *pair) +static bool p_collapse_allowed(PEdge *edge, PEdge *pair) { PVert *oldv, *keepv; p_collapsing_verts(edge, pair, &oldv, &keepv); if (oldv->flag & PVERT_PIN) { - return P_FALSE; + return false; } return (p_collapse_allowed_topologic(edge, pair) && p_collapse_allowed_geometric(edge, pair)); @@ -2572,21 +2463,17 @@ static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart) return norm; } -static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) +static bool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) { - PFace *f; - PEdge *e; - int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior; - PBool success; - LinearSolver *context; - - context = EIG_linear_solver_new(0, nvar, 1); + int ninterior = sys->ninterior; + int nvar = 2 * ninterior; + LinearSolver *context = EIG_linear_solver_new(0, nvar, 1); - for (i = 0; i < nvar; i++) { + for (int i = 0; i < nvar; i++) { EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]); } - for (f = chart->faces; f; f = f->nextlink) { + for (PFace *f = chart->faces; f; f = f->nextlink) { float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3]; float row1[6], row2[6], row3[6]; int vid[6]; @@ -2691,14 +2578,14 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1]; } - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { int r = vid[i]; if (r == -1) { continue; } - for (j = 0; j < 6; j++) { + for (int j = 0; j < 6; j++) { int c = vid[j]; if (c == -1) { @@ -2729,10 +2616,10 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) } } - success = EIG_linear_solver_solve(context); + bool success = EIG_linear_solver_solve(context); if (success) { - for (f = chart->faces; f; f = f->nextlink) { + for (PFace *f = chart->faces; f; f = f->nextlink) { float dlambda1, pre[3], dalpha; PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; @@ -2778,7 +2665,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2]; /* clamp */ - e = f->edge; + PEdge *e = f->edge; do { if (sys->alpha[e->u.id] > (float)M_PI) { sys->alpha[e->u.id] = (float)M_PI; @@ -2789,7 +2676,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) } while (e != f->edge); } - for (i = 0; i < ninterior; i++) { + for (int i = 0; i < ninterior; i++) { sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i); sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i); } @@ -2800,7 +2687,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) return success; } -static PBool p_chart_abf_solve(PChart *chart) +static bool p_chart_abf_solve(PChart *chart) { PVert *v; PFace *f; @@ -2911,7 +2798,7 @@ static PBool p_chart_abf_solve(PChart *chart) if (!p_abf_matrix_invert(&sys, chart)) { param_warning("ABF failed to invert matrix"); p_abf_free_system(&sys); - return P_FALSE; + return false; } p_abf_compute_sines(&sys); @@ -2920,14 +2807,14 @@ static PBool p_chart_abf_solve(PChart *chart) if (i == ABF_MAX_ITER) { param_warning("ABF maximum iterations reached"); p_abf_free_system(&sys); - return P_FALSE; + return false; } } chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha); p_abf_free_system(&sys); - return P_TRUE; + return true; } /* Least Squares Conformal Maps */ @@ -2983,7 +2870,7 @@ static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2) } } -static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2) +static bool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2) { PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2; PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe; @@ -3044,7 +2931,7 @@ static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PV } if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen)) { - return P_FALSE; + return false; } /* find pin1 in the split vertices */ @@ -3144,10 +3031,10 @@ static void p_chart_lscm_load_solution(PChart *chart) } } -static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) +static void p_chart_lscm_begin(PChart *chart, bool live, bool abf) { PVert *v, *pin1, *pin2; - PBool select = P_FALSE, deselect = P_FALSE; + bool select = false, deselect = false; int npins = 0, id = 0; /* give vertices matrix indices and count pins */ @@ -3155,12 +3042,12 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) if (v->flag & PVERT_PIN) { npins++; if (v->flag & PVERT_SELECT) { - select = P_TRUE; + select = true; } } if (!(v->flag & PVERT_SELECT)) { - deselect = P_TRUE; + deselect = true; } } @@ -3213,7 +3100,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) } } -static PBool p_chart_lscm_solve(ParamHandle *handle, PChart *chart) +static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart) { LinearSolver *context = chart->u.lscm.context; PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2; @@ -3350,7 +3237,7 @@ static PBool p_chart_lscm_solve(ParamHandle *handle, PChart *chart) if (EIG_linear_solver_solve(context)) { p_chart_lscm_load_solution(chart); - return P_TRUE; + return true; } for (v = chart->verts; v; v = v->nextlink) { @@ -3358,7 +3245,7 @@ static PBool p_chart_lscm_solve(ParamHandle *handle, PChart *chart) v->uv[1] = 0.0f; } - return P_FALSE; + return false; } static void p_chart_lscm_transform_single_pin(PChart *chart) @@ -3570,7 +3457,7 @@ static int p_compare_geometric_uv(const void *a, const void *b) return 1; } -static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right) +static bool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right) { /* Graham algorithm, taken from: * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */ @@ -3582,7 +3469,7 @@ static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, p_chart_boundaries(chart, NULL, &be); if (!be) { - return P_FALSE; + return false; } e = be; @@ -3636,7 +3523,7 @@ static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, MEM_freeN(U); MEM_freeN(L); - return P_TRUE; + return true; } static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4) @@ -3819,545 +3706,6 @@ static void p_chart_rotate_fit_aabb(PChart *chart) } } -/* Area Smoothing */ - -/* 2d BSP tree for inverse mapping - that's a bit silly. */ - -typedef struct SmoothTriangle { - float co1[2], co2[2], co3[2]; - float oco1[2], oco2[2], oco3[2]; -} SmoothTriangle; - -typedef struct SmoothNode { - struct SmoothNode *c1, *c2; - SmoothTriangle **tri; - float split; - int axis, ntri; -} SmoothNode; - -static void p_barycentric_2d( - const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3]) -{ - float a[2], c[2], h[2], div; - - a[0] = v2[0] - v1[0]; - a[1] = v2[1] - v1[1]; - c[0] = v3[0] - v1[0]; - c[1] = v3[1] - v1[1]; - - div = a[0] * c[1] - a[1] * c[0]; - - if (div == 0.0f) { - b[0] = 1.0f / 3.0f; - b[1] = 1.0f / 3.0f; - b[2] = 1.0f / 3.0f; - } - else { - h[0] = p[0] - v1[0]; - h[1] = p[1] - v1[1]; - - div = 1.0f / div; - - b[1] = (h[0] * c[1] - h[1] * c[0]) * div; - b[2] = (a[0] * h[1] - a[1] * h[0]) * div; - b[0] = 1.0f - b[1] - b[2]; - } -} - -static PBool p_triangle_inside(SmoothTriangle *t, float co[2]) -{ - float b[3]; - - p_barycentric_2d(t->co1, t->co2, t->co3, co, b); - - if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) { - co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2]; - co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2]; - return P_TRUE; - } - - return P_FALSE; -} - -static SmoothNode *p_node_new( - MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth) -{ - SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node)); - int axis, i, t1size = 0, t2size = 0; - float split, /* mi, */ /* UNUSED */ mx; - SmoothTriangle **t1, **t2, *t; - - node->tri = tri; - node->ntri = ntri; - - if (ntri <= 10 || depth >= 15) { - return node; - } - - t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1"); - t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1"); - - axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1; - split = 0.5f * (bmin[axis] + bmax[axis]); - - for (i = 0; i < ntri; i++) { - t = tri[i]; - - if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) { - t1[t1size] = t; - t1size++; - } - if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) { - t2[t2size] = t; - t2size++; - } - } - - if ((t1size == t2size) && (t1size == ntri)) { - MEM_freeN(t1); - MEM_freeN(t2); - return node; - } - - node->tri = NULL; - node->ntri = 0; - MEM_freeN(tri); - - node->axis = axis; - node->split = split; - - /* mi = bmin[axis]; */ /* UNUSED */ - mx = bmax[axis]; - bmax[axis] = split; - node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1); - - bmin[axis] = bmax[axis]; - bmax[axis] = mx; - node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1); - - return node; -} - -static void p_node_delete(SmoothNode *node) -{ - if (node->c1) { - p_node_delete(node->c1); - } - if (node->c2) { - p_node_delete(node->c2); - } - if (node->tri) { - MEM_freeN(node->tri); - } -} - -static PBool p_node_intersect(SmoothNode *node, float co[2]) -{ - int i; - - if (node->tri) { - for (i = 0; i < node->ntri; i++) { - if (p_triangle_inside(node->tri[i], co)) { - return P_TRUE; - } - } - - return P_FALSE; - } - - if (co[node->axis] < node->split) { - return p_node_intersect(node->c1, co); - } - return p_node_intersect(node->c2, co); -} - -/* smoothing */ - -static int p_compare_float(const void *a_, const void *b_) -{ - const float a = *(const float *)a_; - const float b = *(const float *)b_; - - if (a < b) { - return -1; - } - if (a == b) { - return 0; - } - return 1; -} - -static float p_smooth_median_edge_length(PChart *chart) -{ - PEdge *e; - float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength"); - float median; - int i; - - /* ok, so I'm lazy */ - for (i = 0, e = chart->edges; e; e = e->nextlink, i++) { - lengths[i] = p_edge_length(e); - } - - qsort(lengths, i, sizeof(float), p_compare_float); - - median = lengths[i / 2]; - MEM_freeN(lengths); - - return median; -} - -static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d) -{ - float len2d = p_edge_uv_length(e) * avg3d; - float len3d = p_edge_length(e) * avg2d; - - return (len3d == 0.0f) ? 0.0f : len2d / len3d; -} - -static void p_smooth(PChart *chart) -{ - PEdge *e; - PVert *v; - PFace *f; - int j, it2, maxiter2, it; - int nedges = chart->nedges, nwheel, gridx, gridy; - int edgesx, edgesy, nsize, esize, i, x, y, maxiter; - float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d; - float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy; - float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding; - SmoothTriangle *triangles, *t, *t2, **tri, **trip; - SmoothNode *root; - MemArena *arena; - - if (nedges == 0) { - return; - } - - p_chart_uv_bbox(chart, minv, maxv); - median = p_smooth_median_edge_length(chart) * 0.10f; - - if (median == 0.0f) { - return; - } - - invmedian = 1.0f / median; - - /* compute edge distortion */ - avglen2d = avglen3d = 0.0; - - for (e = chart->edges; e; e = e->nextlink) { - avglen2d += p_edge_uv_length(e); - avglen3d += p_edge_length(e); - } - - avglen2d /= nedges; - avglen3d /= nedges; - - for (v = chart->verts; v; v = v->nextlink) { - v->u.distortion = 0.0; - nwheel = 0; - - e = v->edge; - do { - v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d); - nwheel++; - - e = e->next->next->pair; - } while (e && (e != v->edge)); - - v->u.distortion /= nwheel; - } - - /* need to do excessive grid size checking still */ - center[0] = 0.5f * (minv[0] + maxv[0]); - center[1] = 0.5f * (minv[1] + maxv[1]); - - dx = 0.5f * (maxv[0] - minv[0]); - dy = 0.5f * (maxv[1] - minv[1]); - - padding = 0.15f; - dx += padding * dx + 2.0f * median; - dy += padding * dy + 2.0f * median; - - gridx = (int)(dx * invmedian); - gridy = (int)(dy * invmedian); - - minv[0] = center[0] - median * gridx; - minv[1] = center[1] - median * gridy; - maxv[0] = center[0] + median * gridx; - maxv[1] = center[1] + median * gridy; - - /* create grid */ - gridx = gridx * 2 + 1; - gridy = gridy * 2 + 1; - - if ((gridx <= 2) || (gridy <= 2)) { - return; - } - - edgesx = gridx - 1; - edgesy = gridy - 1; - nsize = gridx * gridy; - esize = edgesx * edgesy; - - nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes"); - nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX"); - nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY"); - oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX"); - oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY"); - hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges"); - vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges"); - - if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) { - if (nodes) { - MEM_freeN(nodes); - } - if (nodesx) { - MEM_freeN(nodesx); - } - if (nodesy) { - MEM_freeN(nodesy); - } - if (oldnodesx) { - MEM_freeN(oldnodesx); - } - if (oldnodesy) { - MEM_freeN(oldnodesy); - } - if (hedges) { - MEM_freeN(hedges); - } - if (vedges) { - MEM_freeN(vedges); - } - - // printf("Not enough memory for area smoothing grid"); - return; - } - - for (x = 0; x < gridx; x++) { - for (y = 0; y < gridy; y++) { - i = x + y * gridx; - - nodesx[i] = minv[0] + median * x; - nodesy[i] = minv[1] + median * y; - - nodes[i] = 1.0f; - } - } - - /* embed in grid */ - for (f = chart->faces; f; f = f->nextlink) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - float fmin[2], fmax[2]; - int bx1, by1, bx2, by2; - - INIT_MINMAX2(fmin, fmax); - - minmax_v2v2_v2(fmin, fmax, e1->vert->uv); - minmax_v2v2_v2(fmin, fmax, e2->vert->uv); - minmax_v2v2_v2(fmin, fmax, e3->vert->uv); - - bx1 = (int)((fmin[0] - minv[0]) * invmedian); - by1 = (int)((fmin[1] - minv[1]) * invmedian); - bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2); - by2 = (int)((fmax[1] - minv[1]) * invmedian + 2); - - for (x = bx1; x < bx2; x++) { - for (y = by1; y < by2; y++) { - float p[2], b[3]; - - i = x + y * gridx; - - p[0] = nodesx[i]; - p[1] = nodesy[i]; - - p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b); - - if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) { - nodes[i] = e1->vert->u.distortion * b[0]; - nodes[i] += e2->vert->u.distortion * b[1]; - nodes[i] += e3->vert->u.distortion * b[2]; - } - } - } - } - - /* smooth the grid */ - maxiter = 10; - climit = 0.00001f * nsize; - - for (it = 0; it < maxiter; it++) { - moved = 0.0f; - - for (x = 0; x < edgesx; x++) { - for (y = 0; y < edgesy; y++) { - i = x + y * gridx; - j = x + y * edgesx; - - hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f; - vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f; - - /* we do *inverse* mapping */ - hedges[j] = 1.0f / hedges[j]; - vedges[j] = 1.0f / vedges[j]; - } - } - - maxiter2 = 50; - dlimit = 0.0001f; - - for (it2 = 0; it2 < maxiter2; it2++) { - d = 0.0f; - - memcpy(oldnodesx, nodesx, sizeof(float) * nsize); - memcpy(oldnodesy, nodesy, sizeof(float) * nsize); - - for (x = 1; x < gridx - 1; x++) { - for (y = 1; y < gridy - 1; y++) { - float p[2], oldp[2], sum1, sum2, diff[2], length; - - i = x + gridx * y; - j = x + edgesx * y; - - oldp[0] = oldnodesx[i]; - oldp[1] = oldnodesy[i]; - - sum1 = hedges[j - 1] * oldnodesx[i - 1]; - sum1 += hedges[j] * oldnodesx[i + 1]; - sum1 += vedges[j - edgesx] * oldnodesx[i - gridx]; - sum1 += vedges[j] * oldnodesx[i + gridx]; - - sum2 = hedges[j - 1]; - sum2 += hedges[j]; - sum2 += vedges[j - edgesx]; - sum2 += vedges[j]; - - nodesx[i] = sum1 / sum2; - - sum1 = hedges[j - 1] * oldnodesy[i - 1]; - sum1 += hedges[j] * oldnodesy[i + 1]; - sum1 += vedges[j - edgesx] * oldnodesy[i - gridx]; - sum1 += vedges[j] * oldnodesy[i + gridx]; - - nodesy[i] = sum1 / sum2; - - p[0] = nodesx[i]; - p[1] = nodesy[i]; - - diff[0] = p[0] - oldp[0]; - diff[1] = p[1] - oldp[1]; - - length = len_v2(diff); - d = max_ff(d, length); - moved += length; - } - } - - if (d < dlimit) { - break; - } - } - - if (moved < climit) { - break; - } - } - - MEM_freeN(oldnodesx); - MEM_freeN(oldnodesy); - MEM_freeN(hedges); - MEM_freeN(vedges); - - /* Create BSP. */ - t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris"); - trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP"); - - if (!triangles || !tri) { - MEM_freeN(nodes); - MEM_freeN(nodesx); - MEM_freeN(nodesy); - - if (triangles) { - MEM_freeN(triangles); - } - if (tri) { - MEM_freeN(tri); - } - - // printf("Not enough memory for area smoothing grid"); - return; - } - - for (x = 0; x < edgesx; x++) { - for (y = 0; y < edgesy; y++) { - i = x + y * gridx; - - t->co1[0] = nodesx[i]; - t->co1[1] = nodesy[i]; - - t->co2[0] = nodesx[i + 1]; - t->co2[1] = nodesy[i + 1]; - - t->co3[0] = nodesx[i + gridx]; - t->co3[1] = nodesy[i + gridx]; - - t->oco1[0] = minv[0] + x * median; - t->oco1[1] = minv[1] + y * median; - - t->oco2[0] = minv[0] + (x + 1) * median; - t->oco2[1] = minv[1] + y * median; - - t->oco3[0] = minv[0] + x * median; - t->oco3[1] = minv[1] + (y + 1) * median; - - t2 = t + 1; - - t2->co1[0] = nodesx[i + gridx + 1]; - t2->co1[1] = nodesy[i + gridx + 1]; - - t2->oco1[0] = minv[0] + (x + 1) * median; - t2->oco1[1] = minv[1] + (y + 1) * median; - - t2->co2[0] = t->co2[0]; - t2->co2[1] = t->co2[1]; - t2->oco2[0] = t->oco2[0]; - t2->oco2[1] = t->oco2[1]; - - t2->co3[0] = t->co3[0]; - t2->co3[1] = t->co3[1]; - t2->oco3[0] = t->oco3[0]; - t2->oco3[1] = t->oco3[1]; - - *trip = t; - trip++; - t++; - *trip = t; - trip++; - t++; - } - } - - MEM_freeN(nodes); - MEM_freeN(nodesx); - MEM_freeN(nodesy); - - arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena"); - root = p_node_new(arena, tri, esize * 2, minv, maxv, 0); - - for (v = chart->verts; v; v = v->nextlink) { - if (!p_node_intersect(root, v->uv)) { - param_warning("area smoothing error: couldn't find mapping triangle\n"); - } - } - - p_node_delete(root); - BLI_memarena_free(arena); - - MEM_freeN(triangles); -} - /* Exported */ ParamHandle *GEO_uv_parametrizer_construct_begin(void) @@ -4396,8 +3744,11 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle) p_chart_delete(phandle->charts[i]); } - if (phandle->charts) { - MEM_freeN(phandle->charts); + MEM_SAFE_FREE(phandle->charts); + + if (phandle->pin_hash) { + BLI_ghash_free(phandle->pin_hash, NULL, NULL); + phandle->pin_hash = NULL; } if (phandle->construction_chart) { @@ -4414,14 +3765,88 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle) MEM_freeN(phandle); } +typedef struct GeoUVPinIndex { + struct GeoUVPinIndex *next; + float uv[2]; + ParamKey reindex; +} GeoUVPinIndex; + +/* Find a (mostly) unique ParamKey given a BMVert index and UV co-ordinates. + * For each unique pinned UVs, return a unique ParamKey, starting with + * a very large number, and decreasing steadily from there. + * For non-pinned UVs which share a BMVert with a pinned UV, + * return the index corresponding to the closest pinned UV. + * For everything else, just return the BMVert index. + * Note that ParamKeys will eventually be hashed, so they don't need to be contiguous. + */ +ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]) +{ + if (!handle->pin_hash) { + return bmvertindex; /* No verts pinned. */ + } + + GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex)); + if (!pinuvlist) { + return bmvertindex; /* Vert not pinned. */ + } + + /* At least one of the UVs associated with bmvertindex is pinned. Find the best one. */ + float bestdistsquared = len_squared_v2v2(pinuvlist->uv, uv); + ParamKey bestkey = pinuvlist->reindex; + pinuvlist = pinuvlist->next; + while (pinuvlist) { + const float distsquared = len_squared_v2v2(pinuvlist->uv, uv); + if (bestdistsquared > distsquared) { + bestdistsquared = distsquared; + bestkey = pinuvlist->reindex; + } + pinuvlist = pinuvlist->next; + } + return bestkey; +} + +static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2]) +{ + GeoUVPinIndex *pinuv = BLI_memarena_alloc(handle->arena, sizeof(*pinuv)); + pinuv->next = NULL; + copy_v2_v2(pinuv->uv, uv); + pinuv->reindex = PARAM_KEY_MAX - (handle->unique_pin_count++); + return pinuv; +} + +void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]) +{ + if (!handle->pin_hash) { + handle->pin_hash = BLI_ghash_int_new("uv pin reindex"); + } + + GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex)); + if (!pinuvlist) { + BLI_ghash_insert( + handle->pin_hash, POINTER_FROM_INT(bmvertindex), new_geo_uv_pinindex(handle, uv)); + return; + } + + while (true) { + if (equals_v2v2(pinuvlist->uv, uv)) { + return; + } + if (!pinuvlist->next) { + pinuvlist->next = new_geo_uv_pinindex(handle, uv); + return; + } + pinuvlist = pinuvlist->next; + } +} + static void p_add_ngon(ParamHandle *handle, - ParamKey key, - int nverts, - ParamKey *vkeys, - float **co, - float **uv, - ParamBool *pin, - ParamBool *select) + const ParamKey key, + const int nverts, + const ParamKey *vkeys, + const float **co, + float **uv, /* Output will eventually be written to `uv`. */ + const bool *pin, + const bool *select) { /* Allocate memory for polyfill. */ MemArena *arena = handle->polyfill_arena; @@ -4463,11 +3888,11 @@ static void p_add_ngon(ParamHandle *handle, uint v1 = tri[1]; uint v2 = tri[2]; - ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]}; - float *tri_co[3] = {co[v0], co[v1], co[v2]}; + const ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]}; + const float *tri_co[3] = {co[v0], co[v1], co[v2]}; float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]}; - ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]}; - ParamBool tri_select[3] = {select[v0], select[v1], select[v2]}; + bool tri_pin[3] = {pin[v0], pin[v1], pin[v2]}; + bool tri_select[3] = {select[v0], select[v1], select[v2]}; GEO_uv_parametrizer_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select); } @@ -4476,13 +3901,13 @@ static void p_add_ngon(ParamHandle *handle, } void GEO_uv_parametrizer_face_add(ParamHandle *phandle, - ParamKey key, - int nverts, - ParamKey *vkeys, - float *co[4], - float *uv[4], - ParamBool *pin, - ParamBool *select) + const ParamKey key, + const int nverts, + const ParamKey *vkeys, + const float **co, + float **uv, + const bool *pin, + const bool *select) { param_assert(phash_lookup(phandle->hash_faces, key) == NULL); param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); @@ -4522,8 +3947,8 @@ void GEO_uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys) } void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, - ParamBool fill, - ParamBool topology_from_uvs, + bool fill, + bool topology_from_uvs, int *count_fail) { PChart *chart = phandle->construction_chart; @@ -4532,7 +3957,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); - phandle->ncharts = p_connect_pairs(phandle, (PBool)topology_from_uvs); + phandle->ncharts = p_connect_pairs(phandle, topology_from_uvs); phandle->charts = p_split_charts(phandle, chart, phandle->ncharts); p_chart_delete(phandle->construction_chart); @@ -4574,7 +3999,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, phandle->state = PHANDLE_STATE_CONSTRUCTED; } -void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, ParamBool live, ParamBool abf) +void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf) { PFace *f; int i; @@ -4586,7 +4011,7 @@ void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, ParamBool live, ParamB for (f = phandle->charts[i]->faces; f; f = f->nextlink) { p_face_backup_uvs(f); } - p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf); + p_chart_lscm_begin(phandle->charts[i], live, abf); } } @@ -4601,7 +4026,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in chart = phandle->charts[i]; if (chart->u.lscm.context) { - const PBool result = p_chart_lscm_solve(phandle, chart); + const bool result = p_chart_lscm_solve(phandle, chart); if (result && !(chart->flag & PCHART_HAS_PINS)) { p_chart_rotate_minimum_area(chart); @@ -4702,24 +4127,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *phandle) phandle->rng = NULL; } -void GEO_uv_parametrizer_smooth_area(ParamHandle *phandle) -{ - int i; - - param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); - - for (i = 0; i < phandle->ncharts; i++) { - PChart *chart = phandle->charts[i]; - PVert *v; - - for (v = chart->verts; v; v = v->nextlink) { - v->flag &= ~PVERT_PIN; - } - - p_smooth(chart); - } -} - /* don't pack, just rotate (used for better packing) */ static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pinned) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 6cf7f6f11e5..d59d2cb52fc 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -7,7 +7,7 @@ #include <stdio.h> -#include "BLI_blenlib.h" +#include "BLI_listbase.h" #include "BLI_math_vector.h" #include "BLI_utildefines.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index e7301b4d910..73423d9a8ee 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -49,5 +49,5 @@ typedef void (*gpBakeCb)(struct GpencilModifierData *md_, void generic_bake_deform_stroke(struct Depsgraph *depsgraph, struct GpencilModifierData *md, struct Object *ob, - const bool retime, + bool retime, gpBakeCb bake_cb); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index f5ecce69129..092253dde79 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -8,10 +8,9 @@ #include <stdio.h> #include "BLI_listbase.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" -#include "BLI_math.h" - #include "BLT_translation.h" #include "DNA_defaults.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index 38866bcd32a..407055c6165 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -9,14 +9,11 @@ #include "MEM_guardedalloc.h" -#include "BLI_utildefines.h" - #include "BLI_hash.h" +#include "BLI_listbase.h" +#include "BLI_math_vector.h" #include "BLI_rand.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_rand.h" +#include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index 88515d849bc..cf390e8d3a0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -7,14 +7,15 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "MEM_guardedalloc.h" -#include "BLI_utildefines.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" +#include "BLI_listbase.h" +#include "BLI_math_base.h" +#include "BLI_math_vector.h" #include "BLI_sort.h" +#include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index 792def30812..8ada66cfd55 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -9,7 +9,6 @@ #include "BLI_utildefines.h" -#include "BLI_blenlib.h" #include "BLI_math_color.h" #include "BLI_math_vector.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c index f023b00480c..41015c429fe 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c @@ -9,7 +9,7 @@ #include <string.h> #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLI_string.h" #include "DNA_defaults.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c index e5604005240..0f1652a5620 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c @@ -8,8 +8,8 @@ #include <stdio.h> #include "BLI_listbase.h" -#include "BLI_math.h" #include "BLI_math_geom.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -22,7 +22,6 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index bc0464cb4f9..652894af017 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -6,12 +6,14 @@ */ #include <stdio.h> +#include <string.h> #include "BLI_listbase.h" +#include "BLI_math_base.h" +#include "BLI_math_matrix.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" -#include "BLI_math.h" - #include "BLT_translation.h" #include "DNA_defaults.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c index c92c062348c..5a358f5b3a1 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c @@ -6,10 +6,11 @@ */ #include <stdio.h> +#include <string.h> #include "BLI_hash.h" #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_base.h" #include "BLI_rand.h" #include "BLI_utildefines.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index a07ef2eb195..8d77fb50c71 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -7,9 +7,8 @@ #include <stdio.h> -#include "BLI_utildefines.h" - #include "BLI_math_vector.h" +#include "BLI_utildefines.h" #include "BLT_translation.h" @@ -22,9 +21,6 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "MOD_gpencil_lineart.h" -#include "lineart/MOD_lineart.h" - #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_global.h" @@ -43,8 +39,10 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "MOD_gpencil_lineart.h" #include "MOD_gpencil_modifiertypes.h" #include "MOD_gpencil_ui_common.h" +#include "lineart/MOD_lineart.h" #include "WM_api.h" #include "WM_types.h" @@ -326,6 +324,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemPointerR( row, ptr, "target_material", &obj_data_ptr, "materials", NULL, ICON_SHADING_TEXTURE); + uiLayout *col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "thickness", UI_ITEM_R_SLIDER, IFACE_("Line Thickness"), ICON_NONE); + uiItemR(col, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + gpencil_modifier_panel_end(layout, ptr); } @@ -354,7 +356,7 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayout *sub = uiLayoutRowWithHeading(col, false, IFACE_("Crease")); uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE); uiLayout *entry = uiLayoutRow(sub, false); - uiLayoutSetEnabled(entry, RNA_boolean_get(ptr, "use_crease") || is_first); + uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first); if (use_cache && !is_first) { uiItemL(entry, IFACE_("Angle Cached"), ICON_INFO); } @@ -400,21 +402,6 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "use_back_face_culling", 0, IFACE_("Force Backface Culling"), ICON_NONE); } -static void style_panel_draw(const bContext *UNUSED(C), Panel *panel) -{ - uiLayout *layout = panel->layout; - PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL); - - const bool is_baked = RNA_boolean_get(ptr, "is_baked"); - - uiLayoutSetPropSep(layout, true); - uiLayoutSetEnabled(layout, !is_baked); - - uiItemR(layout, ptr, "thickness", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - - uiItemR(layout, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE); -} - static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; @@ -526,6 +513,7 @@ static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "use_intersection_match", 0, IFACE_("Exact Match"), ICON_NONE); } + static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; @@ -709,8 +697,6 @@ static void panelRegister(ARegionType *region_type) region_type, "edge_types", "Edge Types", NULL, edge_types_panel_draw, panel_type); gpencil_modifier_subpanel_register( region_type, "geometry", "Geometry Processing", NULL, options_panel_draw, panel_type); - gpencil_modifier_subpanel_register( - region_type, "style", "Style", NULL, style_panel_draw, panel_type); PanelType *occlusion_panel = gpencil_modifier_subpanel_register( region_type, "occlusion", "Occlusion", NULL, occlusion_panel_draw, panel_type); gpencil_modifier_subpanel_register(region_type, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 6460a69a6cc..df66251159c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -10,7 +10,7 @@ #include "BLI_utildefines.h" #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLT_translation.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index d80e32feb2e..fd4eb5da835 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -16,8 +16,8 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" +#include "BLI_listbase.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "BKE_context.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 259e62a249c..253603aea67 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -7,11 +7,10 @@ #include <stdio.h> -#include "BLI_listbase.h" -#include "BLI_utildefines.h" - #include "BLI_hash.h" +#include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index f201a147082..ba88c83161f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -7,15 +7,14 @@ #include <stdio.h> +#include "BLI_hash.h" #include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_rand.h" #include "BLI_utildefines.h" #include "BLT_translation.h" -#include "BLI_hash.h" -#include "BLI_math.h" -#include "BLI_rand.h" - #include "DNA_defaults.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index b964b143a0f..0bcbd71f029 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -6,12 +6,10 @@ */ #include <stdio.h> +#include <string.h> #include "BLI_utildefines.h" -#include "BLI_blenlib.h" -#include "BLI_math_vector.h" - #include "BLT_translation.h" #include "DNA_defaults.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c index 7de1cc89a45..cd2373dcb26 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c @@ -9,7 +9,7 @@ #include <string.h> /* For #MEMCPY_STRUCT_AFTER. */ #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -18,7 +18,6 @@ #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index e7dfdfee8d2..07350b73ce3 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -16,7 +16,6 @@ #include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" -#include "DNA_vec_types.h" #include "BKE_context.h" #include "BKE_gpencil_geom.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c index 5c8c65b9f97..6ba7a934bff 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c @@ -8,7 +8,7 @@ #include <stdio.h> #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index 3ddb508d58a..68fe15df898 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -8,7 +8,7 @@ #include <stdio.h> #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "DNA_defaults.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 8fa14496616..ad8804782e8 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -10,7 +10,7 @@ #include "BLI_utildefines.h" #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "DNA_defaults.h" #include "DNA_gpencil_modifier_types.h" @@ -47,7 +47,6 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" -#include "DEG_depsgraph_query.h" static void initData(GpencilModifierData *md) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c index e90408b1a94..f40e6ba0728 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c @@ -8,7 +8,7 @@ #include <stdio.h> #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "DNA_defaults.h" @@ -18,7 +18,6 @@ #include "DNA_object_types.h" #include "DNA_screen_types.h" -#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" @@ -29,7 +28,6 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" -#include "DEG_depsgraph_query.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c index d2c31591a98..1a6cadabf51 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c @@ -8,7 +8,7 @@ #include <stdio.h> #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "DNA_defaults.h" @@ -29,7 +29,6 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" -#include "DEG_depsgraph_query.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index ad3e1b5d7f2..e90d3dc34c5 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -36,10 +36,10 @@ typedef struct LineartTriangle { /* first culled in line list to use adjacent triangle info, then go through triangle list. */ double gn[3]; - unsigned char material_mask_bits; - unsigned char intersection_mask; - unsigned char mat_occlusion; - unsigned char flags; /* #eLineartTriangleFlags */ + uint8_t material_mask_bits; + uint8_t intersection_mask; + uint8_t mat_occlusion; + uint8_t flags; /* #eLineartTriangleFlags */ /** * Only use single link list, because we don't need to go back in order. @@ -84,10 +84,10 @@ typedef struct LineartEdgeSegment { /** at==0: left at==1: right (this is in 2D projected space) */ double at; /** Occlusion level after "at" point */ - unsigned char occlusion; + uint8_t occlusion; /* Used to filter line art occlusion edges */ - unsigned char material_mask_bits; + uint8_t material_mask_bits; } LineartEdgeSegment; typedef struct LineartVert { @@ -102,7 +102,7 @@ typedef struct LineartVert { * size of the struct is extended to include intersection data. * See #eLineArtVertFlags. */ - char flag; + uint8_t flag; } LineartVert; @@ -119,17 +119,14 @@ typedef enum eLineArtVertFlags { } eLineArtVertFlags; typedef struct LineartEdge { - /** We only need link node kind of list here. */ - struct LineartEdge *next; struct LineartVert *v1, *v2; - struct LineartTriangle *t1, *t2; ListBase segments; - char min_occ; + int8_t min_occ; /** Also for line type determination on chaining. */ uint16_t flags; - unsigned char intersection_mask; + uint8_t intersection_mask; /** * Still need this entry because culled lines will not add to object @@ -149,15 +146,15 @@ typedef struct LineartEdgeChain { float length; /** Used when re-connecting and grease-pencil stroke generation. */ - char picked; - char level; + int8_t picked; + int8_t level; /** Chain now only contains one type of segments */ int type; /** Will only connect chains that has the same loop id. */ int loop_id; - unsigned char material_mask_bits; - unsigned char intersection_mask; + uint8_t material_mask_bits; + uint8_t intersection_mask; struct Object *object_ref; } LineartEdgeChain; @@ -170,9 +167,9 @@ typedef struct LineartEdgeChainItem { float gpos[3]; float normal[3]; uint16_t line_type; - char occlusion; - unsigned char material_mask_bits; - unsigned char intersection_mask; + uint8_t occlusion; + uint8_t material_mask_bits; + uint8_t intersection_mask; size_t index; } LineartEdgeChainItem; @@ -180,17 +177,17 @@ typedef struct LineartChainRegisterEntry { struct LineartChainRegisterEntry *next, *prev; LineartEdgeChain *ec; LineartEdgeChainItem *eci; - char picked; + int8_t picked; /* left/right mark. * Because we revert list in chaining so we need the flag. */ - char is_left; + int8_t is_left; } LineartChainRegisterEntry; typedef struct LineartAdjacentEdge { - unsigned int v1; - unsigned int v2; - unsigned int e; + uint32_t v1; + uint32_t v2; + uint32_t e; } LineartAdjacentEdge; enum eLineArtTileRecursiveLimit { @@ -210,49 +207,107 @@ typedef struct LineartPendingEdges { int next; } LineartPendingEdges; -typedef struct LineartRenderBuffer { - struct LineartRenderBuffer *prev, *next; +typedef struct LineartData { + int w, h; int thread_count; + int sizeof_triangle; - int w, h; - int tile_size_w, tile_size_h; - int tile_count_x, tile_count_y; - double width_per_tile, height_per_tile; - double view_projection[4][4]; - double view[4][4]; + LineartStaticMemPool render_data_pool; + /* A pointer to LineartCache::chain_data_pool, which acts as a cache for edge chains. */ + LineartStaticMemPool *chain_data_pool; - float overscan; + struct _qtree { - struct LineartBoundingArea *initial_bounding_areas; - unsigned int bounding_area_count; + int count_x, count_y; + double tile_width, tile_height; - /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there - * will be a lot of triangles aligned in line which can not be separated by continue subdividing - * the tile. So we set a strict limit when using ortho camera. See eLineArtTileRecursiveLimit. */ - int tile_recursive_level; + /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there + * will be a lot of triangles aligned in line which can not be separated by continue + * subdividing the tile. So we set a strict limit when using ortho camera. See + * eLineArtTileRecursiveLimit. */ + int recursive_level; - ListBase vertex_buffer_pointers; - ListBase line_buffer_pointers; - ListBase triangle_buffer_pointers; + struct LineartBoundingArea *initials; - /** This one's memory is not from main pool and is free()ed after culling stage. */ - ListBase triangle_adjacent_pointers; + uint32_t tile_count; - ListBase intersecting_vertex_buffer; - /** Use the one comes with Line Art. */ - LineartStaticMemPool render_data_pool; - ListBase wasted_cuts; - SpinLock lock_cuts; + } qtree; - /* This is just a pointer to LineartCache::chain_data_pool, which acts as a cache for line - * chains. */ - LineartStaticMemPool *chain_data_pool; + struct _geom { + + ListBase vertex_buffer_pointers; + ListBase line_buffer_pointers; + ListBase triangle_buffer_pointers; + + /** This one's memory is not from main pool and is free()ed after culling stage. */ + ListBase triangle_adjacent_pointers; + + ListBase intersecting_vertex_buffer; + + } geom; + + struct _conf { + + double view_projection[4][4]; + double view[4][4]; + + float overscan; + + int max_occlusion_level; + double crease_angle; + double crease_cos; - /* Render status */ - double view_vector[3]; + int draw_material_preview; + double material_transparency; - int triangle_size; + bool use_contour; + bool use_crease; + bool use_material; + bool use_edge_marks; + bool use_intersections; + bool use_loose; + bool fuzzy_intersections; + bool fuzzy_everything; + bool allow_boundaries; + bool allow_overlapping_edges; + bool allow_duplicated_types; + bool remove_doubles; + bool use_loose_as_contour; + bool use_loose_edge_chain; + bool use_geometry_space_chain; + bool use_image_boundary_trimming; + bool use_back_face_culling; + + bool filter_face_mark; + bool filter_face_mark_invert; + bool filter_face_mark_boundaries; + bool filter_face_mark_keep_contour; + + bool force_crease; + bool sharp_as_crease; + + bool chain_preserve_details; + + /* Keep an copy of these data so when line art is running it's self-contained. */ + bool cam_is_persp; + float cam_obmat[4][4]; + double camera_pos[3]; + double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */ + double near_clip, far_clip; + float shift_x, shift_y; + float crease_threshold; + float chaining_image_threshold; + float angle_splitting_threshold; + + float chain_smooth_tolerance; + + double view_vector[3]; + + } conf; + + LineartElementLinkNode *isect_scheduled_up_to; + int isect_scheduled_up_to_index; /* Note: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */ struct LineartPendingEdges pending_edges; @@ -260,79 +315,22 @@ typedef struct LineartRenderBuffer { ListBase chains; - /* For managing calculation tasks for multiple threads. */ + ListBase wasted_cuts; + SpinLock lock_cuts; SpinLock lock_task; - /* settings */ - - int max_occlusion_level; - double crease_angle; - double crease_cos; - - int draw_material_preview; - double material_transparency; - - bool use_contour; - bool use_crease; - bool use_material; - bool use_edge_marks; - bool use_intersections; - bool use_loose; - bool fuzzy_intersections; - bool fuzzy_everything; - bool allow_boundaries; - bool allow_overlapping_edges; - bool allow_duplicated_types; - bool remove_doubles; - bool use_loose_as_contour; - bool use_loose_edge_chain; - bool use_geometry_space_chain; - bool use_image_boundary_trimming; - bool use_back_face_culling; - - bool filter_face_mark; - bool filter_face_mark_invert; - bool filter_face_mark_boundaries; - bool filter_face_mark_keep_contour; - - bool force_crease; - bool sharp_as_crease; - - bool chain_preserve_details; - - /* Keep an copy of these data so when line art is running it's self-contained. */ - bool cam_is_persp; - float cam_obmat[4][4]; - double camera_pos[3]; - double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */ - double near_clip, far_clip; - float shift_x, shift_y; - float crease_threshold; - float chaining_image_threshold; - float angle_splitting_threshold; - - float chain_smooth_tolerance; - - /* FIXME(Yiming): Temporary solution for speeding up calculation by not including lines that - * are not in the selected source. This will not be needed after we have a proper scene-wise - * cache running because multiple modifiers can then select results from that without further - * calculation. */ - int _source_type; - struct Collection *_source_collection; - struct Object *_source_object; - -} LineartRenderBuffer; +} LineartData; typedef struct LineartCache { /** Separate memory pool for chain data, this goes to the cache, so when we free the main pool, * chains will still be available. */ LineartStaticMemPool chain_data_pool; - /** A copy of rb->chains so we have that data available after rb has been destroyed. */ + /** A copy of ld->chains so we have that data available after ld has been destroyed. */ ListBase chains; /** Cache only contains edge types specified in this variable. */ - char rb_edge_types; + uint16_t all_enabled_edge_types; } LineartCache; #define DBL_TRIANGLE_LIM 1e-8 @@ -358,13 +356,13 @@ typedef enum eLineartTriangleFlags { #define LRT_THREAD_EDGE_COUNT 1000 typedef struct LineartRenderTaskInfo { - struct LineartRenderBuffer *rb; + struct LineartData *ld; int thread_id; /** * #pending_edges here only stores a reference to a portion in - * LineartRenderbuffer::pending_edges, assigned by the occlusion scheduler. + * LineartData::pending_edges, assigned by the occlusion scheduler. */ struct LineartPendingEdges pending_edges; @@ -390,12 +388,12 @@ typedef struct LineartObjectInfo { } LineartObjectInfo; typedef struct LineartObjectLoadTaskInfo { - struct LineartRenderBuffer *rb; + struct LineartData *ld; int thread_id; /* LinkNode styled list */ LineartObjectInfo *pending; /* Used to spread the load across several threads. This can not overflow. */ - long unsigned int total_faces; + uint64_t total_faces; } LineartObjectLoadTaskInfo; /** @@ -429,15 +427,18 @@ typedef struct LineartBoundingArea { /** 1,2,3,4 quadrant */ struct LineartBoundingArea *child; + SpinLock lock; + ListBase lp; ListBase rp; ListBase up; ListBase bp; - uint16_t triangle_count; - uint16_t max_triangle_count; - uint16_t line_count; - uint16_t max_line_count; + uint32_t triangle_count; + uint32_t max_triangle_count; + uint32_t line_count; + uint32_t max_line_count; + uint32_t user_count; /* Use array for speeding up multiple accesses. */ struct LineartTriangle **linked_triangles; @@ -459,9 +460,6 @@ typedef struct LineartBoundingArea { #define LRT_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c)) -#define LRT_ABC(index) (index == 0 ? a : (index == 1 ? b : c)) -#define LRT_PABC(index) (index == 0 ? pa : (index == 1 ? pb : pc)) - #define DBL_LOOSER 1e-5 #define LRT_DOUBLE_CLOSE_LOOSER(a, b) (((a) + DBL_LOOSER) >= (b) && ((a)-DBL_LOOSER) <= (b)) #define LRT_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b)) @@ -626,30 +624,28 @@ BLI_INLINE int lineart_intersect_seg_seg(const double *a1, struct Depsgraph; struct LineartGpencilModifierData; -struct LineartRenderBuffer; +struct LineartData; struct Scene; void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd); -void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb); -void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb); +void MOD_lineart_chain_feature_lines(LineartData *ld); +void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld); /** * This function only connects two different chains. It will not do any clean up or smart chaining. * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is * implemented yet. */ -void MOD_lineart_chain_connect(LineartRenderBuffer *rb); -void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, float threshold); -void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb); +void MOD_lineart_chain_connect(LineartData *ld); +void MOD_lineart_chain_discard_short(LineartData *ld, float threshold); +void MOD_lineart_chain_clip_at_border(LineartData *ld); /** * This should always be the last stage!, see the end of * #MOD_lineart_chain_split_for_fixed_occlusion(). */ -void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad); -void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance); -void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, - float dist, - bool use_custom_camera); +void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad); +void MOD_lineart_smooth_chains(LineartData *ld, float tolerance); +void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera); int MOD_lineart_chain_count(const LineartEdgeChain *ec); void MOD_lineart_chain_clear_picked_flag(LineartCache *lc); @@ -669,14 +665,12 @@ struct Scene; /** * This only gets initial "biggest" tile. */ -LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb, - double x, - double y); +LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y); /** * Wrapper for more convenience. */ -LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y); +LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y); struct bGPDframe; struct bGPDlayer; @@ -689,16 +683,16 @@ void MOD_lineart_gpencil_generate(LineartCache *cache, struct Object *ob, struct bGPDlayer *gpl, struct bGPDframe *gpf, - char source_type, + int8_t source_type, void *source_reference, int level_start, int level_end, int mat_nr, - short edge_types, - unsigned char mask_switches, - unsigned char material_mask_bits, - unsigned char intersection_mask, - short thickness, + int16_t edge_types, + uint8_t mask_switches, + uint8_t material_mask_bits, + uint8_t intersection_mask, + int16_t thickness, float opacity, const char *source_vgname, const char *vgname, diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 226b8f532b5..1d84bb8e232 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -23,7 +23,7 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba, LineartVert *vt, LineartVert **new_vt, int match_flag, - unsigned char match_isec_mask) + uint8_t match_isec_mask) { for (int i = 0; i < ba->line_count; i++) { LineartEdge *n_e = ba->linked_lines[i]; @@ -60,12 +60,12 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba, return NULL; } -static LineartEdgeChain *lineart_chain_create(LineartRenderBuffer *rb) +static LineartEdgeChain *lineart_chain_create(LineartData *ld) { LineartEdgeChain *ec; - ec = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChain)); + ec = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChain)); - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); return ec; } @@ -85,14 +85,14 @@ static bool lineart_point_overlapping(LineartEdgeChainItem *eci, return false; } -static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb, +static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld, LineartEdgeChain *ec, float *fbcoord, float *gpos, float *normal, - char type, + uint8_t type, int level, - unsigned char material_mask_bits, + uint8_t material_mask_bits, size_t index) { LineartEdgeChainItem *eci; @@ -108,7 +108,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb, return old_eci; } - eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem)); + eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem)); copy_v4_v4(eci->pos, fbcoord); copy_v3_v3(eci->gpos, gpos); @@ -122,14 +122,14 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb, return eci; } -static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb, +static LineartEdgeChainItem *lineart_chain_prepend_point(LineartData *ld, LineartEdgeChain *ec, float *fbcoord, float *gpos, float *normal, - char type, + uint8_t type, int level, - unsigned char material_mask_bits, + uint8_t material_mask_bits, size_t index) { LineartEdgeChainItem *eci; @@ -138,7 +138,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb return ec->chain.first; } - eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem)); + eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem)); copy_v4_v4(eci->pos, fbcoord); copy_v3_v3(eci->gpos, gpos); @@ -152,14 +152,14 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb return eci; } -void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) +void MOD_lineart_chain_feature_lines(LineartData *ld) { LineartEdgeChain *ec; LineartEdgeChainItem *eci; LineartBoundingArea *ba; LineartEdgeSegment *es; int last_occlusion; - unsigned char last_transparency; + uint8_t last_transparency; /* Used when converting from double. */ float use_fbcoord[4]; float use_gpos[3]; @@ -181,7 +181,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED; - ec = lineart_chain_create(rb); + ec = lineart_chain_create(ld); /* One chain can only have one object_ref and intersection_mask, * so we assign them based on the first segment we found. */ @@ -207,11 +207,11 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) } /* Step 1: grow left. */ - ba = MOD_lineart_get_bounding_area(rb, e->v1->fbcoord[0], e->v1->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, e->v1->fbcoord[0], e->v1->fbcoord[1]); new_vt = e->v1; es = e->segments.first; VERT_COORD_TO_FLOAT(new_vt); - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -248,7 +248,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -274,7 +274,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -287,7 +287,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) last_transparency = es->material_mask_bits; } VERT_COORD_TO_FLOAT(new_e->v2); - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -297,7 +297,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) last_transparency, new_e->v2->index); } - ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]); } /* Restore normal value. */ @@ -328,7 +328,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at); use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -341,7 +341,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) last_transparency = es->material_mask_bits; } VERT_COORD_TO_FLOAT(e->v2) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -352,7 +352,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) e->v2->index); /* Step 3: grow right. */ - ba = MOD_lineart_get_bounding_area(rb, e->v2->fbcoord[0], e->v2->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, e->v2->fbcoord[0], e->v2->fbcoord[1]); new_vt = e->v2; while (ba && (new_e = lineart_line_get_connected( ba, new_vt, &new_vt, e->flags, e->intersection_mask))) { @@ -394,7 +394,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) last_occlusion = es->prev ? es->prev->occlusion : last_occlusion; last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency; POS_TO_FLOAT(lpos, gpos) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -420,7 +420,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -433,7 +433,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) last_transparency = es->material_mask_bits; } VERT_COORD_TO_FLOAT(new_e->v2) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -443,9 +443,9 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) last_transparency, new_e->v2->index); } - ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]); } - if (rb->fuzzy_everything) { + if (ld->conf.fuzzy_everything) { ec->type = LRT_EDGE_FLAG_CONTOUR; } else { @@ -455,7 +455,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) LRT_ITER_ALL_LINES_END } -static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRenderBuffer *rb, +static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartData *ld, LineartBoundingArea *root, LineartEdgeChainItem *eci) { @@ -468,32 +468,32 @@ static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRende ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1] if (IN_BOUND(ch[0], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[0], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[0], eci); } if (IN_BOUND(ch[1], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[1], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[1], eci); } if (IN_BOUND(ch[2], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[2], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[2], eci); } if (IN_BOUND(ch[3], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[3], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[3], eci); } #undef IN_BOUND return NULL; } -static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuffer *rb, +static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartData *ld, LineartEdgeChainItem *eci) { if (!eci) { return NULL; } - LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(rb, eci->pos[0], eci->pos[1]); + LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(ld, eci->pos[0], eci->pos[1]); if (root == NULL) { return NULL; } - return lineart_bounding_area_get_eci_recursive(rb, root, eci); + return lineart_bounding_area_get_eci_recursive(ld, root, eci); } /** @@ -502,14 +502,14 @@ static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuf * areas, this happens either when 1) the geometry is way too dense, or 2) the chaining threshold * is too big that it covers multiple small bounding areas. */ -static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb, +static void lineart_bounding_area_link_point_recursive(LineartData *ld, LineartBoundingArea *root, LineartEdgeChain *ec, LineartEdgeChainItem *eci) { if (root->child == NULL) { LineartChainRegisterEntry *cre = lineart_list_append_pointer_pool_sized( - &root->linked_chains, &rb->render_data_pool, ec, sizeof(LineartChainRegisterEntry)); + &root->linked_chains, &ld->render_data_pool, ec, sizeof(LineartChainRegisterEntry)); cre->eci = eci; @@ -524,34 +524,34 @@ static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb, ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1] if (IN_BOUND(ch[0], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[0], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[0], ec, eci); } else if (IN_BOUND(ch[1], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[1], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[1], ec, eci); } else if (IN_BOUND(ch[2], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[2], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[2], ec, eci); } else if (IN_BOUND(ch[3], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[3], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[3], ec, eci); } #undef IN_BOUND } } -static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdgeChain *ec) +static void lineart_bounding_area_link_chain(LineartData *ld, LineartEdgeChain *ec) { LineartEdgeChainItem *pl = ec->chain.first; LineartEdgeChainItem *pr = ec->chain.last; - LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(rb, pl->pos[0], pl->pos[1]); - LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(rb, pr->pos[0], pr->pos[1]); + LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(ld, pl->pos[0], pl->pos[1]); + LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(ld, pr->pos[0], pr->pos[1]); if (ba1) { - lineart_bounding_area_link_point_recursive(rb, ba1, ec, pl); + lineart_bounding_area_link_point_recursive(ld, ba1, ec, pl); } if (ba2) { - lineart_bounding_area_link_point_recursive(rb, ba2, ec, pr); + lineart_bounding_area_link_point_recursive(ld, ba2, ec, pr); } } @@ -564,7 +564,7 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, float dist_accum = 0; int fixed_occ = last_matching_eci->occlusion; - unsigned char fixed_mask = last_matching_eci->material_mask_bits; + uint8_t fixed_mask = last_matching_eci->material_mask_bits; LineartEdgeChainItem *can_skip_to = NULL; LineartEdgeChainItem *last_eci = last_matching_eci; @@ -606,28 +606,28 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, return false; } -void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) +void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld) { LineartEdgeChain *ec, *new_ec; LineartEdgeChainItem *eci, *next_eci; ListBase swap = {0}; - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; int loop_id = 0; while ((ec = BLI_pophead(&swap)) != NULL) { ec->next = ec->prev = NULL; - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); ec->loop_id = loop_id; loop_id++; LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first; int fixed_occ = first_eci->occlusion; - unsigned char fixed_mask = first_eci->material_mask_bits; + uint8_t fixed_mask = first_eci->material_mask_bits; ec->level = fixed_occ; ec->material_mask_bits = fixed_mask; for (eci = first_eci->next; eci; eci = next_eci) { @@ -639,8 +639,8 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) } if (lineart_chain_fix_ambiguous_segments(ec, eci->prev, - rb->chaining_image_threshold, - rb->chain_preserve_details, + ld->conf.chaining_image_threshold, + ld->conf.chain_preserve_details, &next_eci)) { continue; } @@ -653,7 +653,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) /* No need to split at the last point anyway. */ break; } - new_ec = lineart_chain_create(rb); + new_ec = lineart_chain_create(ld); new_ec->chain.first = eci; new_ec->chain.last = ec->chain.last; new_ec->loop_id = loop_id; @@ -662,7 +662,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) eci->prev = 0; /* End the previous one. */ - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, eci->pos, eci->gpos, @@ -683,16 +683,16 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) } } /* Get rid of those very short "zig-zag" lines that jumps around visibility. */ - MOD_lineart_chain_discard_short(rb, DBL_EDGE_LIM); - LISTBASE_FOREACH (LineartEdgeChain *, iec, &rb->chains) { - lineart_bounding_area_link_chain(rb, iec); + MOD_lineart_chain_discard_short(ld, DBL_EDGE_LIM); + LISTBASE_FOREACH (LineartEdgeChain *, iec, &ld->chains) { + lineart_bounding_area_link_chain(ld, iec); } } /** * NOTE: segment type (crease/material/contour...) is ambiguous after this. */ -static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb), +static void lineart_chain_connect(LineartData *UNUSED(ld), LineartEdgeChain *onto, LineartEdgeChain *sub, int reverse_1, @@ -742,13 +742,13 @@ static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb), } } -static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuffer *rb, +static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld, LineartBoundingArea *ba, LineartEdgeChain *ec, LineartEdgeChainItem *eci, int occlusion, - unsigned char material_mask_bits, - unsigned char isec_mask, + uint8_t material_mask_bits, + uint8_t isec_mask, int loop_id, float dist, float *result_new_len, @@ -761,8 +761,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf * next one. */ LISTBASE_FOREACH_MUTABLE (LineartChainRegisterEntry *, cre, &ba->linked_chains) { if (cre->ec->object_ref != ec->object_ref) { - if (!rb->fuzzy_everything) { - if (rb->fuzzy_intersections) { + if (!ld->conf.fuzzy_everything) { + if (ld->conf.fuzzy_intersections) { /* If none of those are intersection lines... */ if ((!(cre->ec->type & LRT_EDGE_FLAG_INTERSECTION)) && (!(ec->type & LRT_EDGE_FLAG_INTERSECTION))) { @@ -782,9 +782,9 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf (cre->ec->intersection_mask != isec_mask)) { continue; } - if (!rb->fuzzy_everything) { + if (!ld->conf.fuzzy_everything) { if (cre->ec->type != ec->type) { - if (rb->fuzzy_intersections) { + if (ld->conf.fuzzy_intersections) { if (!(cre->ec->type == LRT_EDGE_FLAG_INTERSECTION || ec->type == LRT_EDGE_FLAG_INTERSECTION)) { continue; /* Fuzzy intersections but no intersection line found. */ @@ -796,8 +796,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf } } - float new_len = rb->use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) : - len_v2v2(cre->eci->pos, eci->pos); + float new_len = ld->conf.use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) : + len_v2v2(cre->eci->pos, eci->pos); /* Even if the vertex is not from the same contour loop, we try to chain it still if the * distance is small enough. This way we can better chain smaller loops and smooth them out * later. */ @@ -817,9 +817,9 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf #define LRT_TEST_ADJACENT_AREAS(dist_to, list) \ if (dist_to < dist && dist_to > 0) { \ - LISTBASE_FOREACH (LinkData *, ld, list) { \ - LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \ - adjacent_closest = lineart_chain_get_closest_cre(rb, \ + LISTBASE_FOREACH (LinkData *, link, list) { \ + LineartBoundingArea *sba = (LineartBoundingArea *)link->data; \ + adjacent_closest = lineart_chain_get_closest_cre(ld, \ sba, \ ec, \ eci, \ @@ -848,36 +848,36 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf return closest_cre; } -void MOD_lineart_chain_connect(LineartRenderBuffer *rb) +void MOD_lineart_chain_connect(LineartData *ld) { LineartEdgeChain *ec; LineartEdgeChainItem *eci_l, *eci_r; LineartBoundingArea *ba_l, *ba_r; LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre; - float dist = rb->chaining_image_threshold; + float dist = ld->conf.chaining_image_threshold; float dist_l, dist_r; int occlusion, reverse_main, loop_id; - unsigned char material_mask_bits, isec_mask; + uint8_t material_mask_bits, isec_mask; ListBase swap = {0}; - if (rb->chaining_image_threshold < 0.0001) { + if (ld->conf.chaining_image_threshold < 0.0001) { return; } - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; while ((ec = BLI_pophead(&swap)) != NULL) { ec->next = ec->prev = NULL; if (ec->picked) { continue; } - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); loop_id = ec->loop_id; - if (ec->type == LRT_EDGE_FLAG_LOOSE && (!rb->use_loose_edge_chain)) { + if (ec->type == LRT_EDGE_FLAG_LOOSE && (!ld->conf.use_loose_edge_chain)) { continue; } @@ -887,9 +887,9 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb) eci_l = ec->chain.first; eci_r = ec->chain.last; - while ((ba_l = lineart_bounding_area_get_end_point(rb, eci_l)) && - (ba_r = lineart_bounding_area_get_end_point(rb, eci_r))) { - closest_cre_l = lineart_chain_get_closest_cre(rb, + while ((ba_l = lineart_bounding_area_get_end_point(ld, eci_l)) && + (ba_r = lineart_bounding_area_get_end_point(ld, eci_r))) { + closest_cre_l = lineart_chain_get_closest_cre(ld, ba_l, ec, eci_l, @@ -900,7 +900,7 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb) dist, &dist_l, NULL); - closest_cre_r = lineart_chain_get_closest_cre(rb, + closest_cre_r = lineart_chain_get_closest_cre(ld, ba_r, ec, eci_r, @@ -936,10 +936,10 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb) closest_cre->picked = 1; closest_cre->ec->picked = 1; if (closest_cre->is_left) { - lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 0); + lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 0); } else { - lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 1); + lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 1); } BLI_remlink(&swap, closest_cre->ec); eci_l = ec->chain.first; @@ -969,13 +969,13 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec) return offset_accum; } -void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold) +void MOD_lineart_chain_discard_short(LineartData *ld, const float threshold) { LineartEdgeChain *ec, *next_ec; - for (ec = rb->chains.first; ec; ec = next_ec) { + for (ec = ld->chains.first; ec; ec = next_ec) { next_ec = ec->next; if (MOD_lineart_chain_compute_length(ec) < threshold) { - BLI_remlink(&rb->chains, ec); + BLI_remlink(&ld->chains, ec); } } } @@ -999,9 +999,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc) } } -void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) +void MOD_lineart_smooth_chains(LineartData *ld, float tolerance) { - LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { /* Go through the chain two times, once from each direction. */ for (int times = 0; times < 2; times++) { for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci; @@ -1067,7 +1067,7 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) } } -static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb, +static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartData *ld, LineartEdgeChainItem *eci_inside, LineartEdgeChainItem *eci_outside) { @@ -1097,7 +1097,7 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu ratiof(eci1->pos[1], eci2->pos[1], isec[1]); float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]); - LineartEdgeChainItem *eci = lineart_mem_acquire(rb->chain_data_pool, + LineartEdgeChainItem *eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem)); memcpy(eci, eci1, sizeof(LineartEdgeChainItem)); interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio); @@ -1111,16 +1111,16 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu ((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \ (eci)->pos[1] <= 1.0f) -void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) +void MOD_lineart_chain_clip_at_border(LineartData *ld) { LineartEdgeChain *ec; LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci; bool is_inside, new_inside; ListBase swap = {0}; - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; while ((ec = BLI_pophead(&swap)) != NULL) { bool ec_added = false; LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first; @@ -1137,9 +1137,9 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) { if (new_inside == false) { /* Stroke goes out. */ - new_eci = lineart_chain_create_crossing_point(rb, prev_eci, eci); + new_eci = lineart_chain_create_crossing_point(ld, prev_eci, eci); - LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool, + LineartEdgeChain *new_ec = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChain)); memcpy(new_ec, ec, sizeof(LineartEdgeChain)); new_ec->chain.first = next_eci; @@ -1147,7 +1147,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) prev_eci->next = NULL; ec->chain.last = prev_eci; BLI_addtail(&ec->chain, new_eci); - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); ec_added = true; ec = new_ec; @@ -1156,7 +1156,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) continue; } /* Stroke comes in. */ - new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci); + new_eci = lineart_chain_create_crossing_point(ld, eci, prev_eci); ec->chain.first = eci; eci->prev = NULL; @@ -1172,25 +1172,25 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) } if ((!ec_added) && is_inside) { - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); } } } -void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad) +void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad) { LineartEdgeChain *ec, *new_ec; LineartEdgeChainItem *eci, *next_eci, *prev_eci; ListBase swap = {0}; - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; while ((ec = BLI_pophead(&swap)) != NULL) { ec->next = ec->prev = NULL; - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first; for (eci = first_eci->next; eci; eci = next_eci) { next_eci = eci->next; @@ -1203,7 +1203,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol break; /* No need to split at the last point anyway. */ } if (angle < angle_threshold_rad) { - new_ec = lineart_chain_create(rb); + new_ec = lineart_chain_create(ld); new_ec->chain.first = eci; new_ec->chain.last = ec->chain.last; ec->chain.last = eci->prev; @@ -1211,7 +1211,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol eci->prev = 0; /* End the previous one. */ - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, eci->pos, eci->gpos, @@ -1232,40 +1232,37 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol } } -void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, - float dist, - bool use_custom_camera) +void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera) { float dir[3]; float cam[3]; float view[3]; float view_clamp[3]; - copy_v3fl_v3db(cam, rb->camera_pos); - copy_v3fl_v3db(view, rb->view_vector); if (use_custom_camera) { - copy_v3fl_v3db(cam, rb->camera_pos); + copy_v3fl_v3db(cam, ld->conf.camera_pos); } else { - copy_v3fl_v3db(cam, rb->active_camera_pos); + copy_v3fl_v3db(cam, ld->conf.active_camera_pos); } - if (rb->cam_is_persp) { - LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + if (ld->conf.cam_is_persp) { + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { sub_v3_v3v3(dir, cam, eci->gpos); float orig_len = len_v3(dir); normalize_v3(dir); - mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip)); + mul_v3_fl(dir, MIN2(dist, orig_len - ld->conf.near_clip)); add_v3_v3(eci->gpos, dir); } } } else { - LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + copy_v3fl_v3db(view, ld->conf.view_vector); + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { sub_v3_v3v3(dir, cam, eci->gpos); - float len_lim = dot_v3v3(view, dir) - rb->near_clip; + float len_lim = dot_v3v3(view, dir) - ld->conf.near_clip; normalize_v3_v3(view_clamp, view); mul_v3_fl(view_clamp, MIN2(dist, len_lim)); add_v3_v3(eci->gpos, view_clamp); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 016b70cedb0..c7b2104a6e6 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -46,16 +46,41 @@ #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" -#include "bmesh.h" -#include "bmesh_class.h" -#include "bmesh_tools.h" - #include "lineart_intern.h" -static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb, - LineartEdge *e); +typedef struct LineartIsecSingle { + float v1[3], v2[3]; + LineartTriangle *tri1, *tri2; +} LineartIsecSingle; + +typedef struct LineartIsecThread { + int thread_id; + + /* Scheduled work range. */ + LineartElementLinkNode *pending_from; + LineartElementLinkNode *pending_to; + int index_from; + int index_to; + + /* Thread intersection result data. */ + LineartIsecSingle *array; + int current; + int max; + int count_test; -static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb, + /* For individual thread reference.*/ + LineartData *ld; +} LineartIsecThread; + +typedef struct LineartIsecData { + LineartData *ld; + LineartIsecThread *threads; + int thread_count; +} LineartIsecData; + +static LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, LineartEdge *e); + +static void lineart_bounding_area_link_edge(LineartData *ld, LineartBoundingArea *root_ba, LineartEdge *e); @@ -69,20 +94,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this double *next_x, double *next_y); -static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb, - LineartEdge *e, - int *rowbegin, - int *rowend, - int *colbegin, - int *colend); - -static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb, - LineartBoundingArea *root_ba, - LineartTriangle *tri, - double *LRUB, - int recursive, - int recursive_level, - bool do_intersection); +static bool lineart_get_edge_bounding_areas( + LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend); static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl, const LineartTriangle *tri, @@ -99,52 +112,65 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl, static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e); +static void lineart_bounding_area_link_triangle(LineartData *ld, + LineartBoundingArea *root_ba, + LineartTriangle *tri, + double *LRUB, + int recursive, + int recursive_level, + bool do_intersection, + struct LineartIsecThread *th); + +static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive); + +static void lineart_free_bounding_area_memories(LineartData *ld); + static LineartCache *lineart_init_cache(void); -static void lineart_discard_segment(LineartRenderBuffer *rb, LineartEdgeSegment *es) +static void lineart_discard_segment(LineartData *ld, LineartEdgeSegment *es) { - BLI_spin_lock(&rb->lock_cuts); + BLI_spin_lock(&ld->lock_cuts); memset(es, 0, sizeof(LineartEdgeSegment)); /* Storing the node for potentially reuse the memory for new segment data. * Line Art data is not freed after all calculations are done. */ - BLI_addtail(&rb->wasted_cuts, es); + BLI_addtail(&ld->wasted_cuts, es); - BLI_spin_unlock(&rb->lock_cuts); + BLI_spin_unlock(&ld->lock_cuts); } -static LineartEdgeSegment *lineart_give_segment(LineartRenderBuffer *rb) +static LineartEdgeSegment *lineart_give_segment(LineartData *ld) { - BLI_spin_lock(&rb->lock_cuts); + BLI_spin_lock(&ld->lock_cuts); /* See if there is any already allocated memory we can reuse. */ - if (rb->wasted_cuts.first) { - LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&rb->wasted_cuts); - BLI_spin_unlock(&rb->lock_cuts); + if (ld->wasted_cuts.first) { + LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&ld->wasted_cuts); + BLI_spin_unlock(&ld->lock_cuts); memset(es, 0, sizeof(LineartEdgeSegment)); return es; } - BLI_spin_unlock(&rb->lock_cuts); + BLI_spin_unlock(&ld->lock_cuts); /* Otherwise allocate some new memory. */ - return (LineartEdgeSegment *)lineart_mem_acquire_thread(&rb->render_data_pool, + return (LineartEdgeSegment *)lineart_mem_acquire_thread(&ld->render_data_pool, sizeof(LineartEdgeSegment)); } /** * Cuts the edge in image space and mark occlusion level for each segment. */ -static void lineart_edge_cut(LineartRenderBuffer *rb, +static void lineart_edge_cut(LineartData *ld, LineartEdge *e, double start, double end, uchar material_mask_bits, uchar mat_occlusion) { - LineartEdgeSegment *es, *ies, *next_es, *prev_es; + LineartEdgeSegment *seg, *i_seg, *next_seg, *prev_seg; LineartEdgeSegment *cut_start_before = 0, *cut_end_before = 0; - LineartEdgeSegment *ns = 0, *ns2 = 0; + LineartEdgeSegment *new_seg1 = 0, *new_seg2 = 0; int untouched = 0; /* If for some reason the occlusion function may give a result that has zero length, or reversed @@ -171,132 +197,136 @@ static void lineart_edge_cut(LineartRenderBuffer *rb, /* Begin looking for starting position of the segment. */ /* Not using a list iteration macro because of it more clear when using for loops to iterate * through the segments. */ - for (es = e->segments.first; es; es = es->next) { - if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, start)) { - cut_start_before = es; - ns = cut_start_before; + for (seg = e->segments.first; seg; seg = seg->next) { + if (LRT_DOUBLE_CLOSE_ENOUGH(seg->at, start)) { + cut_start_before = seg; + new_seg1 = cut_start_before; break; } - if (es->next == NULL) { + if (seg->next == NULL) { break; } - ies = es->next; - if (ies->at > start + 1e-09 && start > es->at) { - cut_start_before = ies; - ns = lineart_give_segment(rb); + i_seg = seg->next; + if (i_seg->at > start + 1e-09 && start > seg->at) { + cut_start_before = i_seg; + new_seg1 = lineart_give_segment(ld); break; } } if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) { untouched = 1; } - for (es = cut_start_before; es; es = es->next) { + for (seg = cut_start_before; seg; seg = seg->next) { /* We tried to cut at existing cutting point (e.g. where the line's occluded by a triangle * strip). */ - if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, end)) { - cut_end_before = es; - ns2 = cut_end_before; + if (LRT_DOUBLE_CLOSE_ENOUGH(seg->at, end)) { + cut_end_before = seg; + new_seg2 = cut_end_before; break; } /* This check is to prevent `es->at == 1.0` (where we don't need to cut because we are at the * end point). */ - if (!es->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) { - cut_end_before = es; - ns2 = cut_end_before; + if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) { + cut_end_before = seg; + new_seg2 = cut_end_before; untouched = 1; break; } /* When an actual cut is needed in the line. */ - if (es->at > end) { - cut_end_before = es; - ns2 = lineart_give_segment(rb); + if (seg->at > end) { + cut_end_before = seg; + new_seg2 = lineart_give_segment(ld); break; } } /* When we still can't find any existing cut in the line, we allocate new ones. */ - if (ns == NULL) { - ns = lineart_give_segment(rb); + if (new_seg1 == NULL) { + new_seg1 = lineart_give_segment(ld); } - if (ns2 == NULL) { + if (new_seg2 == NULL) { if (untouched) { - ns2 = ns; - cut_end_before = ns2; + new_seg2 = new_seg1; + cut_end_before = new_seg2; } else { - ns2 = lineart_give_segment(rb); + new_seg2 = lineart_give_segment(ld); } } if (cut_start_before) { - if (cut_start_before != ns) { + if (cut_start_before != new_seg1) { /* Insert cutting points for when a new cut is needed. */ - ies = cut_start_before->prev ? cut_start_before->prev : NULL; - ns->occlusion = ies ? ies->occlusion : 0; - ns->material_mask_bits = ies->material_mask_bits; - BLI_insertlinkbefore(&e->segments, cut_start_before, ns); + i_seg = cut_start_before->prev ? cut_start_before->prev : NULL; + if (i_seg) { + new_seg1->occlusion = i_seg->occlusion; + new_seg1->material_mask_bits = i_seg->material_mask_bits; + } + BLI_insertlinkbefore(&e->segments, cut_start_before, new_seg1); } /* Otherwise we already found a existing cutting point, no need to insert a new one. */ } else { /* We have yet to reach a existing cutting point even after we searched the whole line, so we * append the new cut to the end. */ - ies = e->segments.last; - ns->occlusion = ies->occlusion; - ns->material_mask_bits = ies->material_mask_bits; - BLI_addtail(&e->segments, ns); + i_seg = e->segments.last; + new_seg1->occlusion = i_seg->occlusion; + new_seg1->material_mask_bits = i_seg->material_mask_bits; + BLI_addtail(&e->segments, new_seg1); } if (cut_end_before) { /* The same manipulation as on "cut_start_before". */ - if (cut_end_before != ns2) { - ies = cut_end_before->prev ? cut_end_before->prev : NULL; - ns2->occlusion = ies ? ies->occlusion : 0; - ns2->material_mask_bits = ies ? ies->material_mask_bits : 0; - BLI_insertlinkbefore(&e->segments, cut_end_before, ns2); + if (cut_end_before != new_seg2) { + i_seg = cut_end_before->prev ? cut_end_before->prev : NULL; + if (i_seg) { + new_seg2->occlusion = i_seg->occlusion; + new_seg2->material_mask_bits = i_seg->material_mask_bits; + } + BLI_insertlinkbefore(&e->segments, cut_end_before, new_seg2); } } else { - ies = e->segments.last; - ns2->occlusion = ies->occlusion; - ns2->material_mask_bits = ies->material_mask_bits; - BLI_addtail(&e->segments, ns2); + i_seg = e->segments.last; + new_seg2->occlusion = i_seg->occlusion; + new_seg2->material_mask_bits = i_seg->material_mask_bits; + BLI_addtail(&e->segments, new_seg2); } /* If we touched the cut list, we assign the new cut position based on new cut position, * this way we accommodate precision lost due to multiple cut inserts. */ - ns->at = start; + new_seg1->at = start; if (!untouched) { - ns2->at = end; + new_seg2->at = end; } else { /* For the convenience of the loop below. */ - ns2 = ns2->next; + new_seg2 = new_seg2->next; } /* Register 1 level of occlusion for all touched segments. */ - for (es = ns; es && es != ns2; es = es->next) { - es->occlusion += mat_occlusion; - es->material_mask_bits |= material_mask_bits; + for (seg = new_seg1; seg && seg != new_seg2; seg = seg->next) { + seg->occlusion += mat_occlusion; + seg->material_mask_bits |= material_mask_bits; } /* Reduce adjacent cutting points of the same level, which saves memory. */ - char min_occ = 127; - prev_es = NULL; - for (es = e->segments.first; es; es = next_es) { - next_es = es->next; - - if (prev_es && prev_es->occlusion == es->occlusion && - prev_es->material_mask_bits == es->material_mask_bits) { - BLI_remlink(&e->segments, es); + int8_t min_occ = 127; + prev_seg = NULL; + for (seg = e->segments.first; seg; seg = next_seg) { + next_seg = seg->next; + + if (prev_seg && prev_seg->occlusion == seg->occlusion && + prev_seg->material_mask_bits == seg->material_mask_bits) { + BLI_remlink(&e->segments, seg); /* This puts the node back to the render buffer, if more cut happens, these unused nodes get * picked first. */ - lineart_discard_segment(rb, es); + lineart_discard_segment(ld, seg); continue; } - min_occ = MIN2(min_occ, es->occlusion); + min_occ = MIN2(min_occ, seg->occlusion); - prev_es = es; + prev_seg = seg; } e->min_occ = min_occ; } @@ -312,29 +342,14 @@ BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, Linea (v2->base.flag && v2->intersecting_with == tri)); } -static void lineart_bounding_area_triangle_add(LineartRenderBuffer *rb, - LineartBoundingArea *ba, - LineartTriangle *tri) -{ /* In case of too many triangles concentrating in one point, do not add anymore, these triangles - * will be either narrower than a single pixel, or will still be added into the list of other - * less dense areas. */ - if (ba->triangle_count >= 65535) { - return; - } - if (ba->triangle_count >= ba->max_triangle_count) { - LineartTriangle **new_array = lineart_mem_acquire( - &rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count * 2); - memcpy(new_array, ba->linked_triangles, sizeof(LineartTriangle *) * ba->max_triangle_count); - ba->max_triangle_count *= 2; - ba->linked_triangles = new_array; - } - ba->linked_triangles[ba->triangle_count] = tri; - ba->triangle_count++; +static void lineart_bounding_area_triangle_reallocate(LineartBoundingArea *ba) +{ + ba->max_triangle_count *= 2; + ba->linked_triangles = MEM_recallocN(ba->linked_triangles, + sizeof(LineartTriangle *) * ba->max_triangle_count); } -static void lineart_bounding_area_line_add(LineartRenderBuffer *rb, - LineartBoundingArea *ba, - LineartEdge *e) +static void lineart_bounding_area_line_add(LineartBoundingArea *ba, LineartEdge *e) { /* In case of too many lines concentrating in one point, do not add anymore, these lines will * be either shorter than a single pixel, or will still be added into the list of other less @@ -343,20 +358,21 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb, return; } if (ba->line_count >= ba->max_line_count) { - LineartEdge **new_array = lineart_mem_acquire(&rb->render_data_pool, - sizeof(LineartEdge *) * ba->max_line_count * 2); + LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * ba->max_line_count * 2, + "new ba_line_array"); memcpy(new_array, ba->linked_lines, sizeof(LineartEdge *) * ba->max_line_count); ba->max_line_count *= 2; + MEM_freeN(ba->linked_lines); ba->linked_lines = new_array; } ba->linked_lines[ba->line_count] = e; ba->line_count++; } -static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *e, int thread_id) +static void lineart_occlusion_single_line(LineartData *ld, LineartEdge *e, int thread_id) { double x = e->v1->fbcoord[0], y = e->v1->fbcoord[1]; - LineartBoundingArea *ba = lineart_edge_first_bounding_area(rb, e); + LineartBoundingArea *ba = lineart_edge_first_bounding_area(ld, e); LineartBoundingArea *nba = ba; LineartTriangleThread *tri; @@ -385,20 +401,20 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge * continue; } tri->testing_e[thread_id] = e; - if (lineart_triangle_edge_image_space_occlusion(&rb->lock_task, + if (lineart_triangle_edge_image_space_occlusion(&ld->lock_task, (const LineartTriangle *)tri, e, - rb->camera_pos, - rb->cam_is_persp, - rb->allow_overlapping_edges, - rb->view_projection, - rb->view_vector, - rb->shift_x, - rb->shift_y, + ld->conf.camera_pos, + ld->conf.cam_is_persp, + ld->conf.allow_overlapping_edges, + ld->conf.view_projection, + ld->conf.view_vector, + ld->conf.shift_x, + ld->conf.shift_y, &l, &r)) { - lineart_edge_cut(rb, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion); - if (e->min_occ > rb->max_occlusion_level) { + lineart_edge_cut(ld, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion); + if (e->min_occ > ld->conf.max_occlusion_level) { /* No need to calculate any longer on this line because no level more than set value is * going to show up in the rendered result. */ return; @@ -410,24 +426,24 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge * } } -static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRenderTaskInfo *rti) +static int lineart_occlusion_make_task_info(LineartData *ld, LineartRenderTaskInfo *rti) { int res = 0; int starting_index; - BLI_spin_lock(&rb->lock_task); + BLI_spin_lock(&ld->lock_task); - starting_index = rb->scheduled_count; - rb->scheduled_count += LRT_THREAD_EDGE_COUNT; + starting_index = ld->scheduled_count; + ld->scheduled_count += LRT_THREAD_EDGE_COUNT; - BLI_spin_unlock(&rb->lock_task); + BLI_spin_unlock(&ld->lock_task); - if (starting_index >= rb->pending_edges.next) { + if (starting_index >= ld->pending_edges.next) { res = 0; } else { - rti->pending_edges.array = &rb->pending_edges.array[starting_index]; - int remaining = rb->pending_edges.next - starting_index; + rti->pending_edges.array = &ld->pending_edges.array[starting_index]; + int remaining = ld->pending_edges.next - starting_index; rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT); res = 1; } @@ -437,13 +453,13 @@ static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRend static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartRenderTaskInfo *rti) { - LineartRenderBuffer *rb = rti->rb; + LineartData *ld = rti->ld; LineartEdge *eip; - while (lineart_occlusion_make_task_info(rb, rti)) { + while (lineart_occlusion_make_task_info(ld, rti)) { for (int i = 0; i < rti->pending_edges.max; i++) { eip = rti->pending_edges.array[i]; - lineart_occlusion_single_line(rb, eip, rti->thread_id); + lineart_occlusion_single_line(ld, eip, rti->thread_id); } } } @@ -453,9 +469,9 @@ static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartR * #MOD_lineart_compute_feature_lines function. * This function handles all occlusion calculation. */ -static void lineart_main_occlusion_begin(LineartRenderBuffer *rb) +static void lineart_main_occlusion_begin(LineartData *ld) { - int thread_count = rb->thread_count; + int thread_count = ld->thread_count; LineartRenderTaskInfo *rti = MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count, "Task Pool"); int i; @@ -464,7 +480,7 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb) for (i = 0; i < thread_count; i++) { rti[i].thread_id = i; - rti[i].rb = rb; + rti[i].ld = ld; BLI_task_pool_push(tp, (TaskRunFunction)lineart_occlusion_worker, &rti[i], 0, NULL); } BLI_task_pool_work_and_wait(tp); @@ -554,6 +570,12 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2] return 0; } +enum LineartPointTri { + LRT_OUTSIDE_TRIANGLE = 0, + LRT_ON_TRIANGLE = 1, + LRT_INSIDE_TRIANGLE = 2, +}; + /** * Same algorithm as lineart_point_inside_triangle(), but returns differently: * 0-outside 1-on the edge 2-inside. @@ -564,7 +586,7 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[ double r; if (lineart_point_on_line_segment(v, v0, v1) || lineart_point_on_line_segment(v, v1, v2) || lineart_point_on_line_segment(v, v2, v0)) { - return 1; + return LRT_ON_TRIANGLE; } cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]); @@ -572,28 +594,28 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[ cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]); if ((r = c * cl) < 0) { - return 0; + return LRT_OUTSIDE_TRIANGLE; } c = cl; cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]); if ((r = c * cl) < 0) { - return 0; + return LRT_OUTSIDE_TRIANGLE; } c = cl; cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]); if ((r = c * cl) < 0) { - return 0; + return LRT_OUTSIDE_TRIANGLE; } if (r == 0) { - return 1; + return LRT_ON_TRIANGLE; } - return 2; + return LRT_INSIDE_TRIANGLE; } /** @@ -641,17 +663,17 @@ static bool lineart_point_inside_triangle3d(double v[3], double v0[3], double v1 * The following `lineart_memory_get_XXX_space` functions are for allocating new memory for some * modified geometries in the culling stage. */ -static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBuffer *rb) +static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartData *ld) { LineartElementLinkNode *eln; /* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles * are relatively small. */ - LineartTriangle *render_triangles = lineart_mem_acquire(&rb->render_data_pool, - 64 * rb->triangle_size); + LineartTriangle *render_triangles = lineart_mem_acquire(&ld->render_data_pool, + 64 * ld->sizeof_triangle); - eln = lineart_list_append_pointer_pool_sized(&rb->triangle_buffer_pointers, - &rb->render_data_pool, + eln = lineart_list_append_pointer_pool_sized(&ld->geom.triangle_buffer_pointers, + &ld->render_data_pool, render_triangles, sizeof(LineartElementLinkNode)); eln->element_count = 64; @@ -660,15 +682,15 @@ static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBu return eln; } -static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer *rb) +static LineartElementLinkNode *lineart_memory_get_vert_space(LineartData *ld) { LineartElementLinkNode *eln; - LineartVert *render_vertices = lineart_mem_acquire(&rb->render_data_pool, + LineartVert *render_vertices = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartVert) * 64); - eln = lineart_list_append_pointer_pool_sized(&rb->vertex_buffer_pointers, - &rb->render_data_pool, + eln = lineart_list_append_pointer_pool_sized(&ld->geom.vertex_buffer_pointers, + &ld->render_data_pool, render_vertices, sizeof(LineartElementLinkNode)); eln->element_count = 64; @@ -677,18 +699,18 @@ static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer return eln; } -static LineartElementLinkNode *lineart_memory_get_edge_space(LineartRenderBuffer *rb) +static LineartElementLinkNode *lineart_memory_get_edge_space(LineartData *ld) { LineartElementLinkNode *eln; - LineartEdge *render_edges = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge) * 64); + LineartEdge *render_edges = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdge) * 64); - eln = lineart_list_append_pointer_pool_sized(&rb->line_buffer_pointers, - &rb->render_data_pool, + eln = lineart_list_append_pointer_pool_sized(&ld->geom.line_buffer_pointers, + &ld->render_data_pool, render_edges, sizeof(LineartElementLinkNode)); eln->element_count = 64; - eln->crease_threshold = rb->crease_threshold; + eln->crease_threshold = ld->conf.crease_threshold; eln->flags |= LRT_ELEMENT_IS_ADDITIONAL; return eln; @@ -699,6 +721,7 @@ static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig) /* Just re-assign normal and set cull flag. */ copy_v3_v3_db(tri->gn, orig->gn); tri->flags = LRT_CULL_GENERATED; + tri->intersection_mask = orig->intersection_mask; tri->material_mask_bits = orig->material_mask_bits; tri->mat_occlusion = orig->mat_occlusion; } @@ -729,7 +752,7 @@ static void lineart_discard_duplicated_edges(LineartEdge *old_e) * Does near-plane cut on 1 triangle only. When cutting with far-plane, the camera vectors gets * reversed by the caller so don't need to implement one in a different direction. */ -static void lineart_triangle_cull_single(LineartRenderBuffer *rb, +static void lineart_triangle_cull_single(LineartData *ld, LineartTriangle *tri, int in0, int in1, @@ -746,7 +769,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, LineartElementLinkNode *e_eln, LineartElementLinkNode *t_eln) { - double vv1[3], vv2[3], dot1, dot2; + double span_v1[3], span_v2[3], dot_v1, dot_v2; double a; int v_count = *r_v_count; int e_count = *r_e_count; @@ -755,7 +778,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, LineartEdge *new_e, *e, *old_e; LineartEdgeSegment *es; - LineartTriangleAdjacent *ta; + LineartTriangleAdjacent *tri_adj; if (tri->flags & (LRT_CULL_USED | LRT_CULL_GENERATED | LRT_CULL_DISCARD)) { return; @@ -763,11 +786,12 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, /* See definition of tri->intersecting_verts and the usage in * lineart_geometry_object_load() for details. */ - ta = (void *)tri->intersecting_verts; + tri_adj = (void *)tri->intersecting_verts; LineartVert *vt = &((LineartVert *)v_eln->pointer)[v_count]; - LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * t_count); - LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * (t_count + 1)); + LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * t_count); + LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) + + ld->sizeof_triangle * (t_count + 1)); new_e = &((LineartEdge *)e_eln->pointer)[e_count]; /* Init `edge` to the last `edge` entry. */ @@ -777,12 +801,12 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, new_e = &((LineartEdge *)e_eln->pointer)[e_count]; \ e_count++; \ e = new_e; \ - es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment)); \ + es = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdgeSegment)); \ BLI_addtail(&e->segments, es); #define SELECT_EDGE(e_num, v1_link, v2_link, new_tri) \ - if (ta->e[e_num]) { \ - old_e = ta->e[e_num]; \ + if (tri_adj->e[e_num]) { \ + old_e = tri_adj->e[e_num]; \ new_flag = old_e->flags; \ old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ lineart_discard_duplicated_edges(old_e); \ @@ -795,28 +819,28 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, e->object_ref = ob; \ e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \ e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \ - lineart_add_edge_to_array(&rb->pending_edges, e); \ + lineart_add_edge_to_array(&ld->pending_edges, e); \ } #define RELINK_EDGE(e_num, new_tri) \ - if (ta->e[e_num]) { \ - old_e = ta->e[e_num]; \ + if (tri_adj->e[e_num]) { \ + old_e = tri_adj->e[e_num]; \ old_e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \ old_e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \ } #define REMOVE_TRIANGLE_EDGE \ - if (ta->e[0]) { \ - ta->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ - lineart_discard_duplicated_edges(ta->e[0]); \ + if (tri_adj->e[0]) { \ + tri_adj->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ + lineart_discard_duplicated_edges(tri_adj->e[0]); \ } \ - if (ta->e[1]) { \ - ta->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ - lineart_discard_duplicated_edges(ta->e[1]); \ + if (tri_adj->e[1]) { \ + tri_adj->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ + lineart_discard_duplicated_edges(tri_adj->e[1]); \ } \ - if (ta->e[2]) { \ - ta->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ - lineart_discard_duplicated_edges(ta->e[2]); \ + if (tri_adj->e[2]) { \ + tri_adj->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ + lineart_discard_duplicated_edges(tri_adj->e[2]); \ } switch (in0 + in1 + in2) { @@ -856,22 +880,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, if (!in0) { /* Cut point for line 2---|-----0. */ - sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); /* Assign it to a new point. */ interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a); mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc); vt[0].index = tri->v[2]->index; /* Cut point for line 1---|-----0. */ - sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); /* Assign it to another new point. */ interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a); mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc); @@ -881,7 +905,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, INCREASE_EDGE if (allow_boundaries) { e->flags = LRT_EDGE_FLAG_CONTOUR; - lineart_add_edge_to_array(&rb->pending_edges, e); + lineart_add_edge_to_array(&ld->pending_edges, e); } /* NOTE: inverting `e->v1/v2` (left/right point) doesn't matter as long as * `tri->edge` and `tri->v` has the same sequence. and the winding direction @@ -909,20 +933,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, t_count += 1; } else if (!in2) { - sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a); mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc); vt[0].index = tri->v[0]->index; - sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a); mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc); vt[1].index = tri->v[1]->index; @@ -930,7 +954,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, INCREASE_EDGE if (allow_boundaries) { e->flags = LRT_EDGE_FLAG_CONTOUR; - lineart_add_edge_to_array(&rb->pending_edges, e); + lineart_add_edge_to_array(&ld->pending_edges, e); } e->v1 = &vt[0]; e->v2 = &vt[1]; @@ -950,20 +974,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, t_count += 1; } else if (!in1) { - sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a); mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc); vt[0].index = tri->v[2]->index; - sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a); mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc); vt[1].index = tri->v[0]->index; @@ -971,7 +995,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, INCREASE_EDGE if (allow_boundaries) { e->flags = LRT_EDGE_FLAG_CONTOUR; - lineart_add_edge_to_array(&rb->pending_edges, e); + lineart_add_edge_to_array(&ld->pending_edges, e); } e->v1 = &vt[1]; e->v2 = &vt[0]; @@ -1021,22 +1045,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, */ if (in0) { /* Cut point for line 0---|------1. */ - sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot2 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v2 / (dot_v1 + dot_v2); /* Assign to a new point. */ interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a); mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc); vt[0].index = tri->v[0]->index; /* Cut point for line 0---|------2. */ - sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot2 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v2 / (dot_v1 + dot_v2); /* Assign to other new point. */ interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a); mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc); @@ -1046,7 +1070,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, INCREASE_EDGE if (allow_boundaries) { e->flags = LRT_EDGE_FLAG_CONTOUR; - lineart_add_edge_to_array(&rb->pending_edges, e); + lineart_add_edge_to_array(&ld->pending_edges, e); } e->v1 = &vt[1]; e->v2 = &vt[0]; @@ -1077,20 +1101,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, } else if (in1) { - sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a); mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc); vt[0].index = tri->v[1]->index; - sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a); mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc); vt[1].index = tri->v[1]->index; @@ -1098,7 +1122,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, INCREASE_EDGE if (allow_boundaries) { e->flags = LRT_EDGE_FLAG_CONTOUR; - lineart_add_edge_to_array(&rb->pending_edges, e); + lineart_add_edge_to_array(&ld->pending_edges, e); } e->v1 = &vt[1]; e->v2 = &vt[0]; @@ -1126,20 +1150,20 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, } else if (in2) { - sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a); mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc); vt[0].index = tri->v[2]->index; - sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos); - sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc); - dot1 = dot_v3v3_db(vv1, view_dir); - dot2 = dot_v3v3_db(vv2, view_dir); - a = dot1 / (dot1 + dot2); + sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos); + sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc); + dot_v1 = dot_v3v3_db(span_v1, view_dir); + dot_v2 = dot_v3v3_db(span_v2, view_dir); + a = dot_v1 / (dot_v1 + dot_v2); interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a); mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc); vt[1].index = tri->v[2]->index; @@ -1147,7 +1171,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, INCREASE_EDGE if (allow_boundaries) { e->flags = LRT_EDGE_FLAG_CONTOUR; - lineart_add_edge_to_array(&rb->pending_edges, e); + lineart_add_edge_to_array(&ld->pending_edges, e); } e->v1 = &vt[1]; e->v2 = &vt[0]; @@ -1191,22 +1215,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb, * new topology that represents the trimmed triangle. (which then became a triangle or a square * formed by two triangles) */ -static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far) +static void lineart_main_cull_triangles(LineartData *ld, bool clip_far) { LineartTriangle *tri; LineartElementLinkNode *v_eln, *t_eln, *e_eln; - double(*vp)[4] = rb->view_projection; + double(*vp)[4] = ld->conf.view_projection; int i; int v_count = 0, t_count = 0, e_count = 0; Object *ob; - bool allow_boundaries = rb->allow_boundaries; + bool allow_boundaries = ld->conf.allow_boundaries; double cam_pos[3]; - double clip_start = rb->near_clip, clip_end = rb->far_clip; + double clip_start = ld->conf.near_clip, clip_end = ld->conf.far_clip; double view_dir[3], clip_advance[3]; - copy_v3_v3_db(view_dir, rb->view_vector); - copy_v3_v3_db(clip_advance, rb->view_vector); - copy_v3_v3_db(cam_pos, rb->camera_pos); + copy_v3_v3_db(view_dir, ld->conf.view_vector); + copy_v3_v3_db(clip_advance, ld->conf.view_vector); + copy_v3_v3_db(cam_pos, ld->conf.camera_pos); if (clip_far) { /* Move starting point to end plane. */ @@ -1222,25 +1246,25 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far) add_v3_v3_db(cam_pos, clip_advance); } - v_eln = lineart_memory_get_vert_space(rb); - t_eln = lineart_memory_get_triangle_space(rb); - e_eln = lineart_memory_get_edge_space(rb); + v_eln = lineart_memory_get_vert_space(ld); + t_eln = lineart_memory_get_triangle_space(ld); + e_eln = lineart_memory_get_edge_space(ld); /* Additional memory space for storing generated points and triangles. */ #define LRT_CULL_ENSURE_MEMORY \ if (v_count > 60) { \ v_eln->element_count = v_count; \ - v_eln = lineart_memory_get_vert_space(rb); \ + v_eln = lineart_memory_get_vert_space(ld); \ v_count = 0; \ } \ if (t_count > 60) { \ t_eln->element_count = t_count; \ - t_eln = lineart_memory_get_triangle_space(rb); \ + t_eln = lineart_memory_get_triangle_space(ld); \ t_count = 0; \ } \ if (e_count > 60) { \ e_eln->element_count = e_count; \ - e_eln = lineart_memory_get_edge_space(rb); \ + e_eln = lineart_memory_get_edge_space(ld); \ e_count = 0; \ } @@ -1275,21 +1299,21 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far) int use_w = 3; int in0 = 0, in1 = 0, in2 = 0; - if (!rb->cam_is_persp) { + if (!ld->conf.cam_is_persp) { clip_start = -1; clip_end = 1; use_w = 2; } /* Then go through all the other triangles. */ - LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) { + LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) { if (eln->flags & LRT_ELEMENT_IS_ADDITIONAL) { continue; } ob = eln->object_ref; for (i = 0; i < eln->element_count; i++) { /* Select the triangle in the array. */ - tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i); + tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * i); if (tri->flags & LRT_CULL_DISCARD) { continue; @@ -1297,7 +1321,7 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far) LRT_CULL_DECIDE_INSIDE LRT_CULL_ENSURE_MEMORY - lineart_triangle_cull_single(rb, + lineart_triangle_cull_single(ld, tri, in0, in1, @@ -1326,33 +1350,33 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far) * Adjacent data is only used during the initial stages of computing. * So we can free it using this function when it is not needed anymore. */ -static void lineart_main_free_adjacent_data(LineartRenderBuffer *rb) +static void lineart_main_free_adjacent_data(LineartData *ld) { - LinkData *ld; - while ((ld = BLI_pophead(&rb->triangle_adjacent_pointers)) != NULL) { - MEM_freeN(ld->data); + LinkData *link; + while ((link = BLI_pophead(&ld->geom.triangle_adjacent_pointers)) != NULL) { + MEM_freeN(link->data); } - LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) { + LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) { LineartTriangle *tri = eln->pointer; int i; for (i = 0; i < eln->element_count; i++) { /* See definition of tri->intersecting_verts and the usage in * lineart_geometry_object_load() for detailed. */ tri->intersecting_verts = NULL; - tri = (LineartTriangle *)(((uchar *)tri) + rb->triangle_size); + tri = (LineartTriangle *)(((uchar *)tri) + ld->sizeof_triangle); } } } -static void lineart_main_perspective_division(LineartRenderBuffer *rb) +static void lineart_main_perspective_division(LineartData *ld) { LineartVert *vt; int i; - LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->vertex_buffer_pointers) { + LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.vertex_buffer_pointers) { vt = eln->pointer; for (i = 0; i < eln->element_count; i++) { - if (rb->cam_is_persp) { + if (ld->conf.cam_is_persp) { /* Do not divide Z, we use Z to back transform cut points in later chaining process. */ vt[i].fbcoord[0] /= vt[i].fbcoord[3]; vt[i].fbcoord[1] /= vt[i].fbcoord[3]; @@ -1363,13 +1387,13 @@ static void lineart_main_perspective_division(LineartRenderBuffer *rb) // `vt[i].fbcoord[2] = -2 * vt[i].fbcoord[2] / (far - near) - (far + near) / (far - near); } /* Shifting is always needed. */ - vt[i].fbcoord[0] -= rb->shift_x * 2; - vt[i].fbcoord[1] -= rb->shift_y * 2; + vt[i].fbcoord[0] -= ld->conf.shift_x * 2; + vt[i].fbcoord[1] -= ld->conf.shift_y * 2; } } } -static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb) +static void lineart_main_discard_out_of_frame_edges(LineartData *ld) { LineartEdge *e; int i; @@ -1377,7 +1401,7 @@ static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb) #define LRT_VERT_OUT_OF_BOUND(v) \ (v && (v->fbcoord[0] < -1 || v->fbcoord[0] > 1 || v->fbcoord[1] < -1 || v->fbcoord[1] > 1)) - LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->line_buffer_pointers) { + LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.line_buffer_pointers) { e = (LineartEdge *)eln->pointer; for (i = 0; i < eln->element_count; i++) { if ((LRT_VERT_OUT_OF_BOUND(e[i].v1) && LRT_VERT_OUT_OF_BOUND(e[i].v2))) { @@ -1414,14 +1438,22 @@ static void lineart_mvert_transform_task(void *__restrict userdata, v->index = i; } -#define LRT_EDGE_FLAG_TYPE_MAX_BITS 6 +static const int LRT_MESH_EDGE_TYPES[] = { + LRT_EDGE_FLAG_EDGE_MARK, + LRT_EDGE_FLAG_CONTOUR, + LRT_EDGE_FLAG_CREASE, + LRT_EDGE_FLAG_MATERIAL, + LRT_EDGE_FLAG_LOOSE, +}; -static int lineart_edge_type_duplication_count(char eflag) +#define LRT_MESH_EDGE_TYPES_COUNT 5 + +static int lineart_edge_type_duplication_count(int eflag) { int count = 0; /* See eLineartEdgeFlag for details. */ - for (int i = 0; i < LRT_EDGE_FLAG_TYPE_MAX_BITS; i++) { - if (eflag & (1 << i)) { + for (int i = 0; i < LRT_MESH_EDGE_TYPES_COUNT; i++) { + if (eflag & LRT_MESH_EDGE_TYPES[i]) { count++; } } @@ -1432,17 +1464,17 @@ static int lineart_edge_type_duplication_count(char eflag) * Because we have a variable size for #LineartTriangle, we need an access helper. * See #LineartTriangleThread for more info. */ -static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb, +static LineartTriangle *lineart_triangle_from_index(LineartData *ld, LineartTriangle *rt_array, int index) { - char *b = (char *)rt_array; - b += (index * rb->triangle_size); + int8_t *b = (int8_t *)rt_array; + b += (index * ld->sizeof_triangle); return (LineartTriangle *)b; } typedef struct EdgeFeatData { - LineartRenderBuffer *rb; + LineartData *ld; Mesh *me; const MLoopTri *mlooptri; LineartTriangle *tri_array; @@ -1488,7 +1520,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, } bool face_mark_filtered = false; - bool enable_face_mark = (e_feat_data->use_freestyle_face && e_feat_data->rb->filter_face_mark); + bool enable_face_mark = (e_feat_data->use_freestyle_face && + e_feat_data->ld->conf.filter_face_mark); bool only_contour = false; if (enable_face_mark) { FreestyleFace *ff1, *ff2; @@ -1505,7 +1538,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, * path is simper when it's assuming both ff1 and ff2 not NULL. */ ff2 = ff1; } - if (e_feat_data->rb->filter_face_mark_boundaries ^ e_feat_data->rb->filter_face_mark_invert) { + if (e_feat_data->ld->conf.filter_face_mark_boundaries ^ + e_feat_data->ld->conf.filter_face_mark_invert) { if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) { face_mark_filtered = true; } @@ -1515,12 +1549,12 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, face_mark_filtered = true; } } - if (e_feat_data->rb->filter_face_mark_invert) { + if (e_feat_data->ld->conf.filter_face_mark_invert) { face_mark_filtered = !face_mark_filtered; } if (!face_mark_filtered) { edge_nabr[i].flags = LRT_EDGE_FLAG_INHIBIT; - if (e_feat_data->rb->filter_face_mark_keep_contour) { + if (e_feat_data->ld->conf.filter_face_mark_keep_contour) { only_contour = true; } } @@ -1539,50 +1573,50 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, LineartTriangle *tri1, *tri2; LineartVert *vert; - LineartRenderBuffer *rb = e_feat_data->rb; + LineartData *ld = e_feat_data->ld; int f1 = i / 3, f2 = edge_nabr[i].e / 3; /* The mesh should already be triangulated now, so we can assume each face is a triangle. */ - tri1 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f1); - tri2 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f2); + tri1 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f1); + tri2 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f2); vert = &e_feat_data->v_array[edge_nabr[i].v1]; double view_vector_persp[3]; double *view_vector = view_vector_persp; - double dot_1 = 0, dot_2 = 0; + double dot_v1 = 0, dot_v2 = 0; double result; bool material_back_face = ((tri1->flags | tri2->flags) & LRT_TRIANGLE_MAT_BACK_FACE_CULLING); - if (rb->use_contour || rb->use_back_face_culling || material_back_face) { - if (rb->cam_is_persp) { - sub_v3_v3v3_db(view_vector, rb->camera_pos, vert->gloc); + if (ld->conf.use_contour || ld->conf.use_back_face_culling || material_back_face) { + if (ld->conf.cam_is_persp) { + sub_v3_v3v3_db(view_vector, ld->conf.camera_pos, vert->gloc); } else { - view_vector = rb->view_vector; + view_vector = ld->conf.view_vector; } - dot_1 = dot_v3v3_db(view_vector, tri1->gn); - dot_2 = dot_v3v3_db(view_vector, tri2->gn); + dot_v1 = dot_v3v3_db(view_vector, tri1->gn); + dot_v2 = dot_v3v3_db(view_vector, tri2->gn); - if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) { + if ((result = dot_v1 * dot_v2) <= 0 && (dot_v1 + dot_v2)) { edge_flag_result |= LRT_EDGE_FLAG_CONTOUR; } - if (rb->use_back_face_culling) { - if (dot_1 < 0) { + if (ld->conf.use_back_face_culling) { + if (dot_v1 < 0) { tri1->flags |= LRT_CULL_DISCARD; } - if (dot_2 < 0) { + if (dot_v2 < 0) { tri2->flags |= LRT_CULL_DISCARD; } } if (material_back_face) { - if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_1 < 0) { + if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v1 < 0) { tri1->flags |= LRT_CULL_DISCARD; } - if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_2 < 0) { + if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v2 < 0) { tri2->flags |= LRT_CULL_DISCARD; } } @@ -1590,9 +1624,9 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, if (!only_contour) { - if (rb->use_crease) { + if (ld->conf.use_crease) { bool do_crease = true; - if (!rb->force_crease && !e_feat_data->use_auto_smooth && + if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth && (me->mpoly[mlooptri[f1].poly].flag & ME_SMOOTH) && (me->mpoly[mlooptri[f2].poly].flag & ME_SMOOTH)) { do_crease = false; @@ -1605,7 +1639,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr; int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr; - if (rb->use_material && mat1 != mat2) { + if (ld->conf.use_material && mat1 != mat2) { edge_flag_result |= LRT_EDGE_FLAG_MATERIAL; } } @@ -1621,11 +1655,11 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, if (real_edges[i % 3] >= 0) { MEdge *medge = &me->medge[real_edges[i % 3]]; - if (rb->use_crease && rb->sharp_as_crease && (medge->flag & ME_SHARP)) { + if (ld->conf.use_crease && ld->conf.sharp_as_crease && (medge->flag & ME_SHARP)) { edge_flag_result |= LRT_EDGE_FLAG_CREASE; } - if (rb->use_edge_marks && e_feat_data->use_freestyle_edge) { + if (ld->conf.use_edge_marks && e_feat_data->use_freestyle_edge) { FreestyleEdge *fe; int index = e_feat_data->freestyle_edge_index; fe = &((FreestyleEdge *)me->edata.layers[index].data)[real_edges[i % 3]]; @@ -1641,7 +1675,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, /* Only allocate for feature edge (instead of all edges) to save memory. * If allow duplicated edges, one edge gets added multiple times if it has multiple types. */ - reduce_data->feat_edges += e_feat_data->rb->allow_duplicated_types ? + reduce_data->feat_edges += e_feat_data->ld->conf.allow_duplicated_types ? lineart_edge_type_duplication_count(edge_flag_result) : 1; } @@ -1679,6 +1713,7 @@ static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData sizeof(MEdge *) * to_be_joined->loose_count); loose_data->loose_count += to_be_joined->loose_count; MEM_freeN(to_be_joined->loose_array); + to_be_joined->loose_array = NULL; } static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e) @@ -1766,17 +1801,17 @@ static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartO } static void lineart_triangle_adjacent_assign(LineartTriangle *tri, - LineartTriangleAdjacent *ta, + LineartTriangleAdjacent *tri_adj, LineartEdge *e) { if (lineart_edge_match(tri, e, 0, 1)) { - ta->e[0] = e; + tri_adj->e[0] = e; } else if (lineart_edge_match(tri, e, 1, 2)) { - ta->e[1] = e; + tri_adj->e[1] = e; } else if (lineart_edge_match(tri, e, 2, 0)) { - ta->e[2] = e; + tri_adj->e[2] = e; } } @@ -1862,7 +1897,7 @@ static void lineart_edge_neighbor_init_task(void *__restrict userdata, adj_e->v1 = mloop[looptri->tri[i % 3]].v; adj_e->v2 = mloop[looptri->tri[(i + 1) % 3]].v; if (adj_e->v1 > adj_e->v2) { - SWAP(unsigned int, adj_e->v1, adj_e->v2); + SWAP(uint32_t, adj_e->v1, adj_e->v2); } edge_nabr->e = -1; @@ -1908,7 +1943,7 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge return edge_nabr; } -static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRenderBuffer *re_buf) +static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartData *la_data) { LineartElementLinkNode *elem_link_node; LineartVert *la_v_arr; @@ -1942,19 +1977,20 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend /* If we allow duplicated edges, one edge should get added multiple times if is has been * classified as more than one edge type. This is so we can create multiple different line type * chains containing the same edge. */ - la_v_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool, + la_v_arr = lineart_mem_acquire_thread(&la_data->render_data_pool, sizeof(LineartVert) * me->totvert); - la_tri_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool, - tot_tri * re_buf->triangle_size); + la_tri_arr = lineart_mem_acquire_thread(&la_data->render_data_pool, + tot_tri * la_data->sizeof_triangle); Object *orig_ob = ob_info->original_ob; - BLI_spin_lock(&re_buf->lock_task); - elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->vertex_buffer_pointers, - &re_buf->render_data_pool, - la_v_arr, - sizeof(LineartElementLinkNode)); - BLI_spin_unlock(&re_buf->lock_task); + BLI_spin_lock(&la_data->lock_task); + elem_link_node = lineart_list_append_pointer_pool_sized_thread( + &la_data->geom.vertex_buffer_pointers, + &la_data->render_data_pool, + la_v_arr, + sizeof(LineartElementLinkNode)); + BLI_spin_unlock(&la_data->lock_task); elem_link_node->element_count = me->totvert; elem_link_node->object_ref = orig_ob; @@ -1970,7 +2006,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend use_auto_smooth = true; } else { - crease_angle = re_buf->crease_threshold; + crease_angle = la_data->conf.crease_threshold; } /* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates @@ -1979,12 +2015,13 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY; } - BLI_spin_lock(&re_buf->lock_task); - elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->triangle_buffer_pointers, - &re_buf->render_data_pool, - la_tri_arr, - sizeof(LineartElementLinkNode)); - BLI_spin_unlock(&re_buf->lock_task); + BLI_spin_lock(&la_data->lock_task); + elem_link_node = lineart_list_append_pointer_pool_sized_thread( + &la_data->geom.triangle_buffer_pointers, + &la_data->render_data_pool, + la_tri_arr, + sizeof(LineartElementLinkNode)); + BLI_spin_unlock(&la_data->lock_task); int usage = ob_info->usage; @@ -1996,10 +2033,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri, "LineartTriangleAdjacent"); /* Link is minimal so we use pool anyway. */ - BLI_spin_lock(&re_buf->lock_task); + BLI_spin_lock(&la_data->lock_task); lineart_list_append_pointer_pool_thread( - &re_buf->triangle_adjacent_pointers, &re_buf->render_data_pool, tri_adj); - BLI_spin_unlock(&re_buf->lock_task); + &la_data->geom.triangle_adjacent_pointers, &la_data->render_data_pool, tri_adj); + BLI_spin_unlock(&la_data->lock_task); /* Convert all vertices to lineart verts. */ TaskParallelSettings vert_settings; @@ -2028,10 +2065,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend tri_data.mlooptri = mlooptri; tri_data.vert_arr = la_v_arr; tri_data.tri_arr = la_tri_arr; - tri_data.lineart_triangle_size = re_buf->triangle_size; + tri_data.lineart_triangle_size = la_data->sizeof_triangle; tri_data.tri_adj = tri_adj; - unsigned int total_edges = tot_tri * 3; + uint32_t total_edges = tot_tri * 3; BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings); @@ -2049,7 +2086,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend edge_feat_settings.func_reduce = feat_data_sum_reduce; EdgeFeatData edge_feat_data = {0}; - edge_feat_data.rb = re_buf; + edge_feat_data.ld = la_data; edge_feat_data.me = me; edge_feat_data.mlooptri = mlooptri; edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges); @@ -2075,7 +2112,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend &edge_feat_settings); LooseEdgeData loose_data = {0}; - if (re_buf->use_loose) { + if (la_data->conf.use_loose) { /* Only identifying floating edges at this point because other edges has been taken care of * inside #lineart_identify_mlooptri_feature_edges function. */ TaskParallelSettings edge_loose_settings; @@ -2091,20 +2128,21 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count; - la_edge_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool, + la_edge_arr = lineart_mem_acquire_thread(&la_data->render_data_pool, sizeof(LineartEdge) * allocate_la_e); - la_seg_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool, + la_seg_arr = lineart_mem_acquire_thread(&la_data->render_data_pool, sizeof(LineartEdgeSegment) * allocate_la_e); - BLI_spin_lock(&re_buf->lock_task); - elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->line_buffer_pointers, - &re_buf->render_data_pool, - la_edge_arr, - sizeof(LineartElementLinkNode)); - BLI_spin_unlock(&re_buf->lock_task); + BLI_spin_lock(&la_data->lock_task); + elem_link_node = lineart_list_append_pointer_pool_sized_thread( + &la_data->geom.line_buffer_pointers, + &la_data->render_data_pool, + la_edge_arr, + sizeof(LineartElementLinkNode)); + BLI_spin_unlock(&la_data->lock_task); elem_link_node->element_count = allocate_la_e; elem_link_node->object_ref = orig_ob; - // Start of the edge/seg arr + /* Start of the edge/seg arr */ LineartEdge *la_edge; LineartEdgeSegment *la_seg; la_edge = la_edge_arr; @@ -2125,8 +2163,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend LineartEdge *edge_added = NULL; /* See eLineartEdgeFlag for details. */ - for (int flag_bit = 0; flag_bit < LRT_EDGE_FLAG_TYPE_MAX_BITS; flag_bit++) { - char use_type = 1 << flag_bit; + for (int flag_bit = 0; flag_bit < LRT_MESH_EDGE_TYPES_COUNT; flag_bit++) { + int use_type = LRT_MESH_EDGE_TYPES[flag_bit]; if (!(use_type & edge_nabr->flags)) { continue; } @@ -2134,13 +2172,13 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend la_edge->v1 = &la_v_arr[edge_nabr->v1]; la_edge->v2 = &la_v_arr[edge_nabr->v2]; int findex = i / 3; - la_edge->t1 = lineart_triangle_from_index(re_buf, la_tri_arr, findex); + la_edge->t1 = lineart_triangle_from_index(la_data, la_tri_arr, findex); if (!edge_added) { lineart_triangle_adjacent_assign(la_edge->t1, &tri_adj[findex], la_edge); } if (edge_nabr->e != -1) { findex = edge_nabr->e / 3; - la_edge->t2 = lineart_triangle_from_index(re_buf, la_tri_arr, findex); + la_edge->t2 = lineart_triangle_from_index(la_data, la_tri_arr, findex); if (!edge_added) { lineart_triangle_adjacent_assign(la_edge->t2, &tri_adj[findex], la_edge); } @@ -2162,7 +2200,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend la_edge++; la_seg++; - if (!re_buf->allow_duplicated_types) { + if (!la_data->conf.allow_duplicated_types) { break; } } @@ -2196,10 +2234,7 @@ static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool), LineartObjectLoadTaskInfo *olti) { for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) { - lineart_geometry_object_load(obi, olti->rb); - if (G.debug_value == 4000) { - printf("thread id: %d processed: %d\n", olti->thread_id, obi->original_me->totpoly); - } + lineart_geometry_object_load(obi, olti->ld); } } @@ -2277,7 +2312,7 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_ int this_face_count) { LineartObjectLoadTaskInfo *use_olti = olti_list; - long unsigned int min_face = use_olti->total_faces; + uint64_t min_face = use_olti->total_faces; for (int i = 0; i < thread_count; i++) { if (olti_list[i].total_faces < min_face) { min_face = olti_list[i].total_faces; @@ -2333,7 +2368,7 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4], return true; } -static void lineart_object_load_single_instance(LineartRenderBuffer *rb, +static void lineart_object_load_single_instance(LineartData *ld, Depsgraph *depsgraph, Scene *scene, Object *ob, @@ -2343,7 +2378,7 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb, LineartObjectLoadTaskInfo *olti, int thread_count) { - LineartObjectInfo *obi = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartObjectInfo)); + LineartObjectInfo *obi = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartObjectInfo)); obi->usage = lineart_usage_check(scene->master_collection, ob, is_render); obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection, ob); Mesh *use_mesh; @@ -2354,8 +2389,8 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb, /* Prepare the matrix used for transforming this specific object (instance). This has to be * done before mesh boundbox check because the function needs that. */ - mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, rb->view_projection, use_mat); - mul_m4db_m4db_m4fl_uniq(obi->model_view, rb->view, use_mat); + mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, ld->conf.view_projection, use_mat); + mul_m4db_m4db_m4fl_uniq(obi->model_view, ld->conf.view, use_mat); if (!ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { return; @@ -2377,7 +2412,8 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb, return; } - if (!lineart_geometry_check_visible(obi->model_view_proj, rb->shift_x, rb->shift_y, use_mesh)) { + if (!lineart_geometry_check_visible( + obi->model_view_proj, ld->conf.shift_x, ld->conf.shift_y, use_mesh)) { return; } @@ -2400,15 +2436,15 @@ static void lineart_main_load_geometries( Depsgraph *depsgraph, Scene *scene, Object *camera /* Still use camera arg for convenience. */, - LineartRenderBuffer *rb, + LineartData *ld, bool allow_duplicates) { double proj[4][4], view[4][4], result[4][4]; float inv[4][4]; Camera *cam = camera->data; float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); - int fit = BKE_camera_sensor_fit(cam->sensor_fit, rb->w, rb->h); - double asp = ((double)rb->w / (double)rb->h); + int fit = BKE_camera_sensor_fit(cam->sensor_fit, ld->w, ld->h); + double asp = ((double)ld->w / (double)ld->h); int bound_box_discard_count = 0; @@ -2419,7 +2455,7 @@ static void lineart_main_load_geometries( if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) { sensor /= asp; } - const double fov = focallength_to_fov(cam->lens / (1 + rb->overscan), sensor); + const double fov = focallength_to_fov(cam->lens / (1 + ld->conf.overscan), sensor); lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end); } else if (cam->type == CAM_ORTHO) { @@ -2427,58 +2463,60 @@ static void lineart_main_load_geometries( lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end); } - double t_start; - - if (G.debug_value == 4000) { - t_start = PIL_check_seconds_timer(); - } - - invert_m4_m4(inv, rb->cam_obmat); + invert_m4_m4(inv, ld->conf.cam_obmat); mul_m4db_m4db_m4fl_uniq(result, proj, inv); copy_m4_m4_db(proj, result); - copy_m4_m4_db(rb->view_projection, proj); + copy_m4_m4_db(ld->conf.view_projection, proj); unit_m4_db(view); - copy_m4_m4_db(rb->view, view); + copy_m4_m4_db(ld->conf.view, view); - BLI_listbase_clear(&rb->triangle_buffer_pointers); - BLI_listbase_clear(&rb->vertex_buffer_pointers); + BLI_listbase_clear(&ld->geom.triangle_buffer_pointers); + BLI_listbase_clear(&ld->geom.vertex_buffer_pointers); - int thread_count = rb->thread_count; + double t_start; + if (G.debug_value == 4000) { + t_start = PIL_check_seconds_timer(); + } - /* This memory is in render buffer memory pool. so we don't need to free those after loading. - */ + int thread_count = ld->thread_count; + + /* This memory is in render buffer memory pool. So we don't need to free those after loading. */ LineartObjectLoadTaskInfo *olti = lineart_mem_acquire( - &rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count); + &ld->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count); eEvaluationMode eval_mode = DEG_get_mode(depsgraph); bool is_render = eval_mode == DAG_EVAL_RENDER; - FOREACH_SCENE_OBJECT_BEGIN (scene, ob) { + int flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_VISIBLE; + + /* Instance duplicated & particles. */ + if (allow_duplicates) { + flags |= DEG_ITER_OBJECT_FLAG_DUPLI; + } + + /* XXX(@Yiming): Temporary solution, this iterator is technically unsafe to use *during* + * depsgraph evaluation, see D14997 for detailed explanations. */ + DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) { Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob); if (!eval_ob) { continue; } + /* DEG_OBJECT_ITER_BEGIN will include the instanced mesh of these curve object types, so don't + * load them twice. */ + if (allow_duplicates && ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { + continue; + } + if (BKE_object_visibility(eval_ob, eval_mode) & OB_VISIBLE_SELF) { lineart_object_load_single_instance( - rb, depsgraph, scene, eval_ob, eval_ob, eval_ob->obmat, is_render, olti, thread_count); - } - if (allow_duplicates) { - ListBase *dupli = object_duplilist(depsgraph, scene, eval_ob); - LISTBASE_FOREACH (DupliObject *, dob, dupli) { - if (BKE_object_visibility(eval_ob, eval_mode) & - (OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES)) { - Object *ob_ref = (dob->type & OB_DUPLIPARTS) ? eval_ob : dob->ob; - lineart_object_load_single_instance( - rb, depsgraph, scene, dob->ob, ob_ref, dob->mat, is_render, olti, thread_count); - } - } - free_object_duplilist(dupli); + ld, depsgraph, scene, eval_ob, eval_ob, eval_ob->obmat, is_render, olti, thread_count); } } - FOREACH_SCENE_OBJECT_END; + DEG_OBJECT_ITER_END; TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH); @@ -2486,7 +2524,7 @@ static void lineart_main_load_geometries( printf("thread count: %d\n", thread_count); } for (int i = 0; i < thread_count; i++) { - olti[i].rb = rb; + olti[i].ld = ld; olti[i].thread_id = i; BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL); } @@ -2506,7 +2544,7 @@ static void lineart_main_load_geometries( edge_count += obi->pending_edges.next; } } - lineart_finalize_object_edge_array_reserve(&rb->pending_edges, edge_count); + lineart_finalize_object_edge_array_reserve(&ld->pending_edges, edge_count); for (int i = 0; i < thread_count; i++) { for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) { @@ -2524,7 +2562,7 @@ static void lineart_main_load_geometries( * same numeric index to come close together. */ obi->global_i_offset = global_i; global_i += v_count; - lineart_finalize_object_edge_array(&rb->pending_edges, obi); + lineart_finalize_object_edge_array(&ld->pending_edges, obi); } } @@ -2618,6 +2656,9 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri, (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \ } +#define LRT_ISEC(index) (index == 0 ? isec_e1 : (index == 1 ? isec_e2 : isec_e3)) +#define LRT_PARALLEL(index) (index == 0 ? para_e1 : (index == 1 ? para_e2 : para_e3)) + /** * This is the main function to calculate * the occlusion status between 1(one) triangle and 1(one) line. @@ -2631,7 +2672,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri, * extruding from one of the triangle's point. To get the information using one math process can * solve this problem. * - * 2) Currently using discrete a/b/c/pa/pb/pc/is[3] values for storing + * 2) Currently using discrete a/b/c/para_e1/para_e2/para_e3/is[3] values for storing * intersection/edge_aligned/intersection_order info, which isn't optimal, needs a better * representation (likely a struct) for readability and clarity of code path. * @@ -2653,18 +2694,20 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), double *from, double *to) { - double is[3] = {0}; - int order[3]; - int LCross = -1, RCross = -1; - int a, b, c; /* Crossing info. */ - bool pa, pb, pc; /* Parallel info. */ - int st_l = 0, st_r = 0; - - double Lv[3]; - double Rv[3]; - double vd4[4]; - double Cv[3]; - double dot_l, dot_r, dot_la, dot_ra; + double cross_ratios[3] = {0}; + int cross_order[3]; + int cross_v1 = -1, cross_v2 = -1; + /* If the edge intersects with the triangle edges (including extensions). */ + int isec_e1, isec_e2, isec_e3; + /* If edge is parallel to one of the edges in the triangle. */ + bool para_e1, para_e2, para_e3; + enum LineartPointTri state_v1 = LRT_OUTSIDE_TRIANGLE, state_v2 = LRT_OUTSIDE_TRIANGLE; + + double dir_v1[3]; + double dir_v2[3]; + double view_vector[4]; + double dir_cam[3]; + double dot_v1, dot_v2, dot_v1a, dot_v2a; double dot_f; double gloc[4], trans[4]; double cut = -1; @@ -2687,31 +2730,25 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), } /* Check if the line visually crosses one of the edge in the triangle. */ - a = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &is[0], &pa); - b = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &is[1], &pb); - c = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &is[2], &pc); + isec_e1 = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &cross_ratios[0], ¶_e1); + isec_e2 = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &cross_ratios[1], ¶_e2); + isec_e3 = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &cross_ratios[2], ¶_e3); /* Sort the intersection distance. */ - INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order); + INTERSECT_SORT_MIN_TO_MAX_3(cross_ratios[0], cross_ratios[1], cross_ratios[2], cross_order); - sub_v3_v3v3_db(Lv, e->v1->gloc, tri->v[0]->gloc); - sub_v3_v3v3_db(Rv, e->v2->gloc, tri->v[0]->gloc); - - copy_v3_v3_db(Cv, camera_dir); + sub_v3_v3v3_db(dir_v1, e->v1->gloc, tri->v[0]->gloc); + sub_v3_v3v3_db(dir_v2, e->v2->gloc, tri->v[0]->gloc); + copy_v3_v3_db(dir_cam, camera_dir); + copy_v3_v3_db(view_vector, override_camera_loc); if (override_cam_is_persp) { - copy_v3_v3_db(vd4, override_camera_loc); - } - else { - copy_v4_v4_db(vd4, override_camera_loc); - } - if (override_cam_is_persp) { - sub_v3_v3v3_db(Cv, vd4, tri->v[0]->gloc); + sub_v3_v3v3_db(dir_cam, view_vector, tri->v[0]->gloc); } - dot_l = dot_v3v3_db(Lv, tri->gn); - dot_r = dot_v3v3_db(Rv, tri->gn); - dot_f = dot_v3v3_db(Cv, tri->gn); + dot_v1 = dot_v3v3_db(dir_v1, tri->gn); + dot_v2 = dot_v3v3_db(dir_v2, tri->gn); + dot_f = dot_v3v3_db(dir_cam, tri->gn); /* NOTE(Yiming): When we don't use `dot_f==0` here, it's theoretically possible that _some_ * faces in perspective mode would get erroneously caught in this condition where they really @@ -2722,40 +2759,39 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), return false; } + /* Whether two end points are inside/on_the_edge/outside of the triangle. */ + state_v1 = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2); + state_v2 = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2); + /* If the edge doesn't visually cross any edge of the triangle... */ - if (!a && !b && !c) { + if (!isec_e1 && !isec_e2 && !isec_e3) { /* And if both end point from the edge is outside of the triangle... */ - if (!(st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2)) && - !(st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2))) { + if ((!state_v1) && (!state_v2)) { return 0; /* We don't have any occlusion. */ } } - /* Whether two end points are inside/on_the_edge/outside of the triangle. */ - st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2); - st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2); - /* Determine the cut position. */ - dot_la = fabs(dot_l); - if (dot_la < DBL_EPSILON) { - dot_la = 0; - dot_l = 0; + dot_v1a = fabs(dot_v1); + if (dot_v1a < DBL_EPSILON) { + dot_v1a = 0; + dot_v1 = 0; } - dot_ra = fabs(dot_r); - if (dot_ra < DBL_EPSILON) { - dot_ra = 0; - dot_r = 0; + dot_v2a = fabs(dot_v2); + if (dot_v2a < DBL_EPSILON) { + dot_v2a = 0; + dot_v2 = 0; } - if (dot_l - dot_r == 0) { + if (dot_v1 - dot_v2 == 0) { cut = 100000; } - else if (dot_l * dot_r <= 0) { - cut = dot_la / fabs(dot_l - dot_r); + else if (dot_v1 * dot_v2 <= 0) { + cut = dot_v1a / fabs(dot_v1 - dot_v2); } else { - cut = fabs(dot_r + dot_l) / fabs(dot_l - dot_r); - cut = dot_ra > dot_la ? 1 - cut : cut; + cut = fabs(dot_v2 + dot_v1) / fabs(dot_v1 - dot_v2); + cut = dot_v2a > dot_v1a ? 1 - cut : cut; } /* Transform the cut from geometry space to image space. */ @@ -2776,7 +2812,7 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), } #define LRT_GUARD_NOT_FOUND \ - if (LCross < 0 || RCross < 0) { \ + if (cross_v1 < 0 || cross_v2 < 0) { \ return false; \ } @@ -2784,95 +2820,97 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), * indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision * tolerance. */ - if (st_l == 2) { + if (state_v1 == LRT_INSIDE_TRIANGLE) { /* Left side is in the triangle. */ - if (st_r == 2) { + if (state_v2 == LRT_INSIDE_TRIANGLE) { /* | l---r | */ - INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2); } - else if (st_r == 1) { + else if (state_v2 == LRT_ON_TRIANGLE) { /* | l------r| */ - INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2); } - else if (st_r == 0) { + else if (state_v2 == LRT_OUTSIDE_TRIANGLE) { /* | l-------|------r */ - INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, 0, RCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 0, cross_v2); } } - else if (st_l == 1) { + else if (state_v1 == LRT_ON_TRIANGLE) { /* Left side is on some edge of the triangle. */ - if (st_r == 2) { + if (state_v2 == LRT_INSIDE_TRIANGLE) { /* |l------r | */ - INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2); } - else if (st_r == 1) { + else if (state_v2 == LRT_ON_TRIANGLE) { /* |l---------r| */ - INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2); } - else if (st_r == 0) { + else if (state_v2 == LRT_OUTSIDE_TRIANGLE) { /* |l----------|-------r (crossing the triangle) [OR] * r---------|l | (not crossing the triangle) */ - INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross); - if (RCross >= 0 && LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) { - INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2); + if (cross_v2 >= 0 && LRT_ISEC(cross_v2) && cross_ratios[cross_v2] > (DBL_TRIANGLE_LIM)) { + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1); } else { - INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, RCross); - if (RCross > 0) { - INTERSECT_JUST_SMALLER(is, order, is[RCross], LCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2); + if (cross_v2 > 0) { + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, cross_ratios[cross_v2], cross_v1); } } LRT_GUARD_NOT_FOUND /* We could have the edge being completely parallel to the triangle where there isn't a * viable occlusion result. */ - if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) { + if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) || + (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) { return false; } } } - else if (st_l == 0) { + else if (state_v1 == LRT_OUTSIDE_TRIANGLE) { /* Left side is outside of the triangle. */ - if (st_r == 2) { + if (state_v2 == LRT_INSIDE_TRIANGLE) { /* l---|---r | */ - INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2); } - else if (st_r == 1) { + else if (state_v2 == LRT_ON_TRIANGLE) { /* |r----------|-------l (crossing the triangle) [OR] * l---------|r | (not crossing the triangle) */ - INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross); - if (LCross >= 0 && LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) { - INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1); + if (cross_v1 >= 0 && LRT_ISEC(cross_v1) && cross_ratios[cross_v1] < (1 - DBL_TRIANGLE_LIM)) { + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2); } else { - INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, LCross); - if (LCross > 0) { - INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1); + if (cross_v1 > 0) { + INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2); } } LRT_GUARD_NOT_FOUND /* The same logic applies as above case. */ - if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) { + if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) || + (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) { return false; } } - else if (st_r == 0) { + else if (state_v2 == LRT_OUTSIDE_TRIANGLE) { /* l---|----|----r (crossing the triangle) [OR] * l----r | | (not crossing the triangle) */ - INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, LCross); - if (LCross >= 0 && LRT_ABC(LCross)) { - INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); + INTERSECT_JUST_GREATER(cross_ratios, cross_order, -DBL_TRIANGLE_LIM, cross_v1); + if (cross_v1 >= 0 && LRT_ISEC(cross_v1)) { + INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2); } else { - if (LCross >= 0) { - INTERSECT_JUST_GREATER(is, order, is[LCross], LCross); - if (LCross >= 0) { - INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); + if (cross_v1 >= 0) { + INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v1); + if (cross_v1 >= 0) { + INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2); } } } @@ -2881,28 +2919,28 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), LRT_GUARD_NOT_FOUND - double LF = dot_l * dot_f, RF = dot_r * dot_f; + double dot_1f = dot_v1 * dot_f, dot_2f = dot_v2 * dot_f; /* Determine the start and end point of image space cut on a line. */ - if (LF <= 0 && RF <= 0 && (dot_l || dot_r)) { - *from = MAX2(0, is[LCross]); - *to = MIN2(1, is[RCross]); + if (dot_1f <= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) { + *from = MAX2(0, cross_ratios[cross_v1]); + *to = MIN2(1, cross_ratios[cross_v2]); if (*from >= *to) { return false; } return true; } - if (LF >= 0 && RF <= 0 && (dot_l || dot_r)) { - *from = MAX2(cut, is[LCross]); - *to = MIN2(1, is[RCross]); + if (dot_1f >= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) { + *from = MAX2(cut, cross_ratios[cross_v1]); + *to = MIN2(1, cross_ratios[cross_v2]); if (*from >= *to) { return false; } return true; } - if (LF <= 0 && RF >= 0 && (dot_l || dot_r)) { - *from = MAX2(0, is[LCross]); - *to = MIN2(cut, is[RCross]); + if (dot_1f <= 0 && dot_2f >= 0 && (dot_v1 || dot_v2)) { + *from = MAX2(0, cross_ratios[cross_v1]); + *to = MIN2(cut, cross_ratios[cross_v2]); if (*from >= *to) { return false; } @@ -2916,6 +2954,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), #undef INTERSECT_SORT_MIN_TO_MAX_3 #undef INTERSECT_JUST_GREATER #undef INTERSECT_JUST_SMALLER +#undef LRT_ISEC +#undef LRT_PARALLEL /** * At this stage of the computation we don't have triangle adjacent info anymore, @@ -2997,272 +3037,239 @@ static LineartVert *lineart_triangle_share_point(const LineartTriangle *l, return NULL; } -/** - * To save time and prevent overlapping lines when computing intersection lines. - */ -static bool lineart_vert_already_intersected_2v(LineartVertIntersection *vt, - LineartVertIntersection *v1, - LineartVertIntersection *v2) -{ - return ((vt->isec1 == v1->base.index && vt->isec2 == v2->base.index) || - (vt->isec2 == v2->base.index && vt->isec1 == v1->base.index)); -} - -static void lineart_vert_set_intersection_2v(LineartVert *vt, LineartVert *v1, LineartVert *v2) -{ - LineartVertIntersection *irv = (LineartVertIntersection *)vt; - irv->isec1 = v1->index; - irv->isec2 = v2->index; -} - -/** - * This tests a triangle against a virtual line represented by `v1---v2`. - * The vertices returned after repeated calls to this function - * is then used to create a triangle/triangle intersection line. - */ -static LineartVert *lineart_triangle_2v_intersection_test(LineartRenderBuffer *rb, - LineartVert *v1, - LineartVert *v2, - LineartTriangle *tri, - LineartTriangle *testing, - LineartVert *last) +static bool lineart_triangle_2v_intersection_math( + LineartVert *v1, LineartVert *v2, LineartTriangle *tri, const double *last, double *rv) { - double Lv[3]; - double Rv[3]; - double dot_l, dot_r; - LineartVert *result; + /* Direction vectors for the edge verts. We will check if the verts are on the same side of the + * triangle or not. */ + double dir_v1[3], dir_v2[3]; + double dot_v1, dot_v2; double gloc[3]; - LineartVert *l = v1, *r = v2; - for (LinkNode *ln = (void *)testing->intersecting_verts; ln; ln = ln->next) { - LineartVertIntersection *vt = ln->link; - if (vt->intersecting_with == tri && - lineart_vert_already_intersected_2v( - vt, (LineartVertIntersection *)l, (LineartVertIntersection *)r)) { - return (LineartVert *)vt; - } - } + sub_v3_v3v3_db(dir_v1, v1->gloc, tri->v[0]->gloc); + sub_v3_v3v3_db(dir_v2, v2->gloc, tri->v[0]->gloc); - sub_v3_v3v3_db(Lv, l->gloc, testing->v[0]->gloc); - sub_v3_v3v3_db(Rv, r->gloc, testing->v[0]->gloc); + dot_v1 = dot_v3v3_db(dir_v1, tri->gn); + dot_v2 = dot_v3v3_db(dir_v2, tri->gn); - dot_l = dot_v3v3_db(Lv, testing->gn); - dot_r = dot_v3v3_db(Rv, testing->gn); - - if (dot_l * dot_r > 0 || (!dot_l && !dot_r)) { - return 0; + if (dot_v1 * dot_v2 > 0 || (!dot_v1 && !dot_v2)) { + return false; } - dot_l = fabs(dot_l); - dot_r = fabs(dot_r); + dot_v1 = fabs(dot_v1); + dot_v2 = fabs(dot_v2); - interp_v3_v3v3_db(gloc, l->gloc, r->gloc, dot_l / (dot_l + dot_r)); + interp_v3_v3v3_db(gloc, v1->gloc, v2->gloc, dot_v1 / (dot_v1 + dot_v2)); - /* Due to precision issue, we might end up with the same point as the one we already detected. - */ - if (last && LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[0], gloc[0]) && - LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[1], gloc[1]) && - LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[2], gloc[2])) { - return NULL; + /* Due to precision issue, we might end up with the same point as the one we already detected. */ + if (last && LRT_DOUBLE_CLOSE_ENOUGH(last[0], gloc[0]) && + LRT_DOUBLE_CLOSE_ENOUGH(last[1], gloc[1]) && LRT_DOUBLE_CLOSE_ENOUGH(last[2], gloc[2])) { + return false; } if (!(lineart_point_inside_triangle3d( - gloc, testing->v[0]->gloc, testing->v[1]->gloc, testing->v[2]->gloc))) { - return NULL; + gloc, tri->v[0]->gloc, tri->v[1]->gloc, tri->v[2]->gloc))) { + return false; } - /* This is an intersection vert, the size is bigger than LineartVert, - * allocated separately. */ - result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartVertIntersection)); - - /* Indicate the data structure difference. */ - result->flag = LRT_VERT_HAS_INTERSECTION_DATA; - - copy_v3_v3_db(result->gloc, gloc); - - lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, result); + copy_v3_v3_db(rv, gloc); - return result; + return true; } -/** - * Test if two triangles intersect. Generates one intersection line if the check succeeds. - */ -static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb, - LineartTriangle *tri, - LineartTriangle *testing) +static bool lineart_triangle_intersect_math(LineartTriangle *tri, + LineartTriangle *t2, + double *v1, + double *v2) { - LineartVert *v1 = 0, *v2 = 0; - LineartVert **next = &v1; - LineartEdge *result; - LineartVert *E0T = 0; - LineartVert *E1T = 0; - LineartVert *E2T = 0; - LineartVert *TE0 = 0; - LineartVert *TE1 = 0; - LineartVert *TE2 = 0; + double *next = v1, *last = NULL; LineartVert *sv1, *sv2; - double cl[3]; - double ZMin, ZMax; - ZMax = rb->far_clip; - ZMin = rb->near_clip; - copy_v3_v3_db(cl, rb->camera_pos); - LineartVert *share = lineart_triangle_share_point(testing, tri); + LineartVert *share = lineart_triangle_share_point(t2, tri); if (share) { /* If triangles have sharing points like `abc` and `acd`, then we only need to detect `bc` * against `acd` or `cd` against `abc`. */ - LineartVert *new_share; lineart_triangle_get_other_verts(tri, share, &sv1, &sv2); - v1 = new_share = lineart_mem_acquire(&rb->render_data_pool, (sizeof(LineartVertIntersection))); - - new_share->flag = LRT_VERT_HAS_INTERSECTION_DATA; + copy_v3_v3_db(v1, share->gloc); - copy_v3_v3_db(new_share->gloc, share->gloc); - - v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, tri, testing, 0); - - if (v2 == NULL) { - lineart_triangle_get_other_verts(testing, share, &sv1, &sv2); - v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, testing, tri, 0); - if (v2 == NULL) { - return 0; + if (!lineart_triangle_2v_intersection_math(sv1, sv2, t2, 0, v2)) { + lineart_triangle_get_other_verts(t2, share, &sv1, &sv2); + if (lineart_triangle_2v_intersection_math(sv1, sv2, tri, 0, v2)) { + return true; } - lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, new_share); - } - else { - lineart_prepend_pool(&tri->intersecting_verts, &rb->render_data_pool, new_share); } } else { /* If not sharing any points, then we need to try all the possibilities. */ - E0T = lineart_triangle_2v_intersection_test(rb, tri->v[0], tri->v[1], tri, testing, 0); - if (E0T && (!(*next))) { - (*next) = E0T; - lineart_vert_set_intersection_2v((*next), tri->v[0], tri->v[1]); - next = &v2; - } - E1T = lineart_triangle_2v_intersection_test(rb, tri->v[1], tri->v[2], tri, testing, v1); - if (E1T && (!(*next))) { - (*next) = E1T; - lineart_vert_set_intersection_2v((*next), tri->v[1], tri->v[2]); - next = &v2; - } - if (!(*next)) { - E2T = lineart_triangle_2v_intersection_test(rb, tri->v[2], tri->v[0], tri, testing, v1); - } - if (E2T && (!(*next))) { - (*next) = E2T; - lineart_vert_set_intersection_2v((*next), tri->v[2], tri->v[0]); - next = &v2; + if (lineart_triangle_2v_intersection_math(tri->v[0], tri->v[1], t2, 0, v1)) { + next = v2; + last = v1; } - if (!(*next)) { - TE0 = lineart_triangle_2v_intersection_test( - rb, testing->v[0], testing->v[1], testing, tri, v1); - } - if (TE0 && (!(*next))) { - (*next) = TE0; - lineart_vert_set_intersection_2v((*next), testing->v[0], testing->v[1]); - next = &v2; + if (lineart_triangle_2v_intersection_math(tri->v[1], tri->v[2], t2, last, next)) { + if (last) { + return true; + } + next = v2; + last = v1; } - if (!(*next)) { - TE1 = lineart_triangle_2v_intersection_test( - rb, testing->v[1], testing->v[2], testing, tri, v1); + if (lineart_triangle_2v_intersection_math(tri->v[2], tri->v[0], t2, last, next)) { + if (last) { + return true; + } + next = v2; + last = v1; } - if (TE1 && (!(*next))) { - (*next) = TE1; - lineart_vert_set_intersection_2v((*next), testing->v[1], testing->v[2]); - next = &v2; + + if (lineart_triangle_2v_intersection_math(t2->v[0], t2->v[1], tri, last, next)) { + if (last) { + return true; + } + next = v2; + last = v1; } - if (!(*next)) { - TE2 = lineart_triangle_2v_intersection_test( - rb, testing->v[2], testing->v[0], testing, tri, v1); + if (lineart_triangle_2v_intersection_math(t2->v[1], t2->v[2], tri, last, next)) { + if (last) { + return true; + } + next = v2; + last = v1; } - if (TE2 && (!(*next))) { - (*next) = TE2; - lineart_vert_set_intersection_2v((*next), testing->v[2], testing->v[0]); - next = &v2; + if (lineart_triangle_2v_intersection_math(t2->v[2], t2->v[0], tri, last, next)) { + if (last) { + return true; + } + next = v2; + last = v1; } + } + return false; +} - if (!(*next)) { - return 0; - } +static void lineart_add_isec_thread(LineartIsecThread *th, + const double *v1, + const double *v2, + LineartTriangle *tri1, + LineartTriangle *tri2) +{ + if (th->current == th->max) { + + LineartIsecSingle *new_array = MEM_mallocN(sizeof(LineartIsecSingle) * th->max * 2, + "LineartIsecSingle"); + memcpy(new_array, th->array, sizeof(LineartIsecSingle) * th->max); + th->max *= 2; + MEM_freeN(th->array); + th->array = new_array; + } + LineartIsecSingle *isec_single = &th->array[th->current]; + copy_v3fl_v3db(isec_single->v1, v1); + copy_v3fl_v3db(isec_single->v2, v2); + isec_single->tri1 = tri1; + isec_single->tri2 = tri2; + th->current++; +} + +#define LRT_ISECT_TRIANGLE_PER_THREAD 4096 + +static bool lineart_schedule_new_triangle_task(LineartIsecThread *th) +{ + LineartData *ld = th->ld; + int remaining = LRT_ISECT_TRIANGLE_PER_THREAD; + + BLI_spin_lock(&ld->lock_task); + LineartElementLinkNode *eln = ld->isect_scheduled_up_to; + + if (!eln) { + BLI_spin_unlock(&ld->lock_task); + return false; } - /* The intersection line has been generated only in geometry space, so we need to transform - * them as well. */ - mul_v4_m4v3_db(v1->fbcoord, rb->view_projection, v1->gloc); - mul_v4_m4v3_db(v2->fbcoord, rb->view_projection, v2->gloc); - if (rb->cam_is_persp) { - mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3])); - mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3])); + th->pending_from = eln; + th->index_from = ld->isect_scheduled_up_to_index; + + while (remaining > 0 && eln) { + int remaining_this_eln = eln->element_count - ld->isect_scheduled_up_to_index; + int added_count = MIN2(remaining, remaining_this_eln); + remaining -= added_count; + if (remaining || added_count == remaining_this_eln) { + eln = eln->next; + ld->isect_scheduled_up_to = eln; + ld->isect_scheduled_up_to_index = 0; + } + else { + ld->isect_scheduled_up_to_index += added_count; + } } - v1->fbcoord[0] -= rb->shift_x * 2; - v1->fbcoord[1] -= rb->shift_y * 2; - v2->fbcoord[0] -= rb->shift_x * 2; - v2->fbcoord[1] -= rb->shift_y * 2; - /* This z transformation is not the same as the rest of the part, because the data don't go - * through normal perspective division calls in the pipeline, but this way the 3D result and - * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke - * generation anyway. */ - v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin)); - v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin)); + th->pending_to = eln ? eln : ld->geom.triangle_buffer_pointers.last; + th->index_to = ld->isect_scheduled_up_to_index; - ((LineartVertIntersection *)v1)->intersecting_with = tri; - ((LineartVertIntersection *)v2)->intersecting_with = testing; + BLI_spin_unlock(&ld->lock_task); - result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge)); - result->v1 = v1; - result->v2 = v2; - result->t1 = tri; - result->t2 = testing; + return true; +} - LineartEdgeSegment *es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment)); - BLI_addtail(&result->segments, es); - /* Don't need to OR flags right now, just a type mark. */ - result->flags = LRT_EDGE_FLAG_INTERSECTION; - result->intersection_mask = (tri->intersection_mask | testing->intersection_mask); +/* This function initializes two things: + * 1) Triangle array scheduling info, for each worker thread to get its chunk from the scheduler. + * 2) Per-thread intersection result array. Does not store actual #LineartEdge, these results will + * be finalized by #lineart_create_edges_from_isec_data + */ +static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count) +{ + d->threads = MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr"); + d->ld = ld; + d->thread_count = thread_count; - lineart_add_edge_to_array(&rb->pending_edges, result); + ld->isect_scheduled_up_to = ld->geom.triangle_buffer_pointers.first; + ld->isect_scheduled_up_to_index = 0; - return result; + for (int i = 0; i < thread_count; i++) { + LineartIsecThread *it = &d->threads[i]; + it->array = MEM_mallocN(sizeof(LineartIsecSingle) * 100, "LineartIsecSingle arr"); + it->max = 100; + it->current = 0; + it->thread_id = i; + it->ld = ld; + } } -static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb, - LineartTriangle *tri, - LineartBoundingArea *ba) +static void lineart_destroy_isec_thread(LineartIsecData *d) { - /* Testing_triangle->testing[0] is used to store pairing triangle reference. - * See definition of LineartTriangleThread for more info. */ - LineartTriangle *testing_triangle; - LineartTriangleThread *tt; + for (int i = 0; i < d->thread_count; i++) { + LineartIsecThread *it = &d->threads[i]; + MEM_freeN(it->array); + } + MEM_freeN(d->threads); +} - double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc; +static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri, + LineartBoundingArea *ba, + LineartIsecThread *th, + int up_to) +{ + BLI_assert(th != NULL); - /* If this is not the smallest subdiv bounding area. */ - if (ba->child) { - lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[0]); - lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[1]); - lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[2]); - lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[3]); + if (!th) { return; } - /* If this _is_ the smallest subdiv bounding area, then do the intersections there. */ - for (int i = 0; i < ba->triangle_count; i++) { - testing_triangle = ba->linked_triangles[i]; - tt = (LineartTriangleThread *)testing_triangle; + double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc; + + /* If this _is_ the smallest subdivision bounding area, then do the intersections there. */ + for (int i = 0; i < up_to; i++) { + /* Testing_triangle->testing[0] is used to store pairing triangle reference. + * See definition of LineartTriangleThread for more info. */ + LineartTriangle *testing_triangle = ba->linked_triangles[i]; + LineartTriangleThread *tt = (LineartTriangleThread *)testing_triangle; - if (testing_triangle == tri || tt->testing_e[0] == (LineartEdge *)tri) { + if (testing_triangle == tri || tt->testing_e[th->thread_id] == (LineartEdge *)tri) { continue; } - tt->testing_e[0] = (LineartEdge *)tri; + tt->testing_e[th->thread_id] = (LineartEdge *)tri; if ((testing_triangle->flags & LRT_TRIANGLE_NO_INTERSECTION) || ((testing_triangle->flags & LRT_TRIANGLE_INTERSECTION_ONLY) && @@ -3285,21 +3292,25 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb, } /* If we do need to compute intersection, then finally do it. */ - lineart_triangle_intersect(rb, tri, testing_triangle); + + double iv1[3], iv2[3]; + if (lineart_triangle_intersect_math(tri, testing_triangle, iv1, iv2)) { + lineart_add_isec_thread(th, iv1, iv2, tri, testing_triangle); + } } } /** * The calculated view vector will point towards the far-plane from the camera position. */ -static void lineart_main_get_view_vector(LineartRenderBuffer *rb) +static void lineart_main_get_view_vector(LineartData *ld) { float direction[3] = {0, 0, 1}; float trans[3]; float inv[4][4]; float obmat_no_scale[4][4]; - copy_m4_m4(obmat_no_scale, rb->cam_obmat); + copy_m4_m4(obmat_no_scale, ld->conf.cam_obmat); normalize_v3(obmat_no_scale[0]); normalize_v3(obmat_no_scale[1]); @@ -3307,43 +3318,45 @@ static void lineart_main_get_view_vector(LineartRenderBuffer *rb) invert_m4_m4(inv, obmat_no_scale); transpose_m4(inv); mul_v3_mat3_m4v3(trans, inv, direction); - copy_m4_m4(rb->cam_obmat, obmat_no_scale); - copy_v3db_v3fl(rb->view_vector, trans); + copy_m4_m4(ld->conf.cam_obmat, obmat_no_scale); + copy_v3db_v3fl(ld->conf.view_vector, trans); } -static void lineart_destroy_render_data(LineartRenderBuffer *rb) +static void lineart_destroy_render_data(LineartData *ld) { - if (rb == NULL) { + if (ld == NULL) { return; } - BLI_listbase_clear(&rb->chains); - BLI_listbase_clear(&rb->wasted_cuts); + BLI_listbase_clear(&ld->chains); + BLI_listbase_clear(&ld->wasted_cuts); - BLI_listbase_clear(&rb->vertex_buffer_pointers); - BLI_listbase_clear(&rb->line_buffer_pointers); - BLI_listbase_clear(&rb->triangle_buffer_pointers); + BLI_listbase_clear(&ld->geom.vertex_buffer_pointers); + BLI_listbase_clear(&ld->geom.line_buffer_pointers); + BLI_listbase_clear(&ld->geom.triangle_buffer_pointers); - BLI_spin_end(&rb->lock_task); - BLI_spin_end(&rb->lock_cuts); - BLI_spin_end(&rb->render_data_pool.lock_mem); + BLI_spin_end(&ld->lock_task); + BLI_spin_end(&ld->lock_cuts); + BLI_spin_end(&ld->render_data_pool.lock_mem); - if (rb->pending_edges.array) { - MEM_freeN(rb->pending_edges.array); + if (ld->pending_edges.array) { + MEM_freeN(ld->pending_edges.array); } - lineart_mem_destroy(&rb->render_data_pool); + lineart_free_bounding_area_memories(ld); + + lineart_mem_destroy(&ld->render_data_pool); } void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd) { - LineartRenderBuffer *rb = lmd->render_buffer_ptr; + LineartData *ld = lmd->la_data_ptr; - lineart_destroy_render_data(rb); + lineart_destroy_render_data(ld); - if (rb) { - MEM_freeN(rb); - lmd->render_buffer_ptr = NULL; + if (ld) { + MEM_freeN(ld); + lmd->la_data_ptr = NULL; } if (G.debug_value == 4000) { @@ -3367,17 +3380,17 @@ void MOD_lineart_clear_cache(struct LineartCache **lc) (*lc) = NULL; } -static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, - LineartGpencilModifierData *lmd, - Object *camera, - Object *active_camera, - LineartCache *lc) +static LineartData *lineart_create_render_buffer(Scene *scene, + LineartGpencilModifierData *lmd, + Object *camera, + Object *active_camera, + LineartCache *lc) { - LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer"); + LineartData *ld = MEM_callocN(sizeof(LineartData), "Line Art render buffer"); lmd->cache = lc; - lmd->render_buffer_ptr = rb; - lc->rb_edge_types = lmd->edge_types_override; + lmd->la_data_ptr = ld; + lc->all_enabled_edge_types = lmd->edge_types_override; if (!scene || !camera || !lc) { return NULL; @@ -3390,98 +3403,98 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, clipping_offset = 0.0001; } - copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]); + copy_v3db_v3fl(ld->conf.camera_pos, camera->obmat[3]); if (active_camera) { - copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]); + copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->obmat[3]); } - copy_m4_m4(rb->cam_obmat, camera->obmat); - rb->cam_is_persp = (c->type == CAM_PERSP); - rb->near_clip = c->clip_start + clipping_offset; - rb->far_clip = c->clip_end - clipping_offset; - rb->w = scene->r.xsch; - rb->h = scene->r.ysch; + copy_m4_m4(ld->conf.cam_obmat, camera->obmat); - if (rb->cam_is_persp) { - rb->tile_recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE; + ld->conf.cam_is_persp = (c->type == CAM_PERSP); + ld->conf.near_clip = c->clip_start + clipping_offset; + ld->conf.far_clip = c->clip_end - clipping_offset; + ld->w = scene->r.xsch; + ld->h = scene->r.ysch; + + if (ld->conf.cam_is_persp) { + ld->qtree.recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE; } else { - rb->tile_recursive_level = LRT_TILE_RECURSIVE_ORTHO; + ld->qtree.recursive_level = LRT_TILE_RECURSIVE_ORTHO; } - double asp = ((double)rb->w / (double)rb->h); - int fit = BKE_camera_sensor_fit(c->sensor_fit, rb->w, rb->h); - rb->shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp; - rb->shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp; + double asp = ((double)ld->w / (double)ld->h); + int fit = BKE_camera_sensor_fit(c->sensor_fit, ld->w, ld->h); + ld->conf.shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp; + ld->conf.shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp; - rb->overscan = lmd->overscan; + ld->conf.overscan = lmd->overscan; - rb->shift_x /= (1 + rb->overscan); - rb->shift_y /= (1 + rb->overscan); + ld->conf.shift_x /= (1 + ld->conf.overscan); + ld->conf.shift_y /= (1 + ld->conf.overscan); - rb->crease_threshold = cos(M_PI - lmd->crease_threshold); - rb->chaining_image_threshold = lmd->chaining_image_threshold; - rb->angle_splitting_threshold = lmd->angle_splitting_threshold; - rb->chain_smooth_tolerance = lmd->chain_smooth_tolerance; + ld->conf.crease_threshold = cos(M_PI - lmd->crease_threshold); + ld->conf.chaining_image_threshold = lmd->chaining_image_threshold; + ld->conf.angle_splitting_threshold = lmd->angle_splitting_threshold; + ld->conf.chain_smooth_tolerance = lmd->chain_smooth_tolerance; - rb->fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0; - rb->fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0; - rb->allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0; - rb->use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0; - rb->use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0; - rb->use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0; - rb->use_image_boundary_trimming = (lmd->calculation_flags & LRT_USE_IMAGE_BOUNDARY_TRIMMING) != - 0; + ld->conf.fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0; + ld->conf.fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0; + ld->conf.allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0; + ld->conf.use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0; + ld->conf.use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0; + ld->conf.use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0; + ld->conf.use_image_boundary_trimming = (lmd->calculation_flags & + LRT_USE_IMAGE_BOUNDARY_TRIMMING) != 0; /* See lineart_edge_from_triangle() for how this option may impact performance. */ - rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0; + ld->conf.allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0; - rb->allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0; + ld->conf.allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0; - rb->force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0; - rb->sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0; + ld->conf.force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0; + ld->conf.sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0; - rb->chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0; + ld->conf.chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0; /* This is used to limit calculation to a certain level to save time, lines who have higher * occlusion levels will get ignored. */ - rb->max_occlusion_level = lmd->level_end_override; + ld->conf.max_occlusion_level = lmd->level_end_override; - rb->use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0; + ld->conf.use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0; int16_t edge_types = lmd->edge_types_override; - rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0; - rb->use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0; - rb->use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0; - rb->use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0; - rb->use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0; - rb->use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0; + ld->conf.use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0; + ld->conf.use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0; + ld->conf.use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0; + ld->conf.use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0; + ld->conf.use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0; + ld->conf.use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0; + + ld->conf.filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0; + ld->conf.filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0; + ld->conf.filter_face_mark_boundaries = (lmd->calculation_flags & + LRT_FILTER_FACE_MARK_BOUNDARIES) != 0; + ld->conf.filter_face_mark_keep_contour = (lmd->calculation_flags & + LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0; - rb->filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0; - rb->filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0; - rb->filter_face_mark_boundaries = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_BOUNDARIES) != - 0; - rb->filter_face_mark_keep_contour = (lmd->calculation_flags & - LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0; + ld->chain_data_pool = &lc->chain_data_pool; - rb->chain_data_pool = &lc->chain_data_pool; + BLI_spin_init(&ld->lock_task); + BLI_spin_init(&ld->lock_cuts); + BLI_spin_init(&ld->render_data_pool.lock_mem); - BLI_spin_init(&rb->lock_task); - BLI_spin_init(&rb->lock_cuts); - BLI_spin_init(&rb->render_data_pool.lock_mem); + ld->thread_count = BKE_render_num_threads(&scene->r); - return rb; + return ld; } -static int lineart_triangle_size_get(const Scene *scene, LineartRenderBuffer *rb) +static int lineart_triangle_size_get(LineartData *ld) { - if (rb->thread_count == 0) { - rb->thread_count = BKE_render_num_threads(&scene->r); - } - return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (rb->thread_count)); + return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (ld->thread_count)); } -static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb) +static void lineart_main_bounding_area_make_initial(LineartData *ld) { /* Initial tile split is defined as 4 (subdivided as 4*4), increasing the value allows the * algorithm to build the acceleration structure for bigger scenes a little faster but not as @@ -3491,24 +3504,32 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb) int row, col; LineartBoundingArea *ba; + /* Always make sure the shortest side has at least LRT_BA_ROWS tiles. */ + if (ld->w > ld->h) { + sp_w = sp_h * ld->w / ld->h; + } + else { + sp_h = sp_w * ld->h / ld->w; + } + /* Because NDC (Normalized Device Coordinates) range is (-1,1), * so the span for each initial tile is double of that in the (0,1) range. */ double span_w = (double)1 / sp_w * 2.0; double span_h = (double)1 / sp_h * 2.0; - rb->tile_count_x = sp_w; - rb->tile_count_y = sp_h; - rb->width_per_tile = span_w; - rb->height_per_tile = span_h; + ld->qtree.count_x = sp_w; + ld->qtree.count_y = sp_h; + ld->qtree.tile_width = span_w; + ld->qtree.tile_height = span_h; - rb->bounding_area_count = sp_w * sp_h; - rb->initial_bounding_areas = lineart_mem_acquire( - &rb->render_data_pool, sizeof(LineartBoundingArea) * rb->bounding_area_count); + ld->qtree.tile_count = sp_w * sp_h; + ld->qtree.initials = lineart_mem_acquire(&ld->render_data_pool, + sizeof(LineartBoundingArea) * ld->qtree.tile_count); /* Initialize tiles. */ for (row = 0; row < sp_h; row++) { for (col = 0; col < sp_w; col++) { - ba = &rb->initial_bounding_areas[row * LRT_BA_ROWS + col]; + ba = &ld->qtree.initials[row * ld->qtree.count_x + col]; /* Set the four direction limits. */ ba->l = span_w * col - 1.0; @@ -3522,34 +3543,12 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb) /* Init linked_triangles array. */ ba->max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT; ba->max_line_count = LRT_TILE_EDGE_COUNT_INITIAL; - ba->linked_triangles = lineart_mem_acquire( - &rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count); - ba->linked_lines = lineart_mem_acquire(&rb->render_data_pool, - sizeof(LineartEdge *) * ba->max_line_count); + ba->linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba->max_triangle_count, + "ba_linked_triangles"); + ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba->max_line_count, + "ba_linked_lines"); - /* Link adjacent ones. */ - if (row) { - lineart_list_append_pointer_pool( - &ba->up, - &rb->render_data_pool, - &rb->initial_bounding_areas[(row - 1) * LRT_BA_ROWS + col]); - } - if (col) { - lineart_list_append_pointer_pool(&ba->lp, - &rb->render_data_pool, - &rb->initial_bounding_areas[row * LRT_BA_ROWS + col - 1]); - } - if (row != sp_h - 1) { - lineart_list_append_pointer_pool( - &ba->bp, - &rb->render_data_pool, - &rb->initial_bounding_areas[(row + 1) * LRT_BA_ROWS + col]); - } - if (col != sp_w - 1) { - lineart_list_append_pointer_pool(&ba->rp, - &rb->render_data_pool, - &rb->initial_bounding_areas[row * LRT_BA_ROWS + col + 1]); - } + BLI_spin_init(&ba->lock); } } } @@ -3557,11 +3556,11 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb) /** * Re-link adjacent tiles after one gets subdivided. */ -static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartBoundingArea *root) +static void lineart_bounding_areas_connect_new(LineartData *ld, LineartBoundingArea *root) { LineartBoundingArea *ba = root->child, *tba; LinkData *lip2, *next_lip; - LineartStaticMemPool *mph = &rb->render_data_pool; + LineartStaticMemPool *mph = &ld->render_data_pool; /* Inter-connection with newly created 4 child bounding areas. */ lineart_list_append_pointer_pool(&ba[1].rp, mph, &ba[0]); @@ -3697,17 +3696,59 @@ static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartB BLI_listbase_clear(&root->bp); } +static void lineart_bounding_areas_connect_recursive(LineartData *ld, LineartBoundingArea *root) +{ + if (root->child) { + lineart_bounding_areas_connect_new(ld, root); + for (int i = 0; i < 4; i++) { + lineart_bounding_areas_connect_recursive(ld, &root->child[i]); + } + } +} + +static void lineart_main_bounding_areas_connect_post(LineartData *ld) +{ + int total_tile_initial = ld->qtree.count_x * ld->qtree.count_y; + int tiles_per_row = ld->qtree.count_x; + + for (int row = 0; row < ld->qtree.count_y; row++) { + for (int col = 0; col < ld->qtree.count_x; col++) { + LineartBoundingArea *ba = &ld->qtree.initials[row * tiles_per_row + col]; + /* Link adjacent ones. */ + if (row) { + lineart_list_append_pointer_pool( + &ba->up, &ld->render_data_pool, &ld->qtree.initials[(row - 1) * tiles_per_row + col]); + } + if (col) { + lineart_list_append_pointer_pool( + &ba->lp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col - 1]); + } + if (row != ld->qtree.count_y - 1) { + lineart_list_append_pointer_pool( + &ba->bp, &ld->render_data_pool, &ld->qtree.initials[(row + 1) * tiles_per_row + col]); + } + if (col != ld->qtree.count_x - 1) { + lineart_list_append_pointer_pool( + &ba->rp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col + 1]); + } + } + } + for (int i = 0; i < total_tile_initial; i++) { + lineart_bounding_areas_connect_recursive(ld, &ld->qtree.initials[i]); + } +} + /** - * Subdivide a tile after one tile contains too many triangles. + * Subdivide a tile after one tile contains too many triangles, then re-link triangles into all the + * child tiles. */ -static void lineart_bounding_area_split(LineartRenderBuffer *rb, +static void lineart_bounding_area_split(LineartData *ld, LineartBoundingArea *root, int recursive_level) { - LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool, - sizeof(LineartBoundingArea) * 4); - LineartTriangle *tri; + LineartBoundingArea *ba = lineart_mem_acquire_thread(&ld->render_data_pool, + sizeof(LineartBoundingArea) * 4); ba[0].l = root->cx; ba[0].r = root->r; ba[0].u = root->u; @@ -3736,51 +3777,55 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb, ba[3].cx = (ba[3].l + ba[3].r) / 2; ba[3].cy = (ba[3].u + ba[3].b) / 2; - root->child = ba; - - lineart_bounding_areas_connect_new(rb, root); - - /* Init linked_triangles array. */ + /* Init linked_triangles array and locks. */ for (int i = 0; i < 4; i++) { ba[i].max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT; ba[i].max_line_count = LRT_TILE_EDGE_COUNT_INITIAL; - ba[i].linked_triangles = lineart_mem_acquire( - &rb->render_data_pool, sizeof(LineartTriangle *) * LRT_TILE_SPLITTING_TRIANGLE_LIMIT); - ba[i].linked_lines = lineart_mem_acquire(&rb->render_data_pool, - sizeof(LineartEdge *) * LRT_TILE_EDGE_COUNT_INITIAL); + ba[i].linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba[i].max_triangle_count, + "ba_linked_triangles"); + ba[i].linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba[i].max_line_count, + "ba_linked_lines"); + BLI_spin_init(&ba[i].lock); } for (int i = 0; i < root->triangle_count; i++) { - tri = root->linked_triangles[i]; - LineartBoundingArea *cba = root->child; + LineartTriangle *tri = root->linked_triangles[i]; + double b[4]; b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); - if (LRT_BOUND_AREA_CROSSES(b, &cba[0].l)) { - lineart_bounding_area_link_triangle(rb, &cba[0], tri, b, 0, recursive_level + 1, false); + + /* Re-link triangles into child tiles, not doing intersection lines during this because this + * batch of triangles are all tested with each other for intersections. */ + if (LRT_BOUND_AREA_CROSSES(b, &ba[0].l)) { + lineart_bounding_area_link_triangle(ld, &ba[0], tri, b, 0, recursive_level + 1, false, NULL); } - if (LRT_BOUND_AREA_CROSSES(b, &cba[1].l)) { - lineart_bounding_area_link_triangle(rb, &cba[1], tri, b, 0, recursive_level + 1, false); + if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) { + lineart_bounding_area_link_triangle(ld, &ba[1], tri, b, 0, recursive_level + 1, false, NULL); } - if (LRT_BOUND_AREA_CROSSES(b, &cba[2].l)) { - lineart_bounding_area_link_triangle(rb, &cba[2], tri, b, 0, recursive_level + 1, false); + if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) { + lineart_bounding_area_link_triangle(ld, &ba[2], tri, b, 0, recursive_level + 1, false, NULL); } - if (LRT_BOUND_AREA_CROSSES(b, &cba[3].l)) { - lineart_bounding_area_link_triangle(rb, &cba[3], tri, b, 0, recursive_level + 1, false); + if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) { + lineart_bounding_area_link_triangle(ld, &ba[3], tri, b, 0, recursive_level + 1, false, NULL); } } - rb->bounding_area_count += 3; + /* At this point the child tiles are fully initialized and it's safe for new triangles to be + * inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */ + root->child = ba; + + ld->qtree.tile_count += 3; } -static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb), +static bool lineart_bounding_area_edge_intersect(LineartData *UNUSED(fb), const double l[2], const double r[2], LineartBoundingArea *ba) { - double vx, vy; + double dx, dy; double converted[4]; double c1, c; @@ -3791,25 +3836,25 @@ static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb) return false; } - vx = l[0] - r[0]; - vy = l[1] - r[1]; + dx = l[0] - r[0]; + dy = l[1] - r[1]; - c1 = vx * (converted[2] - l[1]) - vy * (converted[0] - l[0]); + c1 = dx * (converted[2] - l[1]) - dy * (converted[0] - l[0]); c = c1; - c1 = vx * (converted[2] - l[1]) - vy * (converted[1] - l[0]); + c1 = dx * (converted[2] - l[1]) - dy * (converted[1] - l[0]); if (c1 * c <= 0) { return true; } c = c1; - c1 = vx * (converted[3] - l[1]) - vy * (converted[0] - l[0]); + c1 = dx * (converted[3] - l[1]) - dy * (converted[0] - l[0]); if (c1 * c <= 0) { return true; } c = c1; - c1 = vx * (converted[3] - l[1]) - vy * (converted[1] - l[0]); + c1 = dx * (converted[3] - l[1]) - dy * (converted[1] - l[0]); if (c1 * c <= 0) { return true; } @@ -3818,7 +3863,7 @@ static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb) return false; } -static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb, +static bool lineart_bounding_area_triangle_intersect(LineartData *fb, LineartTriangle *tri, LineartBoundingArea *ba) { @@ -3853,36 +3898,36 @@ static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb, } /** - * 1) Link triangles with bounding areas for later occlusion test. - * 2) Test triangles with existing(added previously) triangles for intersection lines. + * This function does two things: + * + * 1) Builds a quad-tree under ld->InitialBoundingAreas to achieve good geometry separation for + * fast overlapping test between triangles and lines. This acceleration structure makes the + * occlusion stage much faster. + * + * 2) Test triangles with other triangles that are previously linked into each tile + * (#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(LineartRenderBuffer *rb, +static void lineart_bounding_area_link_triangle(LineartData *ld, LineartBoundingArea *root_ba, LineartTriangle *tri, double *LRUB, int recursive, int recursive_level, - bool do_intersection) + bool do_intersection, + struct LineartIsecThread *th) { - if (!lineart_bounding_area_triangle_intersect(rb, tri, root_ba)) { + if (!lineart_bounding_area_triangle_intersect(ld, tri, root_ba)) { return; } - if (root_ba->child == NULL) { - lineart_bounding_area_triangle_add(rb, root_ba, tri); - /* If splitting doesn't improve triangle separation, then shouldn't allow splitting anymore. - * Here we use recursive limit. This is especially useful in orthographic render, - * where a lot of faces could easily line up perfectly in image space, - * which can not be separated by simply slicing the image tile. */ - if (root_ba->triangle_count >= LRT_TILE_SPLITTING_TRIANGLE_LIMIT && recursive && - recursive_level < rb->tile_recursive_level) { - lineart_bounding_area_split(rb, root_ba, recursive_level); - } - if (recursive && do_intersection && rb->use_intersections) { - lineart_triangle_intersect_in_bounding_area(rb, tri, root_ba); - } - } - else { - LineartBoundingArea *ba = root_ba->child; + + LineartBoundingArea *old_ba = root_ba; + + if (old_ba->child) { + /* If old_ba->child is not NULL, then tile splitting is fully finished, safe to directly insert + * into child tiles. */ double *B1 = LRUB; double b[4]; if (!LRUB) { @@ -3892,48 +3937,109 @@ static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb, b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); B1 = b; } - if (LRT_BOUND_AREA_CROSSES(B1, &ba[0].l)) { - lineart_bounding_area_link_triangle( - rb, &ba[0], tri, B1, recursive, recursive_level + 1, do_intersection); + for (int iba = 0; iba < 4; iba++) { + if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) { + lineart_bounding_area_link_triangle( + ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th); + } + } + return; + } + + /* When splitting tiles, triangles are relinked into new tiles by a single thread, #th is NULL + * in that situation. */ + if (th) { + BLI_spin_lock(&old_ba->lock); + } + + /* If there are still space left in this tile for insertion. */ + if (old_ba->triangle_count < old_ba->max_triangle_count) { + const uint32_t old_tri_count = old_ba->triangle_count; + + old_ba->linked_triangles[old_ba->triangle_count++] = tri; + + /* Do intersections in place. */ + if (do_intersection && ld->conf.use_intersections) { + lineart_triangle_intersect_in_bounding_area(tri, old_ba, th, old_tri_count); + } + + if (th) { + BLI_spin_unlock(&old_ba->lock); } - if (LRT_BOUND_AREA_CROSSES(B1, &ba[1].l)) { - lineart_bounding_area_link_triangle( - rb, &ba[1], tri, B1, recursive, recursive_level + 1, do_intersection); + } + else { /* We need to wait for either splitting or array extension to be done. */ + + if (recursive_level < ld->qtree.recursive_level) { + if (!old_ba->child) { + /* old_ba->child==NULL, means we are the thread that's doing the splitting. */ + lineart_bounding_area_split(ld, old_ba, recursive_level); + } /* Otherwise other thread has completed the splitting process. */ + } + else { + if (old_ba->triangle_count == old_ba->max_triangle_count) { + /* Means we are the thread that's doing the extension. */ + lineart_bounding_area_triangle_reallocate(old_ba); + } /* Otherwise other thread has completed the extending the array. */ } - if (LRT_BOUND_AREA_CROSSES(B1, &ba[2].l)) { - lineart_bounding_area_link_triangle( - rb, &ba[2], tri, B1, recursive, recursive_level + 1, do_intersection); + + /* Unlock before going into recursive call. */ + if (th) { + BLI_spin_unlock(&old_ba->lock); + } + + /* Of course we still have our own triangle needs to be added. */ + lineart_bounding_area_link_triangle( + ld, root_ba, tri, LRUB, recursive, recursive_level, do_intersection, th); + } +} + +static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive) +{ + BLI_spin_end(&ba->lock); + if (ba->linked_lines) { + MEM_freeN(ba->linked_lines); + } + if (ba->linked_triangles) { + MEM_freeN(ba->linked_triangles); + } + if (recursive && ba->child) { + for (int i = 0; i < 4; i++) { + lineart_free_bounding_area_memory(&ba->child[i], recursive); } - if (LRT_BOUND_AREA_CROSSES(B1, &ba[3].l)) { - lineart_bounding_area_link_triangle( - rb, &ba[3], tri, B1, recursive, recursive_level + 1, do_intersection); + } +} +static void lineart_free_bounding_area_memories(LineartData *ld) +{ + for (int i = 0; i < ld->qtree.count_y; i++) { + for (int j = 0; j < ld->qtree.count_x; j++) { + lineart_free_bounding_area_memory(&ld->qtree.initials[i * ld->qtree.count_x + j], true); } } } -static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb, +static void lineart_bounding_area_link_edge(LineartData *ld, LineartBoundingArea *root_ba, LineartEdge *e) { if (root_ba->child == NULL) { - lineart_bounding_area_line_add(rb, root_ba, e); + lineart_bounding_area_line_add(root_ba, e); } else { if (lineart_bounding_area_edge_intersect( - rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) { - lineart_bounding_area_link_edge(rb, &root_ba->child[0], e); + ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) { + lineart_bounding_area_link_edge(ld, &root_ba->child[0], e); } if (lineart_bounding_area_edge_intersect( - rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) { - lineart_bounding_area_link_edge(rb, &root_ba->child[1], e); + ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) { + lineart_bounding_area_link_edge(ld, &root_ba->child[1], e); } if (lineart_bounding_area_edge_intersect( - rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) { - lineart_bounding_area_link_edge(rb, &root_ba->child[2], e); + ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) { + lineart_bounding_area_link_edge(ld, &root_ba->child[2], e); } if (lineart_bounding_area_edge_intersect( - rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) { - lineart_bounding_area_link_edge(rb, &root_ba->child[3], e); + ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) { + lineart_bounding_area_link_edge(ld, &root_ba->child[3], e); } } } @@ -3941,16 +4047,16 @@ static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb, /** * Link lines to their respective bounding areas. */ -static void lineart_main_link_lines(LineartRenderBuffer *rb) +static void lineart_main_link_lines(LineartData *ld) { LRT_ITER_ALL_LINES_BEGIN { int r1, r2, c1, c2, row, col; - if (lineart_get_edge_bounding_areas(rb, e, &r1, &r2, &c1, &c2)) { + if (lineart_get_edge_bounding_areas(ld, e, &r1, &r2, &c1, &c2)) { for (row = r1; row != r2 + 1; row++) { for (col = c1; col != c2 + 1; col++) { lineart_bounding_area_link_edge( - rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], e); + ld, &ld->qtree.initials[row * ld->qtree.count_x + col], e); } } } @@ -3958,14 +4064,10 @@ static void lineart_main_link_lines(LineartRenderBuffer *rb) LRT_ITER_ALL_LINES_END } -static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb, - LineartTriangle *tri, - int *rowbegin, - int *rowend, - int *colbegin, - int *colend) +static bool lineart_get_triangle_bounding_areas( + LineartData *ld, LineartTriangle *tri, int *rowbegin, int *rowend, int *colbegin, int *colend) { - double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile; + double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; double b[4]; if (!tri->v[0] || !tri->v[1] || !tri->v[2]) { @@ -3983,14 +4085,14 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb, (*colbegin) = (int)((b[0] + 1.0) / sp_w); (*colend) = (int)((b[1] + 1.0) / sp_w); - (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1; - (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1; + (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1; + (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1; - if ((*colend) >= rb->tile_count_x) { - (*colend) = rb->tile_count_x - 1; + if ((*colend) >= ld->qtree.count_x) { + (*colend) = ld->qtree.count_x - 1; } - if ((*rowend) >= rb->tile_count_y) { - (*rowend) = rb->tile_count_y - 1; + if ((*rowend) >= ld->qtree.count_y) { + (*rowend) = ld->qtree.count_y - 1; } if ((*colbegin) < 0) { (*colbegin) = 0; @@ -4002,14 +4104,10 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb, return true; } -static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb, - LineartEdge *e, - int *rowbegin, - int *rowend, - int *colbegin, - int *colend) +static bool lineart_get_edge_bounding_areas( + LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend) { - double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile; + double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; double b[4]; if (!e->v1 || !e->v2) { @@ -4031,31 +4129,29 @@ static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb, (*colbegin) = (int)((b[0] + 1.0) / sp_w); (*colend) = (int)((b[1] + 1.0) / sp_w); - (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1; - (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1; + (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1; + (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1; /* It's possible that the line stretches too much out to the side, resulting negative value. */ if ((*rowend) < (*rowbegin)) { - (*rowend) = rb->tile_count_y - 1; + (*rowend) = ld->qtree.count_y - 1; } if ((*colend) < (*colbegin)) { - (*colend) = rb->tile_count_x - 1; + (*colend) = ld->qtree.count_x - 1; } - CLAMP((*colbegin), 0, rb->tile_count_x - 1); - CLAMP((*rowbegin), 0, rb->tile_count_y - 1); - CLAMP((*colend), 0, rb->tile_count_x - 1); - CLAMP((*rowend), 0, rb->tile_count_y - 1); + CLAMP((*colbegin), 0, ld->qtree.count_x - 1); + CLAMP((*rowbegin), 0, ld->qtree.count_y - 1); + CLAMP((*colend), 0, ld->qtree.count_x - 1); + CLAMP((*rowend), 0, ld->qtree.count_y - 1); return true; } -LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb, - double x, - double y) +LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y) { - double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile; + double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; int col, row; if (x > 1 || x < -1 || y > 1 || y < -1) { @@ -4063,13 +4159,13 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r } col = (int)((x + 1.0) / sp_w); - row = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1; + row = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1; - if (col >= rb->tile_count_x) { - col = rb->tile_count_x - 1; + if (col >= ld->qtree.count_x) { + col = ld->qtree.count_x - 1; } - if (row >= rb->tile_count_y) { - row = rb->tile_count_y - 1; + if (row >= ld->qtree.count_y) { + row = ld->qtree.count_y - 1; } if (col < 0) { col = 0; @@ -4078,29 +4174,29 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r row = 0; } - return &rb->initial_bounding_areas[row * LRT_BA_ROWS + col]; + return &ld->qtree.initials[row * ld->qtree.count_x + col]; } -static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y) +static LineartBoundingArea *lineart_get_bounding_area(LineartData *ld, double x, double y) { LineartBoundingArea *iba; - double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile; + double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; int c = (int)((x + 1.0) / sp_w); - int r = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1; + int r = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1; if (r < 0) { r = 0; } if (c < 0) { c = 0; } - if (r >= rb->tile_count_y) { - r = rb->tile_count_y - 1; + if (r >= ld->qtree.count_y) { + r = ld->qtree.count_y - 1; } - if (c >= rb->tile_count_x) { - c = rb->tile_count_x - 1; + if (c >= ld->qtree.count_x) { + c = ld->qtree.count_x - 1; } - iba = &rb->initial_bounding_areas[r * LRT_BA_ROWS + c]; + iba = &ld->qtree.initials[r * ld->qtree.count_x + c]; while (iba->child) { if (x > iba->cx) { if (y > iba->cy) { @@ -4122,48 +4218,152 @@ static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, d return iba; } -LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y) +LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y) { LineartBoundingArea *ba; - if ((ba = MOD_lineart_get_parent_bounding_area(rb, x, y)) != NULL) { - return lineart_get_bounding_area(rb, x, y); + if ((ba = MOD_lineart_get_parent_bounding_area(ld, x, y)) != NULL) { + return lineart_get_bounding_area(ld, x, y); } return NULL; } -/** - * Sequentially add triangles into render buffer. This also does intersection along the way. - */ -static void lineart_main_add_triangles(LineartRenderBuffer *rb) +static void lineart_add_triangles_worker(TaskPool *__restrict UNUSED(pool), LineartIsecThread *th) { - LineartTriangle *tri; - int i, lim; - int x1, x2, y1, y2; - int r, co; - - LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) { - tri = eln->pointer; - lim = eln->element_count; - for (i = 0; i < lim; i++) { - if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) { - tri = (void *)(((uchar *)tri) + rb->triangle_size); - continue; - } - if (lineart_get_triangle_bounding_areas(rb, tri, &y1, &y2, &x1, &x2)) { - for (co = x1; co <= x2; co++) { - for (r = y1; r <= y2; r++) { - lineart_bounding_area_link_triangle(rb, - &rb->initial_bounding_areas[r * LRT_BA_ROWS + co], - tri, - 0, - 1, - 0, - (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION))); - } + LineartData *ld = th->ld; + int _dir_control = 0; + while (lineart_schedule_new_triangle_task(th)) { + for (LineartElementLinkNode *eln = th->pending_from; eln != th->pending_to->next; + eln = eln->next) { + int index_start = eln == th->pending_from ? th->index_from : 0; + int index_end = eln == th->pending_to ? th->index_to : eln->element_count; + LineartTriangle *tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * index_start); + for (int ei = index_start; ei < index_end; ei++) { + int x1, x2, y1, y2; + int r, co; + if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) { + tri = (void *)(((uchar *)tri) + ld->sizeof_triangle); + continue; } - } /* Else throw away. */ - tri = (void *)(((uchar *)tri) + rb->triangle_size); + if (lineart_get_triangle_bounding_areas(ld, tri, &y1, &y2, &x1, &x2)) { + _dir_control++; + for (co = x1; co <= x2; co++) { + for (r = y1; r <= y2; r++) { + lineart_bounding_area_link_triangle(ld, + &ld->qtree.initials[r * ld->qtree.count_x + co], + tri, + 0, + 1, + 0, + (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)), + th); + } + } + } /* Else throw away. */ + tri = (void *)(((uchar *)tri) + ld->sizeof_triangle); + } + } + } +} + +static void lineart_create_edges_from_isec_data(LineartIsecData *d) +{ + LineartData *ld = d->ld; + double ZMax = ld->conf.far_clip; + double ZMin = ld->conf.near_clip; + + for (int i = 0; i < d->thread_count; i++) { + LineartIsecThread *th = &d->threads[i]; + if (G.debug_value == 4000) { + printf("Thread %d isec generated %d lines.\n", i, th->current); } + if (!th->current) { + continue; + } + /* We don't care about removing duplicated vert in this method, chaining can handle that, + * and it saves us from using locks and look up tables. */ + LineartVertIntersection *v = lineart_mem_acquire( + &ld->render_data_pool, sizeof(LineartVertIntersection) * th->current * 2); + LineartEdge *e = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdge) * th->current); + LineartEdgeSegment *es = lineart_mem_acquire(&ld->render_data_pool, + sizeof(LineartEdgeSegment) * th->current); + for (int j = 0; j < th->current; j++) { + LineartVertIntersection *v1i = v; + LineartVertIntersection *v2i = v + 1; + LineartIsecSingle *is = &th->array[j]; + v1i->intersecting_with = is->tri1; + v2i->intersecting_with = is->tri2; + LineartVert *v1 = (LineartVert *)v1i; + LineartVert *v2 = (LineartVert *)v2i; + v1->flag |= LRT_VERT_HAS_INTERSECTION_DATA; + v2->flag |= LRT_VERT_HAS_INTERSECTION_DATA; + copy_v3db_v3fl(v1->gloc, is->v1); + copy_v3db_v3fl(v2->gloc, is->v2); + /* The intersection line has been generated only in geometry space, so we need to transform + * them as well. */ + mul_v4_m4v3_db(v1->fbcoord, ld->conf.view_projection, v1->gloc); + mul_v4_m4v3_db(v2->fbcoord, ld->conf.view_projection, v2->gloc); + mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3])); + mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3])); + + v1->fbcoord[0] -= ld->conf.shift_x * 2; + v1->fbcoord[1] -= ld->conf.shift_y * 2; + v2->fbcoord[0] -= ld->conf.shift_x * 2; + v2->fbcoord[1] -= ld->conf.shift_y * 2; + + /* This z transformation is not the same as the rest of the part, because the data don't go + * through normal perspective division calls in the pipeline, but this way the 3D result and + * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke + * generation anyway. */ + v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin)); + v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin)); + e->v1 = v1; + e->v2 = v2; + e->t1 = is->tri1; + e->t2 = is->tri2; + e->flags = LRT_EDGE_FLAG_INTERSECTION; + e->intersection_mask = (is->tri1->intersection_mask | is->tri2->intersection_mask); + BLI_addtail(&e->segments, es); + + lineart_add_edge_to_array(&ld->pending_edges, e); + + v += 2; + e++; + es++; + } + } +} + +/** + * Sequentially add triangles into render buffer, intersection lines between those triangles will + * also be computed at the same time. + */ +static void lineart_main_add_triangles(LineartData *ld) +{ + double t_start; + if (G.debug_value == 4000) { + t_start = PIL_check_seconds_timer(); + } + + /* Initialize per-thread data for thread task scheduling information and storing intersection + * results. */ + LineartIsecData d = {0}; + lineart_init_isec_thread(&d, ld, ld->thread_count); + + TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH); + for (int i = 0; i < ld->thread_count; i++) { + BLI_task_pool_push(tp, (TaskRunFunction)lineart_add_triangles_worker, &d.threads[i], 0, NULL); + } + BLI_task_pool_work_and_wait(tp); + BLI_task_pool_free(tp); + + /* Create actual lineart edges from intersection results. */ + lineart_create_edges_from_isec_data(&d); + + lineart_destroy_isec_thread(&d); + + if (G.debug_value == 4000) { + double t_elapsed = PIL_check_seconds_timer() - t_start; + printf("Line art intersection time: %f\n", t_elapsed); } } @@ -4171,8 +4371,7 @@ static void lineart_main_add_triangles(LineartRenderBuffer *rb) * This function gets the tile for the point `e->v1`, and later use #lineart_bounding_area_next() * to get next along the way. */ -static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb, - LineartEdge *e) +static LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, LineartEdge *e) { double data[2] = {e->v1->fbcoord[0], e->v1->fbcoord[1]}; double LU[2] = {-1, 1}, RU[2] = {1, 1}, LB[2] = {-1, -1}, RB[2] = {1, -1}; @@ -4180,7 +4379,7 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer bool p_unused; if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) { - return lineart_get_bounding_area(rb, data[0], data[1]); + return lineart_get_bounding_area(ld, data[0], data[1]); } if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr, &p_unused) && @@ -4201,7 +4400,7 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer } interp_v2_v2v2_db(data, e->v1->fbcoord, e->v2->fbcoord, r); - return lineart_get_bounding_area(rb, data[0], data[1]); + return lineart_get_bounding_area(ld, data[0], data[1]); } /** @@ -4432,7 +4631,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartCache **cached_result, bool enable_stroke_depth_offset) { - LineartRenderBuffer *rb; + LineartData *ld; Scene *scene = DEG_get_evaluated_scene(depsgraph); int intersections_only = 0; /* Not used right now, but preserve for future. */ Object *use_camera; @@ -4443,8 +4642,6 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, t_start = PIL_check_seconds_timer(); } - BKE_scene_camera_switch_update(scene); - if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) { if (!lmd->source_camera || (use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type != @@ -4453,6 +4650,9 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, } } else { + + BKE_scene_camera_switch_update(scene); + if (!scene->camera) { return false; } @@ -4462,54 +4662,53 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartCache *lc = lineart_init_cache(); *cached_result = lc; - rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc); + ld = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc); /* Triangle thread testing data size varies depending on the thread count. * See definition of LineartTriangleThread for details. */ - rb->triangle_size = lineart_triangle_size_get(scene, rb); - - /* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */ - rb->_source_type = lmd->source_type; - rb->_source_collection = lmd->source_collection; - rb->_source_object = lmd->source_object; + ld->sizeof_triangle = lineart_triangle_size_get(ld); /* Get view vector before loading geometries, because we detect feature lines there. */ - lineart_main_get_view_vector(rb); + lineart_main_get_view_vector(ld); lineart_main_load_geometries( - depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS); + depsgraph, scene, use_camera, ld, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS); - if (!rb->vertex_buffer_pointers.first) { + if (!ld->geom.vertex_buffer_pointers.first) { /* No geometry loaded, return early. */ return true; } /* Initialize the bounding box acceleration structure, it's a lot like BVH in 3D. */ - lineart_main_bounding_area_make_initial(rb); + lineart_main_bounding_area_make_initial(ld); /* We need to get cut into triangles that are crossing near/far plans, only this way can we get * correct coordinates of those clipped lines. Done in two steps, * setting clip_far==false for near plane. */ - lineart_main_cull_triangles(rb, false); + lineart_main_cull_triangles(ld, false); /* `clip_far == true` for far plane. */ - lineart_main_cull_triangles(rb, true); + lineart_main_cull_triangles(ld, true); /* At this point triangle adjacent info pointers is no longer needed, free them. */ - lineart_main_free_adjacent_data(rb); + lineart_main_free_adjacent_data(ld); /* Do the perspective division after clipping is done. */ - lineart_main_perspective_division(rb); + lineart_main_perspective_division(ld); - lineart_main_discard_out_of_frame_edges(rb); + lineart_main_discard_out_of_frame_edges(ld); /* Triangle intersections are done here during sequential adding of them. Only after this, * triangles and lines are all linked with acceleration structure, and the 2D occlusion stage * can do its job. */ - lineart_main_add_triangles(rb); + lineart_main_add_triangles(ld); + + /* Re-link bounding areas because they have been subdivided by worker threads and we need + * adjacent info. */ + lineart_main_bounding_areas_connect_post(ld); /* Link lines to acceleration structure, this can only be done after perspective division, if * we do it after triangles being added, the acceleration structure has already been * subdivided, this way we do less list manipulations. */ - lineart_main_link_lines(rb); + lineart_main_link_lines(ld); /* "intersection_only" is preserved for being called in a standalone fashion. * If so the data will already be available at the stage. Otherwise we do the occlusion and @@ -4518,54 +4717,54 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, if (!intersections_only) { /* Occlusion is work-and-wait. This call will not return before work is completed. */ - lineart_main_occlusion_begin(rb); + lineart_main_occlusion_begin(ld); /* Chaining is all single threaded. See lineart_chain.c * In this particular call, only lines that are geometrically connected (share the _exact_ * same end point) will be chained together. */ - MOD_lineart_chain_feature_lines(rb); + MOD_lineart_chain_feature_lines(ld); /* We are unable to take care of occlusion if we only connect end points, so here we do a * spit, where the splitting point could be any cut in e->segments. */ - MOD_lineart_chain_split_for_fixed_occlusion(rb); + MOD_lineart_chain_split_for_fixed_occlusion(ld); /* Then we connect chains based on the _proximity_ of their end points in image space, here's * the place threshold value gets involved. */ - MOD_lineart_chain_connect(rb); + MOD_lineart_chain_connect(ld); float *t_image = &lmd->chaining_image_threshold; /* This configuration ensures there won't be accidental lost of short unchained segments. */ - MOD_lineart_chain_discard_short(rb, MIN2(*t_image, 0.001f) - FLT_EPSILON); + MOD_lineart_chain_discard_short(ld, MIN2(*t_image, 0.001f) - FLT_EPSILON); - if (rb->chain_smooth_tolerance > FLT_EPSILON) { + if (ld->conf.chain_smooth_tolerance > FLT_EPSILON) { /* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best * effective range in image-space (Coordinate only goes from -1 to 1). This value is * somewhat arbitrary, but works best for the moment. */ - MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50); + MOD_lineart_smooth_chains(ld, ld->conf.chain_smooth_tolerance / 50); } - if (rb->use_image_boundary_trimming) { - MOD_lineart_chain_clip_at_border(rb); + if (ld->conf.use_image_boundary_trimming) { + MOD_lineart_chain_clip_at_border(ld); } - if (rb->angle_splitting_threshold > FLT_EPSILON) { - MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold); + if (ld->conf.angle_splitting_threshold > FLT_EPSILON) { + MOD_lineart_chain_split_angle(ld, ld->conf.angle_splitting_threshold); } if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) { MOD_lineart_chain_offset_towards_camera( - rb, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA); + ld, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA); } /* Finally transfer the result list into cache. */ - memcpy(&lc->chains, &rb->chains, sizeof(ListBase)); + memcpy(&lc->chains, &ld->chains, sizeof(ListBase)); /* At last, we need to clear flags so we don't confuse GPencil generation calls. */ MOD_lineart_chain_clear_picked_flag(lc); } if (G.debug_value == 4000) { - lineart_count_and_print_render_buffer_memory(rb); + lineart_count_and_print_render_buffer_memory(ld); double t_elapsed = PIL_check_seconds_timer() - t_start; printf("Line art total time: %lf\n", t_elapsed); @@ -4574,15 +4773,15 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, return true; } -static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartRenderBuffer *rb) +static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartData *ld) { int types = 0; - types |= rb->use_contour ? LRT_EDGE_FLAG_CONTOUR : 0; - types |= rb->use_crease ? LRT_EDGE_FLAG_CREASE : 0; - types |= rb->use_material ? LRT_EDGE_FLAG_MATERIAL : 0; - types |= rb->use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0; - types |= rb->use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0; - types |= rb->use_loose ? LRT_EDGE_FLAG_LOOSE : 0; + types |= ld->conf.use_contour ? LRT_EDGE_FLAG_CONTOUR : 0; + types |= ld->conf.use_crease ? LRT_EDGE_FLAG_CREASE : 0; + types |= ld->conf.use_material ? LRT_EDGE_FLAG_MATERIAL : 0; + types |= ld->conf.use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0; + types |= ld->conf.use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0; + types |= ld->conf.use_loose ? LRT_EDGE_FLAG_LOOSE : 0; return types; } @@ -4601,7 +4800,7 @@ static void lineart_gpencil_generate(LineartCache *cache, uchar mask_switches, uchar material_mask_bits, uchar intersection_mask, - short thickness, + int16_t thickness, float opacity, const char *source_vgname, const char *vgname, @@ -4630,7 +4829,7 @@ static void lineart_gpencil_generate(LineartCache *cache, /* (!orig_col && !orig_ob) means the whole scene is selected. */ - int enabled_types = cache->rb_edge_types; + int enabled_types = cache->all_enabled_edge_types; bool invert_input = modifier_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP; bool match_output = modifier_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP; @@ -4760,16 +4959,16 @@ void MOD_lineart_gpencil_generate(LineartCache *cache, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, - char source_type, + int8_t source_type, void *source_reference, int level_start, int level_end, int mat_nr, - short edge_types, + int16_t edge_types, uchar mask_switches, uchar material_mask_bits, uchar intersection_mask, - short thickness, + int16_t thickness, float opacity, const char *source_vgname, const char *vgname, @@ -4782,7 +4981,7 @@ void MOD_lineart_gpencil_generate(LineartCache *cache, Object *source_object = NULL; Collection *source_collection = NULL; - short use_types = 0; + int16_t use_types = 0; if (source_type == LRT_SOURCE_OBJECT) { if (!source_reference) { return; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h index 1a197c8b4b7..5e24061bd78 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h @@ -18,7 +18,7 @@ #include <string.h> struct LineartEdge; -struct LineartRenderBuffer; +struct LineartData; struct LineartStaticMemPool; struct LineartStaticMemPoolNode; @@ -49,7 +49,6 @@ void *lineart_mem_acquire(struct LineartStaticMemPool *smp, size_t size); void *lineart_mem_acquire_thread(struct LineartStaticMemPool *smp, size_t size); void lineart_mem_destroy(struct LineartStaticMemPool *smp); -void lineart_prepend_edge_direct(void **list_head, void *node); void lineart_prepend_pool(LinkNode **first, struct LineartStaticMemPool *smp, void *link); void lineart_matrix_ortho_44d(double (*mProjection)[4], @@ -62,14 +61,14 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4], void lineart_matrix_perspective_44d( double (*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax); -int lineart_count_intersection_segment_count(struct LineartRenderBuffer *rb); +int lineart_count_intersection_segment_count(struct LineartData *ld); -void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb); +void lineart_count_and_print_render_buffer_memory(struct LineartData *ld); #define LRT_ITER_ALL_LINES_BEGIN \ LineartEdge *e; \ - for (int i = 0; i < rb->pending_edges.next; i++) { \ - e = rb->pending_edges.array[i]; + for (int i = 0; i < ld->pending_edges.next; i++) { \ + e = ld->pending_edges.array[i]; #define LRT_ITER_ALL_LINES_NEXT ; /* Doesn't do anything now with new array setup. */ @@ -80,9 +79,9 @@ void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb #define LRT_BOUND_AREA_CROSSES(b1, b2) \ ((b1)[0] < (b2)[1] && (b1)[1] > (b2)[0] && (b1)[3] < (b2)[2] && (b1)[2] > (b2)[3]) -/* Initial bounding area row/column count, setting 4 is the simplest way algorithm could function - * efficiently. */ -#define LRT_BA_ROWS 4 +/* Initial bounding area row/column count, setting 10 is tested to be relatively optimal for the + * performance under current algorithm. */ +#define LRT_BA_ROWS 10 #ifdef __cplusplus extern "C" { diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c index 2b60fc45800..bbf88985e6a 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c @@ -141,8 +141,8 @@ static bool bake_strokes(Object *ob, if (!is_first) { MOD_lineart_clear_cache(&local_lc); } - /* Restore the original cache pointer so the modifiers below still have access to the - * "global" cache. */ + /* Restore the original cache pointer so the modifiers below still have access to the "global" + * cache. */ lmd->cache = gpd->runtime.lineart_cache; } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c index 4ea17b25995..95647f2dd75 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c @@ -144,13 +144,6 @@ void lineart_mem_destroy(LineartStaticMemPool *smp) } } -void lineart_prepend_edge_direct(void **list_head, void *node) -{ - LineartEdge *e_n = (LineartEdge *)node; - e_n->next = (*list_head); - (*list_head) = e_n; -} - void lineart_prepend_pool(LinkNode **first, LineartStaticMemPool *smp, void *link) { LinkNode *ln = lineart_mem_acquire_thread(smp, sizeof(LinkNode)); @@ -212,13 +205,13 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4], mProjection[3][3] = 1.0f; } -void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb) +void lineart_count_and_print_render_buffer_memory(LineartData *ld) { size_t total = 0; size_t sum_this = 0; size_t count_this = 0; - LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &rb->render_data_pool.pools) { + LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &ld->render_data_pool.pools) { count_this++; sum_this += LRT_MEMORY_POOL_1MB; } @@ -227,7 +220,7 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb) sum_this = 0; count_this = 0; - LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->line_buffer_pointers) { + LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.line_buffer_pointers) { count_this++; sum_this += reln->element_count * sizeof(LineartEdge); } @@ -236,9 +229,9 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb) sum_this = 0; count_this = 0; - LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) { + LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.triangle_buffer_pointers) { count_this++; - sum_this += reln->element_count * rb->triangle_size; + sum_this += reln->element_count * ld->sizeof_triangle; } printf(" allocated %zu triangle blocks, total %zu Bytes.\n", count_this, sum_this); total += sum_this; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index e78c86ae196..cadc2c4445b 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -21,13 +21,12 @@ set(INC ../imbuf ../makesdna ../makesrna - ../windowmanager + # For theme color access. ../editors/include - # For node muting stuff... + # For node muting stuff. ../nodes - ../nodes/intern ../../../intern/atomic ../../../intern/clog @@ -447,18 +446,18 @@ set(SRC_SHADER_CREATE_INFOS ../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh ../draw/engines/gpencil/shaders/infos/gpencil_info.hh ../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh - ../draw/engines/overlay/shaders/infos/antialiasing_info.hh - ../draw/engines/overlay/shaders/infos/armature_info.hh - ../draw/engines/overlay/shaders/infos/background_info.hh - ../draw/engines/overlay/shaders/infos/edit_mode_info.hh - ../draw/engines/overlay/shaders/infos/extra_info.hh - ../draw/engines/overlay/shaders/infos/facing_info.hh - ../draw/engines/overlay/shaders/infos/grid_info.hh - ../draw/engines/overlay/shaders/infos/outline_info.hh - ../draw/engines/overlay/shaders/infos/paint_info.hh - ../draw/engines/overlay/shaders/infos/sculpt_info.hh - ../draw/engines/overlay/shaders/infos/volume_info.hh - ../draw/engines/overlay/shaders/infos/wireframe_info.hh + ../draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh + ../draw/engines/overlay/shaders/infos/overlay_armature_info.hh + ../draw/engines/overlay/shaders/infos/overlay_background_info.hh + ../draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh + ../draw/engines/overlay/shaders/infos/overlay_extra_info.hh + ../draw/engines/overlay/shaders/infos/overlay_facing_info.hh + ../draw/engines/overlay/shaders/infos/overlay_grid_info.hh + ../draw/engines/overlay/shaders/infos/overlay_outline_info.hh + ../draw/engines/overlay/shaders/infos/overlay_paint_info.hh + ../draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh + ../draw/engines/overlay/shaders/infos/overlay_volume_info.hh + ../draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh ../draw/engines/select/shaders/infos/select_id_info.hh ../draw/engines/workbench/shaders/infos/workbench_composite_info.hh ../draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 1af0080baef..1fe3b363687 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -10,6 +10,7 @@ #include <stddef.h> #include "BKE_attribute.h" +#include "BKE_pbvh.h" #ifdef __cplusplus extern "C" { @@ -20,6 +21,7 @@ struct CCGElem; struct CCGKey; struct DMFlagMat; struct GSet; +struct TableGSet; struct MLoop; struct MLoopCol; struct MLoopTri; @@ -29,6 +31,9 @@ struct MVert; struct Mesh; struct PBVH; struct SubdivCCG; +struct CustomData; + +typedef struct PBVHGPUFormat PBVHGPUFormat; /** * Buffers for drawing from PBVH grids. @@ -78,36 +83,46 @@ enum { }; /** + * Creates a vertex buffer (coordinate, normal, color) and, + * if smooth shading, an element index buffer. * Threaded: do not call any functions that use OpenGL calls! */ -void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, +void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, + GPU_PBVH_Buffers *buffers, const struct MVert *mvert, - const float (*vert_normals)[3], + const CustomData *vdata, + const CustomData *ldata, const float *vmask, - const void *vcol_data, - int vcol_type, - AttributeDomain vcol_domain, const int *sculpt_face_sets, - int face_sets_color_seed, - int face_sets_color_default, - int update_flags); + const int face_sets_color_seed, + const int face_sets_color_default, + const int update_flags, + const float (*vert_normals)[3]); + +bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type, + PBVHGPUFormat *vbo_id, + const struct CustomData *vdata, + const struct CustomData *ldata, + bool active_attrs_only); /** * Creates a vertex buffer (coordinate, normal, color) and, * if smooth shading, an element index buffer. * Threaded: do not call any functions that use OpenGL calls! */ -void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, +void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id, + struct GPU_PBVH_Buffers *buffers, struct BMesh *bm, struct GSet *bm_faces, struct GSet *bm_unique_verts, struct GSet *bm_other_verts, - int update_flags); + const int update_flags); /** * Threaded: do not call any functions that use OpenGL calls! */ -void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, +void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id, + GPU_PBVH_Buffers *buffers, struct SubdivCCG *subdiv_ccg, struct CCGElem **grids, const struct DMFlagMat *grid_flag_mats, @@ -120,7 +135,8 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, int update_flags); /** - * Finish update. Not thread safe, must run in OpenGL main thread. + * Finish update. Not thread safe, must run in OpenGL main + * thread. */ void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers); @@ -133,9 +149,11 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires); short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers); - bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers); +PBVHGPUFormat *GPU_pbvh_make_format(void); +void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index fff90e6f8ff..c0633f0323d 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -7,7 +7,7 @@ #pragma once -#include "DNA_customdata_types.h" /* for CustomDataType */ +#include "DNA_customdata_types.h" /* for eCustomDataType */ #include "DNA_image_types.h" #include "DNA_listBase.h" @@ -130,9 +130,9 @@ typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOu GPUNodeLink *GPU_constant(const float *num); GPUNodeLink *GPU_uniform(const float *num); -GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name); +GPUNodeLink *GPU_attribute(GPUMaterial *mat, eCustomDataType type, const char *name); GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat, - CustomDataType type, + eCustomDataType type, const char *name, eGPUDefaultValue default_value); GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli); @@ -259,7 +259,7 @@ void GPU_pass_cache_free(void); typedef struct GPUMaterialAttribute { struct GPUMaterialAttribute *next, *prev; - int type; /* CustomDataType */ + int type; /* eCustomDataType */ char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ char input_name[12 + 1]; /* GPU_MAX_SAFE_ATTR_NAME + 1 */ eGPUType gputype; diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index b045d908438..5bd20b7be98 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -113,7 +113,7 @@ typedef enum eGPUTextureFormat { GPU_R16F, GPU_R16, /* Max texture buffer format. */ - /* Special formats texture & renderbuffer */ + /* Special formats texture & render-buffer. */ GPU_RGB10_A2, GPU_R11F_G11F_B10F, GPU_DEPTH32F_STENCIL8, diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 32b117dac12..1b34b6e6c69 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -14,7 +14,6 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" -#include "GPU_matrix.h" #include "GPU_platform.h" #include "GPU_shader.h" diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index ab5e23a846c..4dff35c3633 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -11,15 +11,8 @@ #include "BLI_utildefines.h" #include "MEM_guardedalloc.h" -#include "DNA_userdef_types.h" - -#include "UI_interface.h" -#include "UI_resources.h" - #include "GPU_batch.h" -#include "GPU_batch_presets.h" /* own include */ -#include "GPU_batch_utils.h" -#include "GPU_context.h" +#include "GPU_batch_presets.h" /* Own include. */ /* -------------------------------------------------------------------- */ /** \name Local Structures @@ -139,7 +132,7 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod) /** \name Create Sphere (3D) * \{ */ -GPUBatch *gpu_batch_sphere(int lat_res, int lon_res) +static GPUBatch *gpu_batch_sphere(int lat_res, int lon_res) { const float lon_inc = 2 * M_PI / lon_res; const float lat_inc = M_PI / lat_res; diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c index 43a47aab945..10a05fe90b9 100644 --- a/source/blender/gpu/intern/gpu_batch_utils.c +++ b/source/blender/gpu/intern/gpu_batch_utils.c @@ -8,7 +8,6 @@ #include "BLI_math.h" #include "BLI_polyfill_2d.h" -#include "BLI_rect.h" #include "BLI_sort_utils.h" #include "BLI_utildefines.h" diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index fed998bb33e..a1fe3d79223 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -9,20 +9,18 @@ #include <limits.h> #include <stddef.h> +#include <stdlib.h> #include <string.h> #include "MEM_guardedalloc.h" #include "BLI_bitmap.h" #include "BLI_ghash.h" -#include "BLI_hash.h" -#include "BLI_math.h" #include "BLI_math_color.h" -#include "BLI_math_color_blend.h" #include "BLI_utildefines.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_userdef_types.h" #include "BKE_DerivedMesh.h" #include "BKE_attribute.h" @@ -36,17 +34,12 @@ #include "GPU_batch.h" #include "GPU_buffers.h" +#include "DRW_engine.h" + #include "gpu_private.h" #include "bmesh.h" -/* XXX: the rest of the code in this file is used for optimized PBVH - * drawing and doesn't interact at all with the buffer code above */ - -/* -------------------------------------------------------------------- */ -/** \name Private Types - * \{ */ - struct GPU_PBVH_Buffers { GPUIndexBuf *index_buf, *index_buf_fast; GPUIndexBuf *index_lines_buf, *index_lines_buf_fast; @@ -88,10 +81,52 @@ struct GPU_PBVH_Buffers { bool show_overlay; }; -static struct { +typedef struct GPUAttrRef { + uchar domain, type; + ushort cd_offset; + int layer_idx; +} GPUAttrRef; + +#define MAX_GPU_ATTR 256 + +typedef struct PBVHGPUFormat { GPUVertFormat format; - uint pos, nor, msk, col, fset; -} g_vbo_id = {{0}}; + uint pos, nor, msk, fset; + uint col[MAX_GPU_ATTR]; + uint uv[MAX_GPU_ATTR]; + int totcol, totuv; + + /* Upload only the active color and UV attributes, + * used for workbench mode. */ + bool active_attrs_only; +} PBVHGPUFormat; + +PBVHGPUFormat *GPU_pbvh_make_format(void) +{ + PBVHGPUFormat *vbo_id = MEM_callocN(sizeof(PBVHGPUFormat), "PBVHGPUFormat"); + + GPU_pbvh_attribute_names_update(PBVH_FACES, vbo_id, NULL, NULL, false); + + return vbo_id; +} + +void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id) +{ + MEM_SAFE_FREE(vbo_id); +} + +static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask, + eCustomDataMask type_mask, + const CustomData *vdata, + const CustomData *edata, + const CustomData *ldata, + const CustomData *pdata, + GPUAttrRef r_cd_attrs[MAX_GPU_ATTR], + bool active_only, + int active_type, + int active_domain, + const CustomDataLayer *active_layer, + const CustomDataLayer *render_layer); /** \} */ @@ -101,20 +136,6 @@ static struct { void gpu_pbvh_init() { - /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - if (g_vbo_id.format.attr_len == 0) { - g_vbo_id.pos = GPU_vertformat_attr_add( - &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - g_vbo_id.nor = GPU_vertformat_attr_add( - &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */ - g_vbo_id.msk = GPU_vertformat_attr_add( - &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); - g_vbo_id.col = GPU_vertformat_attr_add( - &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - g_vbo_id.fset = GPU_vertformat_attr_add( - &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - } } void gpu_pbvh_exit() @@ -122,33 +143,37 @@ void gpu_pbvh_exit() /* Nothing to do. */ } +static CustomDataLayer *get_active_layer(const CustomData *cdata, int type) +{ + int idx = CustomData_get_active_layer_index(cdata, type); + return idx != -1 ? cdata->layers + idx : NULL; +} + +static CustomDataLayer *get_render_layer(const CustomData *cdata, int type) +{ + int idx = CustomData_get_render_layer_index(cdata, type); + return idx != -1 ? cdata->layers + idx : NULL; +} + /* Allocates a non-initialized buffer to be sent to GPU. * Return is false it indicates that the memory map failed. */ -static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) +static bool gpu_pbvh_vert_buf_data_set(PBVHGPUFormat *vbo_id, + GPU_PBVH_Buffers *buffers, + uint vert_len) { /* Keep so we can test #GPU_USAGE_DYNAMIC buffer use. * Not that format initialization match in both blocks. * Do this to keep braces balanced - otherwise indentation breaks. */ -#if 0 - if (buffers->vert_buf == NULL) { - /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC); - GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); - } - else if (vert_len != buffers->vert_buf->vertex_len) { - GPU_vertbuf_data_resize(buffers->vert_buf, vert_len); - } -#else + if (buffers->vert_buf == NULL) { /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC); + buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&vbo_id->format, GPU_USAGE_STATIC); } if (GPU_vertbuf_get_data(buffers->vert_buf) == NULL || GPU_vertbuf_get_vertex_len(buffers->vert_buf) != vert_len) { /* Allocate buffer if not allocated yet or size changed. */ GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); } -#endif return GPU_vertbuf_get_data(buffers->vert_buf) != NULL; } @@ -194,25 +219,62 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE); } -void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, +void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, + GPU_PBVH_Buffers *buffers, const MVert *mvert, - const float (*vert_normals)[3], + const CustomData *vdata, + const CustomData *ldata, const float *vmask, - const void *vcol_data, - int vcol_type, - AttributeDomain vcol_domain, const int *sculpt_face_sets, int face_sets_color_seed, int face_sets_color_default, - int update_flags) + int update_flags, + const float (*vert_normals)[3]) { - const MPropCol *vtcol = vcol_type == CD_PROP_COLOR ? vcol_data : NULL; - const MLoopCol *vcol = vcol_type == CD_PROP_BYTE_COLOR ? vcol_data : NULL; - const float(*f3col)[3] = vcol_type == CD_PROP_FLOAT3 ? vcol_data : NULL; + GPUAttrRef vcol_refs[MAX_GPU_ATTR]; + GPUAttrRef cd_uvs[MAX_GPU_ATTR]; + + Mesh me_query; + BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id); + + CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&me_query.id); + eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&me_query.id, actcol) : + ATTR_DOMAIN_AUTO; + + CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&me_query.id); + + int totcol; + + if (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) { + totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR, + CD_MASK_COLOR_ALL, + vdata, + NULL, + ldata, + NULL, + vcol_refs, + vbo_id->active_attrs_only, + actcol ? actcol->type : 0, + actcol_domain, + actcol, + rendercol); + } + else { + totcol = 0; + } - const bool color_loops = vcol_domain == ATTR_DOMAIN_CORNER; - const bool show_vcol = (vtcol || vcol || f3col) && - (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; + int totuv = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER, + CD_MASK_MLOOPUV, + NULL, + NULL, + ldata, + NULL, + cd_uvs, + vbo_id->active_attrs_only, + CD_MLOOPUV, + ATTR_DOMAIN_CORNER, + get_active_layer(ldata, CD_MLOOPUV), + get_render_layer(ldata, CD_MLOOPUV)); const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; const bool show_face_sets = sculpt_face_sets && @@ -224,25 +286,106 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const int totelem = buffers->tot_tri * 3; /* Build VBO */ - if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) { + if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totelem)) { GPUVertBufRaw pos_step = {0}; GPUVertBufRaw nor_step = {0}; GPUVertBufRaw msk_step = {0}; GPUVertBufRaw fset_step = {0}; GPUVertBufRaw col_step = {0}; + GPUVertBufRaw uv_step = {0}; - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step); - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step); - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step); - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.fset, &fset_step); - if (show_vcol) { - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step); - } + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->nor, &nor_step); + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->msk, &msk_step); + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->fset, &fset_step); /* calculate normal for each polygon only once */ uint mpoly_prev = UINT_MAX; short no[3] = {0, 0, 0}; + if (totuv > 0) { + for (int uv_i = 0; uv_i < totuv; uv_i++) { + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->uv[uv_i], &uv_step); + + GPUAttrRef *ref = cd_uvs + uv_i; + CustomDataLayer *layer = ldata->layers + ref->layer_idx; + MLoopUV *muv = layer->data; + + for (uint i = 0; i < buffers->face_indices_len; i++) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; + + if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) { + continue; + } + + for (uint j = 0; j < 3; j++) { + MLoopUV *muv2 = muv + lt->tri[j]; + + memcpy(GPU_vertbuf_raw_step(&uv_step), muv2->uv, sizeof(muv2->uv)); + } + } + } + } + + for (int col_i = 0; col_i < totcol; col_i++) { + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->col[col_i], &col_step); + + MPropCol *pcol = NULL; + MLoopCol *mcol = NULL; + + GPUAttrRef *ref = vcol_refs + col_i; + const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata; + CustomDataLayer *layer = cdata->layers + ref->layer_idx; + + bool color_loops = ref->domain == ATTR_DOMAIN_CORNER; + + if (layer->type == CD_PROP_COLOR) { + pcol = (MPropCol *)layer->data; + } + else { + mcol = (MLoopCol *)layer->data; + } + + for (uint i = 0; i < buffers->face_indices_len; i++) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; + const uint vtri[3] = { + buffers->mloop[lt->tri[0]].v, + buffers->mloop[lt->tri[1]].v, + buffers->mloop[lt->tri[2]].v, + }; + + if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) { + continue; + } + + for (uint j = 0; j < 3; j++) { + /* Vertex Colors. */ + const uint loop_index = lt->tri[j]; + + ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; + + if (pcol) { + MPropCol *pcol2 = pcol + (color_loops ? loop_index : vtri[j]); + + scol[0] = unit_float_to_ushort_clamp(pcol2->color[0]); + scol[1] = unit_float_to_ushort_clamp(pcol2->color[1]); + scol[2] = unit_float_to_ushort_clamp(pcol2->color[2]); + scol[3] = unit_float_to_ushort_clamp(pcol2->color[3]); + } + else { + const MLoopCol *mcol2 = mcol + (color_loops ? loop_index : vtri[j]); + + scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]); + scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]); + scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]); + scol[3] = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f)); + } + + memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); + } + } + } + for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; const uint vtri[3] = { @@ -296,50 +439,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, *(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask; empty_mask = empty_mask && (cmask == 0); - /* Vertex Colors. */ - if (show_vcol) { - ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - if (vtcol) { - if (color_loops) { - scol[0] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[0]); - scol[1] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[1]); - scol[2] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[2]); - scol[3] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[3]); - } - else { - scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]); - scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]); - scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]); - scol[3] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[3]); - } - memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); - } - else if (f3col) { - if (color_loops) { - scol[0] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][0]); - scol[1] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][1]); - scol[2] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][2]); - scol[3] = USHRT_MAX; - } - else { - scol[0] = unit_float_to_ushort_clamp(f3col[vtri[j]][0]); - scol[1] = unit_float_to_ushort_clamp(f3col[vtri[j]][1]); - scol[2] = unit_float_to_ushort_clamp(f3col[vtri[j]][2]); - scol[3] = USHRT_MAX; - } - memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); - } - else if (vcol) { - const uint loop_index = lt->tri[j]; - const MLoopCol *mcol = vcol + (color_loops ? loop_index : vtri[j]); - - scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); - scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); - scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); - scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); - memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); - } - } /* Face Sets. */ memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3])); } @@ -604,7 +703,8 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, } } -void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, +void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id, + GPU_PBVH_Buffers *buffers, SubdivCCG *subdiv_ccg, CCGElem **grids, const struct DMFlagMat *grid_flag_mats, @@ -628,8 +728,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, /* Build VBO */ const int has_mask = key->has_mask; - buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - uint vert_per_grid = (buffers->smooth) ? key->grid_area : (square_i(key->grid_size - 1) * 4); uint vert_count = totgrid * vert_per_grid; @@ -653,7 +751,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, uint vbo_index_offset = 0; /* Build VBO */ - if (gpu_pbvh_vert_buf_data_set(buffers, vert_count)) { + if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, vert_count)) { GPUIndexBufBuilder elb_lines; if (buffers->index_lines_buf == NULL) { @@ -683,25 +781,25 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, for (x = 0; x < key->grid_size; x++) { CCGElem *elem = CCG_grid_elem(key, grid, x, y); GPU_vertbuf_attr_set( - buffers->vert_buf, g_vbo_id.pos, vbo_index, CCG_elem_co(key, elem)); + buffers->vert_buf, vbo_id->pos, vbo_index, CCG_elem_co(key, elem)); short no_short[3]; normal_float_to_short_v3(no_short, CCG_elem_no(key, elem)); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index, no_short); if (has_mask && show_mask) { float fmask = *CCG_elem_mask(key, elem); uchar cmask = (uchar)(fmask * 255); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &cmask); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index, &cmask); empty_mask = empty_mask && (cmask == 0); } if (show_vcol) { const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index, &vcol); } - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index, &face_set_color); vbo_index += 1; } @@ -730,37 +828,37 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, normal_quad_v3(fno, co[3], co[2], co[1], co[0]); normal_float_to_short_v3(no_short, fno); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 0, co[0]); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 0, no_short); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 1, co[1]); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 1, no_short); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 2, co[2]); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 2, no_short); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 3, co[3]); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 3, no_short); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 0, co[0]); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 0, no_short); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 1, co[1]); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 1, no_short); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 2, co[2]); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 2, no_short); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 3, co[3]); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 3, no_short); if (has_mask && show_mask) { float fmask = (*CCG_elem_mask(key, elems[0]) + *CCG_elem_mask(key, elems[1]) + *CCG_elem_mask(key, elems[2]) + *CCG_elem_mask(key, elems[3])) * 0.25f; uchar cmask = (uchar)(fmask * 255); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 0, &cmask); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 1, &cmask); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 2, &cmask); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 3, &cmask); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 0, &cmask); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 1, &cmask); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 2, &cmask); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 3, &cmask); empty_mask = empty_mask && (cmask == 0); } const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 3, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 0, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 1, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 2, &vcol); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 3, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 0, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 1, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 2, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 3, &face_set_color); vbo_index += 4; } @@ -805,7 +903,8 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid * \{ */ /* Output a BMVert into a VertexBufferFormat array at v_index. */ -static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, +static void gpu_bmesh_vert_to_buffer_copy(PBVHGPUFormat *vbo_id, + BMVert *v, GPUVertBuf *vert_buf, int v_index, const float fno[3], @@ -819,27 +918,27 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN)); /* Set coord, normal, and mask */ - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co); + GPU_vertbuf_attr_set(vert_buf, vbo_id->pos, v_index, v->co); short no_short[3]; normal_float_to_short_v3(no_short, fno ? fno : v->no); - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short); + GPU_vertbuf_attr_set(vert_buf, vbo_id->nor, v_index, no_short); if (show_mask) { float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); uchar cmask = (uchar)(effective_mask * 255); - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &cmask); + GPU_vertbuf_attr_set(vert_buf, vbo_id->msk, v_index, &cmask); *empty_mask = *empty_mask && (cmask == 0); } if (show_vcol) { const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol); + GPU_vertbuf_attr_set(vert_buf, vbo_id->col[0], v_index, &vcol); } /* Add default face sets color to avoid artifacts. */ const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, &face_set); + GPU_vertbuf_attr_set(vert_buf, vbo_id->fset, v_index, &face_set); } /* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */ @@ -896,7 +995,8 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers) } } -void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, +void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id, + GPU_PBVH_Buffers *buffers, BMesh *bm, GSet *bm_faces, GSet *bm_unique_verts, @@ -935,7 +1035,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); /* Fill vertex buffer */ - if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) { + if (!gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totvert)) { /* Memory map failed */ return; } @@ -965,7 +1065,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, /* Add vertex to the vertex buffer each time a new one is encountered */ *idx_p = POINTER_FROM_UINT(v_index); - gpu_bmesh_vert_to_buffer_copy(v[i], + gpu_bmesh_vert_to_buffer_copy(vbo_id, + v[i], buffers->vert_buf, v_index, NULL, @@ -1032,7 +1133,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0); for (i = 0; i < 3; i++) { - gpu_bmesh_vert_to_buffer_copy(v[i], + gpu_bmesh_vert_to_buffer_copy(vbo_id, + v[i], buffers->vert_buf, v_index++, f->no, @@ -1075,6 +1177,250 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) return buffers; } +/** + * Builds a list of attributes from a set of domains and a set of + * customdata types. + * + * \param active_only Returns only one item, a GPUAttrRef to active_layer + * \param active_layer CustomDataLayer to use for the active layer + * \param active_layer CustomDataLayer to use for the render layer + */ +static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask, + eCustomDataMask type_mask, + const CustomData *vdata, + const CustomData *edata, + const CustomData *ldata, + const CustomData *pdata, + GPUAttrRef r_cd_attrs[MAX_GPU_ATTR], + bool active_only, + int active_type, + int active_domain, + const CustomDataLayer *active_layer, + const CustomDataLayer *render_layer) +{ + const CustomData *cdata_active = active_domain == ATTR_DOMAIN_POINT ? vdata : ldata; + + if (!cdata_active) { + return 0; + } + + if (active_only) { + int idx = active_layer ? active_layer - cdata_active->layers : -1; + + if (idx >= 0 && idx < cdata_active->totlayer) { + r_cd_attrs[0].cd_offset = cdata_active->layers[idx].offset; + r_cd_attrs[0].domain = active_domain; + r_cd_attrs[0].type = active_type; + r_cd_attrs[0].layer_idx = idx; + + return 1; + } + + return 0; + } + + const CustomData *datas[4] = {vdata, edata, pdata, ldata}; + + int count = 0; + for (eAttrDomain domain = 0; domain < 4; domain++) { + const CustomData *cdata = datas[domain]; + + if (!cdata || !((1 << domain) & domain_mask)) { + continue; + } + + CustomDataLayer *cl = cdata->layers; + + for (int i = 0; count < MAX_GPU_ATTR && i < cdata->totlayer; i++, cl++) { + if ((CD_TYPE_AS_MASK(cl->type) & type_mask) && !(cl->flag & CD_FLAG_TEMPORARY)) { + GPUAttrRef *ref = r_cd_attrs + count; + + ref->cd_offset = cl->offset; + ref->type = cl->type; + ref->layer_idx = i; + ref->domain = domain; + + count++; + } + } + } + + /* ensure render layer is last + draw cache code seems to need this + */ + + for (int i = 0; i < count; i++) { + GPUAttrRef *ref = r_cd_attrs + i; + const CustomData *cdata = datas[ref->domain]; + + if (cdata->layers + ref->layer_idx == render_layer) { + SWAP(GPUAttrRef, r_cd_attrs[i], r_cd_attrs[count - 1]); + break; + } + } + + return count; +} + +static bool gpu_pbvh_format_equals(PBVHGPUFormat *a, PBVHGPUFormat *b) +{ + bool bad = false; + + bad |= a->active_attrs_only != b->active_attrs_only; + + bad |= a->pos != b->pos; + bad |= a->fset != b->fset; + bad |= a->msk != b->msk; + bad |= a->nor != b->nor; + + for (int i = 0; i < MIN2(a->totuv, b->totuv); i++) { + bad |= a->uv[i] != b->uv[i]; + } + + for (int i = 0; i < MIN2(a->totcol, b->totcol); i++) { + bad |= a->col[i] != b->col[i]; + } + + bad |= a->totuv != b->totuv; + bad |= a->totcol != b->totcol; + + return !bad; +} + +bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type, + PBVHGPUFormat *vbo_id, + const CustomData *vdata, + const CustomData *ldata, + bool active_attrs_only) +{ + const bool active_only = active_attrs_only; + PBVHGPUFormat old_format = *vbo_id; + + GPU_vertformat_clear(&vbo_id->format); + + vbo_id->active_attrs_only = active_attrs_only; + + if (vbo_id->format.attr_len == 0) { + vbo_id->pos = GPU_vertformat_attr_add( + &vbo_id->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + vbo_id->nor = GPU_vertformat_attr_add( + &vbo_id->format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + + /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */ + vbo_id->msk = GPU_vertformat_attr_add( + &vbo_id->format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + + vbo_id->totcol = 0; + if (pbvh_type == PBVH_FACES) { + int ci = 0; + + Mesh me_query; + + BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id); + + CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me_query.id); + CustomDataLayer *render_color_layer = BKE_id_attributes_render_color_get(&me_query.id); + eAttrDomain active_color_domain = active_color_layer ? + BKE_id_attribute_domain(&me_query.id, + active_color_layer) : + ATTR_DOMAIN_NUM; + + GPUAttrRef vcol_layers[MAX_GPU_ATTR]; + int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR, + CD_MASK_COLOR_ALL, + vdata, + NULL, + ldata, + NULL, + vcol_layers, + active_only, + active_color_layer ? active_color_layer->type : -1, + active_color_domain, + active_color_layer, + render_color_layer); + + for (int i = 0; i < totlayer; i++) { + GPUAttrRef *ref = vcol_layers + i; + const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata; + + const CustomDataLayer *layer = cdata->layers + ref->layer_idx; + + if (vbo_id->totcol < MAX_GPU_ATTR) { + vbo_id->col[ci++] = GPU_vertformat_attr_add( + &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + vbo_id->totcol++; + + bool is_render = render_color_layer == layer; + bool is_active = active_color_layer == layer; + + DRW_cdlayer_attr_aliases_add(&vbo_id->format, "c", cdata, layer, is_render, is_active); + } + } + } + + /* ensure at least one vertex color layer */ + if (vbo_id->totcol == 0) { + vbo_id->col[0] = GPU_vertformat_attr_add( + &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + vbo_id->totcol = 1; + + GPU_vertformat_alias_add(&vbo_id->format, "ac"); + } + + vbo_id->fset = GPU_vertformat_attr_add( + &vbo_id->format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + + vbo_id->totuv = 0; + if (pbvh_type == PBVH_FACES && ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) { + GPUAttrRef uv_layers[MAX_GPU_ATTR]; + CustomDataLayer *active = NULL, *render = NULL; + + active = get_active_layer(ldata, CD_MLOOPUV); + render = get_render_layer(ldata, CD_MLOOPUV); + + int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER, + CD_MASK_MLOOPUV, + NULL, + NULL, + ldata, + NULL, + uv_layers, + active_only, + CD_MLOOPUV, + ATTR_DOMAIN_CORNER, + active, + render); + + vbo_id->totuv = totlayer; + + for (int i = 0; i < totlayer; i++) { + GPUAttrRef *ref = uv_layers + i; + + vbo_id->uv[i] = GPU_vertformat_attr_add( + &vbo_id->format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + CustomDataLayer *cl = ldata->layers + ref->layer_idx; + bool is_active = ref->layer_idx == CustomData_get_active_layer_index(ldata, CD_MLOOPUV); + + DRW_cdlayer_attr_aliases_add(&vbo_id->format, "u", ldata, cl, cl == render, is_active); + + /* Apparently the render attribute is 'a' while active is 'au', + * at least going by the draw cache extractor code. + */ + if (cl == render) { + GPU_vertformat_alias_add(&vbo_id->format, "a"); + } + } + } + } + + if (!gpu_pbvh_format_equals(&old_format, vbo_id)) { + return true; + } + + return false; +} + GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires) { if (wires) { diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc index eb69a1d2635..18748627b83 100644 --- a/source/blender/gpu/intern/gpu_capabilities.cc +++ b/source/blender/gpu/intern/gpu_capabilities.cc @@ -8,7 +8,7 @@ * with checks for drivers and GPU support. */ -#include "DNA_userdef_types.h" +#include "DNA_userdef_types.h" /* For `U.glreslimit`. */ #include "GPU_capabilities.h" diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index f1b46f8bf86..fa7ce3a364b 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -12,8 +12,6 @@ #include "DNA_customdata_types.h" #include "DNA_image_types.h" -#include "BLI_blenlib.h" -#include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_hash_mm2a.h" #include "BLI_link_utils.h" @@ -23,7 +21,6 @@ #include "PIL_time.h" #include "BKE_material.h" -#include "BKE_world.h" #include "GPU_capabilities.h" #include "GPU_material.h" @@ -35,13 +32,12 @@ #include "BLI_vector.hh" #include "gpu_codegen.h" -#include "gpu_material_library.h" #include "gpu_node_graph.h" #include "gpu_shader_create_info.hh" #include "gpu_shader_dependency_private.h" -#include <stdarg.h> -#include <string.h> +#include <cstdarg> +#include <cstring> #include <sstream> #include <string> diff --git a/source/blender/gpu/intern/gpu_compute.cc b/source/blender/gpu/intern/gpu_compute.cc index b45cf8211cb..277f6d22280 100644 --- a/source/blender/gpu/intern/gpu_compute.cc +++ b/source/blender/gpu/intern/gpu_compute.cc @@ -7,7 +7,6 @@ #include "GPU_compute.h" #include "gpu_backend.hh" -#include "gpu_storage_buffer_private.hh" void GPU_compute_dispatch(GPUShader *shader, uint groups_x_len, diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index c6eaf7defdc..9fb5826506a 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -23,8 +23,6 @@ #include "GPU_context.h" #include "GPU_framebuffer.h" -#include "GHOST_C-api.h" - #include "gpu_backend.hh" #include "gpu_batch_private.hh" #include "gpu_context_private.hh" @@ -177,7 +175,7 @@ void GPU_render_step() /** \name Backend selection * \{ */ -static GPUBackend *g_backend; +static GPUBackend *g_backend = nullptr; bool GPU_backend_supported(eGPUBackendType type) { diff --git a/source/blender/gpu/intern/gpu_drawlist.cc b/source/blender/gpu/intern/gpu_drawlist.cc index b5b8d2f90bc..e1699bd0036 100644 --- a/source/blender/gpu/intern/gpu_drawlist.cc +++ b/source/blender/gpu/intern/gpu_drawlist.cc @@ -7,9 +7,6 @@ * Implementation of Multi Draw Indirect. */ -#include "MEM_guardedalloc.h" - -#include "GPU_batch.h" #include "GPU_drawlist.h" #include "gpu_backend.hh" diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index fb3c9549f18..08d761106e5 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -7,7 +7,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" #include "BLI_math_base.h" #include "BLI_utildefines.h" @@ -18,7 +17,6 @@ #include "gpu_backend.hh" #include "gpu_context_private.hh" -#include "gpu_private.h" #include "gpu_texture_private.hh" #include "gpu_framebuffer_private.hh" diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 69467e5b28a..8f04b1c2dfe 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -18,7 +18,6 @@ #include "gpu_context_private.hh" #include "gpu_immediate_private.hh" #include "gpu_shader_private.hh" -#include "gpu_vertex_buffer_private.hh" #include "gpu_vertex_format_private.h" using namespace blender::gpu; diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 67035853594..a275fd8fc6c 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -13,7 +13,6 @@ #include "BLI_utildefines.h" #include "GPU_immediate.h" -#include "GPU_immediate_util.h" #include "UI_resources.h" @@ -337,13 +336,27 @@ static void imm_draw_circle_3D( /* Note(Metal/AMD): For small primitives, line list more efficient than line strip. */ immBegin(GPU_PRIM_LINES, nsegments * 2); - immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f); - for (int i = 1; i < nsegments; i++) { - float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments); - immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f); - immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f); + const float angle = (float)(2 * M_PI) / (float)nsegments; + float xprev = cosf(-angle) * radius; + float yprev = sinf(-angle) * radius; + const float alpha = 2.0f * cosf(angle); + + float xr = radius; + float yr = 0; + + for (int i = 0; i < nsegments; i++) { + immVertex3f(pos, x + xr, y + yr, 0.0f); + if (i) { + immVertex3f(pos, x + xr, y + yr, 0.0f); + } + const float xnext = alpha * xr - xprev; + const float ynext = alpha * yr - yprev; + xprev = xr; + yprev = yr; + xr = xnext; + yr = ynext; } - immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f); + immVertex3f(pos, x + radius, y, 0.0f); immEnd(); } else { diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index e97c9e9c829..062614fb5cb 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -6,15 +6,10 @@ */ #include "GPU_init_exit.h" /* interface */ -#include "BKE_global.h" #include "BLI_sys_types.h" #include "GPU_batch.h" -#include "GPU_buffers.h" -#include "GPU_context.h" -#include "GPU_immediate.h" #include "intern/gpu_codegen.h" -#include "intern/gpu_material_library.h" #include "intern/gpu_private.h" #include "intern/gpu_shader_create_info_private.hh" #include "intern/gpu_shader_dependency_private.h" diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 23028f58059..4d3ea3e0c99 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -19,14 +19,11 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" -#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" -#include "BKE_scene.h" -#include "BKE_world.h" #include "NOD_shader.h" @@ -669,7 +666,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); mat->refcount = 1; #ifndef NDEBUG - BLI_snprintf(mat->name, sizeof(mat->name), "%s", name); + STRNCPY(mat->name, name); #else UNUSED_VARS(name); #endif @@ -750,6 +747,9 @@ void GPU_material_compile(GPUMaterial *mat) mat->status = GPU_MAT_SUCCESS; gpu_node_graph_free_nodes(&mat->graph); } + else { + mat->status = GPU_MAT_FAILED; + } } else { mat->status = GPU_MAT_FAILED; diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 91fb0544cf6..3c6a03c56d3 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -328,7 +328,7 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph) /* Attributes and Textures */ -static char attr_prefix_get(CustomDataType type) +static char attr_prefix_get(eCustomDataType type) { switch (type) { case CD_TANGENT: @@ -347,7 +347,7 @@ static char attr_prefix_get(CustomDataType type) static void attr_input_name(GPUMaterialAttribute *attr) { - /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ + /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.cc */ if (attr->type == CD_ORCO) { /* OPTI: orco is computed from local positions, but only if no modifier is present. */ STRNCPY(attr->input_name, "orco"); @@ -364,7 +364,7 @@ static void attr_input_name(GPUMaterialAttribute *attr) /** Add a new varying attribute of given type and name. Returns NULL if out of slots. */ static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph, - CustomDataType type, + eCustomDataType type, const char *name) { /* Find existing attribute. */ @@ -468,7 +468,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, /* Creating Inputs */ -GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const char *name) +GPUNodeLink *GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const char *name) { GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name); @@ -491,7 +491,7 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const ch } GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat, - const CustomDataType type, + const eCustomDataType type, const char *name, eGPUDefaultValue default_value) { diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index ac33c5d5ca8..7afba20c2d9 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -12,12 +12,8 @@ #include "GPU_select.h" -#include "MEM_guardedalloc.h" - #include "BLI_rect.h" -#include "DNA_userdef_types.h" - #include "BLI_utildefines.h" #include "gpu_select_private.h" diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 840201c8c97..b5b2d7fa1a5 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -13,7 +13,6 @@ #include "GPU_debug.h" #include "GPU_framebuffer.h" -#include "GPU_immediate.h" #include "GPU_select.h" #include "GPU_state.h" diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc index 26c9ed79d6c..7393dfd0d81 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.cc +++ b/source/blender/gpu/intern/gpu_select_sample_query.cc @@ -19,7 +19,6 @@ #include "BLI_rect.h" -#include "BLI_bitmap.h" #include "BLI_utildefines.h" #include "BLI_vector.hh" diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index b92fae4a89b..c3a1236e814 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -5,25 +5,9 @@ * \ingroup gpu */ -#include "MEM_guardedalloc.h" - -#include "BLI_math_base.h" -#include "BLI_math_vector.h" -#include "BLI_path_util.h" -#include "BLI_string.h" -#include "BLI_string_utils.h" #include "BLI_utildefines.h" -#include "BKE_appdir.h" -#include "BKE_global.h" - -#include "DNA_space_types.h" - -#include "GPU_matrix.h" -#include "GPU_platform.h" #include "GPU_shader.h" -#include "GPU_texture.h" -#include "GPU_uniform_buffer.h" /* Adjust these constants as needed. */ #define MAX_DEFINE_LENGTH 256 diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc index f5b90989481..81c21e4e7e2 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.cc +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -19,7 +19,6 @@ #include "gpu_shader_create_info.hh" #include "gpu_shader_create_info_private.hh" #include "gpu_shader_dependency_private.h" -#include "gpu_shader_private.hh" #undef GPU_SHADER_INTERFACE_INFO #undef GPU_SHADER_CREATE_INFO diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc index 842914f5bed..d91e15243f3 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency.cc +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -15,7 +15,6 @@ #include "BLI_ghash.h" #include "BLI_map.hh" -#include "BLI_set.hh" #include "BLI_string_ref.hh" #include "gpu_material_library.h" diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc index ea138973c74..6f43b379d31 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.cc +++ b/source/blender/gpu/intern/gpu_shader_interface.cc @@ -38,7 +38,7 @@ static void sort_input_list(MutableSpan<ShaderInput> dst) /* Simple sorting by going through the array and selecting the biggest element each time. */ for (uint i = 0; i < dst.size(); i++) { - ShaderInput *input_src = &src[0]; + ShaderInput *input_src = src.data(); for (uint j = 1; j < src.size(); j++) { if (src[j].name_hash > input_src->name_hash) { input_src = &src[j]; diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc index 83fc34a3278..572727fa515 100644 --- a/source/blender/gpu/intern/gpu_shader_log.cc +++ b/source/blender/gpu/intern/gpu_shader_log.cc @@ -15,8 +15,6 @@ #include "gpu_shader_dependency_private.h" #include "gpu_shader_private.hh" -#include "GPU_platform.h" - #include "CLG_log.h" static CLG_LogRef LOG = {"gpu.shader"}; diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc index f74d500340d..a1e0b8867a0 100644 --- a/source/blender/gpu/intern/gpu_state.cc +++ b/source/blender/gpu/intern/gpu_state.cc @@ -14,8 +14,6 @@ #include "BLI_math_vector.h" #include "BLI_utildefines.h" -#include "BKE_global.h" - #include "GPU_state.h" #include "gpu_context_private.hh" diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc index 68020ec66f4..afa27da9c85 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer.cc +++ b/source/blender/gpu/intern/gpu_storage_buffer.cc @@ -12,7 +12,6 @@ #include "BLI_math_base.h" #include "gpu_backend.hh" -#include "gpu_node_graph.h" #include "GPU_material.h" #include "GPU_vertex_buffer.h" /* For GPUUsageType. */ diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index d78dc845074..218d22ddf53 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -13,7 +13,6 @@ #include "gpu_backend.hh" #include "gpu_context_private.hh" #include "gpu_framebuffer_private.hh" -#include "gpu_vertex_buffer_private.hh" #include "gpu_texture_private.hh" @@ -702,7 +701,11 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size) void GPU_samplers_update() { - GPUBackend::get()->samplers_update(); + /* Backend may not exist when we are updating preferences from background mode. */ + GPUBackend *backend = GPUBackend::get(); + if (backend) { + backend->samplers_update(); + } } /** \} */ diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc index f47970d48d1..0dbd565291b 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.cc +++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc @@ -12,7 +12,6 @@ #include "gpu_backend.hh" #include "gpu_vertex_format_private.h" -#include "gl_vertex_buffer.hh" /* TODO: remove. */ #include "gpu_context_private.hh" /* TODO: remove. */ #include "gpu_vertex_buffer_private.hh" diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index c3118ca320c..71bdf9e336b 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -9,16 +9,13 @@ #include <string.h> -#include "BLI_listbase.h" #include "BLI_math_vector.h" -#include "BLI_memblock.h" #include "BLI_rect.h" #include "BKE_colortools.h" #include "IMB_colormanagement.h" -#include "DNA_userdef_types.h" #include "DNA_vec_types.h" #include "GPU_capabilities.h" diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm index 8bdec962af0..1064091a036 100644 --- a/source/blender/gpu/metal/mtl_backend.mm +++ b/source/blender/gpu/metal/mtl_backend.mm @@ -256,7 +256,7 @@ bool MTLBackend::metal_is_supported() NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; - /* Metal Viewport requires macOS Version 10.15 onwards. */ + /* Metal Viewport requires macOS Version 10.15 onward. */ bool supported_os_version = version.majorVersion >= 11 || (version.majorVersion == 10 ? version.minorVersion >= 15 : false); if (!supported_os_version) { diff --git a/source/blender/gpu/metal/mtl_state.mm b/source/blender/gpu/metal/mtl_state.mm index 5f52bc55f72..fa2f5c54391 100644 --- a/source/blender/gpu/metal/mtl_state.mm +++ b/source/blender/gpu/metal/mtl_state.mm @@ -532,9 +532,11 @@ void MTLStateManager::set_blend(const eGPUBlend value) /* NOTE(Metal): Granular option for specifying before/after stages for a barrier * Would be a useful feature. */ -/*void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits, +#if 0 +void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits, eGPUStageBarrierBits before_stages, - eGPUStageBarrierBits after_stages) */ + eGPUStageBarrierBits after_stages) +#endif void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits) { /* NOTE(Metal): The Metal API implicitly tracks dependencies between resources. diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh index b820256ec36..b4b1e91c496 100644 --- a/source/blender/gpu/metal/mtl_texture.hh +++ b/source/blender/gpu/metal/mtl_texture.hh @@ -349,7 +349,7 @@ class MTLTexture : public Texture { * - Per-component size matches (e.g. GPU_DATA_UBYTE) * OR GPU_DATA_10_11_11_REV && GPU_R11G11B10 (equiv) * OR D24S8 and GPU_DATA_UINT_24_8 - * We can Use BLIT ENCODER. + * We can use BLIT ENCODER. * * OTHERWISE TRIGGER COMPUTE: * - Compute sizes will vary. Threads per grid WILL match 'extent'. diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 0c796ddc765..4869bff2737 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -10,8 +10,6 @@ #include "gpu_capabilities_private.hh" #include "gpu_platform_private.hh" -#include "glew-mx.h" - #include "gl_debug.hh" #include "gl_backend.hh" @@ -408,7 +406,7 @@ static void detect_workarounds() /* Certain Intel/AMD based platforms don't clear the viewport textures. Always clearing leads to * noticeable performance regressions on other platforms as well. */ if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) || - GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY)) { + GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { GCaps.clear_viewport_workaround = true; } diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index e738413879e..fde2a53bb0f 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -11,12 +11,9 @@ #include "BLI_assert.h" -#include "glew-mx.h" - #include "gpu_batch_private.hh" #include "gpu_shader_private.hh" -#include "gl_backend.hh" #include "gl_context.hh" #include "gl_debug.hh" #include "gl_index_buffer.hh" diff --git a/source/blender/gpu/opengl/gl_compute.cc b/source/blender/gpu/opengl/gl_compute.cc index 2fbf23c227d..1f8bb69dc3a 100644 --- a/source/blender/gpu/opengl/gl_compute.cc +++ b/source/blender/gpu/opengl/gl_compute.cc @@ -8,8 +8,6 @@ #include "gl_debug.hh" -#include "glew-mx.h" - namespace blender::gpu { void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len) diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc index 72892ffcd34..f4f060821b0 100644 --- a/source/blender/gpu/opengl/gl_context.cc +++ b/source/blender/gpu/opengl/gl_context.cc @@ -6,7 +6,6 @@ */ #include "BLI_assert.h" -#include "BLI_system.h" #include "BLI_utildefines.h" #include "BKE_global.h" diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc index c02b6b26068..79d1b54828d 100644 --- a/source/blender/gpu/opengl/gl_debug_layer.cc +++ b/source/blender/gpu/opengl/gl_debug_layer.cc @@ -10,8 +10,6 @@ #include "BLI_utildefines.h" -#include "glew-mx.h" - #include "gl_debug.hh" using GPUvoidptr = void *; diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc index 2f87c859273..fd76d8c58f8 100644 --- a/source/blender/gpu/opengl/gl_drawlist.cc +++ b/source/blender/gpu/opengl/gl_drawlist.cc @@ -11,9 +11,6 @@ #include "BLI_assert.h" #include "GPU_batch.h" -#include "GPU_capabilities.h" - -#include "glew-mx.h" #include "gpu_context_private.hh" #include "gpu_drawlist_private.hh" diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc index 57eeabba0a0..bd9fba4250d 100644 --- a/source/blender/gpu/opengl/gl_framebuffer.cc +++ b/source/blender/gpu/opengl/gl_framebuffer.cc @@ -7,8 +7,6 @@ #include "BKE_global.h" -#include "GPU_capabilities.h" - #include "gl_backend.hh" #include "gl_debug.hh" #include "gl_state.hh" diff --git a/source/blender/gpu/opengl/gl_immediate.cc b/source/blender/gpu/opengl/gl_immediate.cc index c32a6afd8cf..a332a2fbc7c 100644 --- a/source/blender/gpu/opengl/gl_immediate.cc +++ b/source/blender/gpu/opengl/gl_immediate.cc @@ -7,8 +7,6 @@ * Mimics old style opengl immediate mode drawing. */ -#include "BKE_global.h" - #include "gpu_context_private.hh" #include "gpu_shader_private.hh" #include "gpu_vertex_format_private.h" diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc index 8cedb831272..566169182e3 100644 --- a/source/blender/gpu/opengl/gl_index_buffer.cc +++ b/source/blender/gpu/opengl/gl_index_buffer.cc @@ -6,7 +6,6 @@ */ #include "gl_context.hh" -#include "gl_debug.hh" #include "gl_index_buffer.hh" diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 5a28b8b7318..ccdf10c1ed2 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -13,7 +13,6 @@ #include "GPU_capabilities.h" #include "GPU_platform.h" -#include "gl_backend.hh" #include "gl_debug.hh" #include "gl_vertex_buffer.hh" @@ -613,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_VERSION_4_2 || GLEW_ARB_conservative_depth) { + if (GLEW_ARB_conservative_depth) { ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n"; } ss << "\n/* Outputs. */\n"; @@ -836,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_VERSION_4_2 && GLEW_ARB_conservative_depth) { + if (GLEW_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_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index f6a7eee80c3..1b3ab2941a8 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -9,7 +9,6 @@ #include "BLI_bitmap.h" -#include "gl_backend.hh" #include "gl_batch.hh" #include "gl_context.hh" diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc index 68a88938f69..8be4ac29af6 100644 --- a/source/blender/gpu/opengl/gl_state.cc +++ b/source/blender/gpu/opengl/gl_state.cc @@ -12,10 +12,7 @@ #include "GPU_capabilities.h" -#include "glew-mx.h" - #include "gl_context.hh" -#include "gl_debug.hh" #include "gl_framebuffer.hh" #include "gl_texture.hh" diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index b30674fe5fa..4592adc3a61 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -5,8 +5,6 @@ * \ingroup gpu */ -#include "BKE_global.h" - #include "BLI_string.h" #include "gpu_backend.hh" diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index 14f84273925..055c8d104e2 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -5,8 +5,6 @@ * \ingroup gpu */ -#include "BKE_global.h" - #include "DNA_userdef_types.h" #include "GPU_capabilities.h" diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.cc b/source/blender/gpu/opengl/gl_uniform_buffer.cc index b8bcaf0047e..e58cea9de43 100644 --- a/source/blender/gpu/opengl/gl_uniform_buffer.cc +++ b/source/blender/gpu/opengl/gl_uniform_buffer.cc @@ -5,14 +5,10 @@ * \ingroup gpu */ -#include "BKE_global.h" - #include "BLI_string.h" -#include "gpu_backend.hh" #include "gpu_context_private.hh" -#include "gl_backend.hh" #include "gl_debug.hh" #include "gl_uniform_buffer.hh" diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index cfcf77fe705..a3299fc3325 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -7,7 +7,6 @@ #include "gpu_shader_interface.hh" #include "gpu_vertex_buffer_private.hh" -#include "gpu_vertex_format_private.h" #include "gl_batch.hh" #include "gl_context.hh" diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl index 4962fb01c88..b0da035ef09 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl @@ -5,7 +5,7 @@ void main() float dist_squared = dot(centered, centered); const float rad_squared = 0.25; - // round point with jaggy edges + /* Round point with jaggy edges. */ if (dist_squared > rad_squared) { discard; } diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh index 6840dfe25de..396ee64454c 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh @@ -37,7 +37,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color) GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color_clipped) .do_static_compilation(true) - /* TODO(fclem): Put in an UBO to fit the 128byte requirement. */ + /* TODO(fclem): Put in a UBO to fit the 128byte requirement. */ .push_constant(Type::MAT4, "ModelMatrix") .push_constant(Type::VEC4, "ClipPlane") .define("CLIP") diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl index ff84a0a334c..b1a29833d77 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl @@ -1,6 +1,8 @@ void camera(out vec3 outview, out float outdepth, out float outdist) { - outdepth = abs(transform_point(ViewMatrix, g_data.P).z); - outdist = distance(g_data.P, cameraPos); - outview = normalize(g_data.P - cameraPos); + vec3 vP = transform_point(ViewMatrix, g_data.P); + vP.z = -vP.z; + outdepth = abs(vP.z); + outdist = length(vP); + outview = normalize(vP); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl index 530907859e9..c95a41c58fc 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl @@ -34,6 +34,13 @@ void node_eevee_specular(vec4 diffuse, diffuse_data.N = N; diffuse_data.sss_id = 0u; + /* WORKAROUND: Nasty workaround to the current interface with the closure evaluation. + * Ideally the occlusion input should be move to the output node or removed all-together. + * This is temporary to avoid a regression in 3.2 and should be removed after EEVEE-Next rewrite. + */ + diffuse_data.sss_radius.r = occlusion; + diffuse_data.sss_radius.g = -1.0; /* Flag */ + ClosureReflection reflection_data; reflection_data.weight = alpha; if (true) { @@ -41,7 +48,7 @@ void node_eevee_specular(vec4 diffuse, vec2 split_sum = brdf_lut(NV, roughness); vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum); - reflection_data.color = specular.rgb * brdf; + reflection_data.color = brdf; reflection_data.N = N; reflection_data.roughness = roughness; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl index 4c9ff31622f..fed7ac7df66 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl @@ -1,6 +1,6 @@ #pragma BLENDER_REQUIRE(gpu_shader_material_tangent.glsl) -void node_geometry(vec3 orco, +void node_geometry(vec3 orco_attr, out vec3 position, out vec3 normal, out vec3 tangent, @@ -21,8 +21,8 @@ void node_geometry(vec3 orco, tangent = g_data.curve_T; } else { - tangent_orco_z(orco, orco); - node_tangent(orco, tangent); + tangent_orco_z(orco_attr, orco_attr); + node_tangent(orco_attr, tangent); } parametric = vec3(g_data.barycentric_coords, 0.0); diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index e46326467cc..1309e3810be 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -178,13 +178,13 @@ if(WITH_IMAGE_WEBP) list(APPEND SRC intern/webp.c ) - list(APPEND INC_SYS - ${WEBP_INCLUDE_DIRS} - ) + list(APPEND INC_SYS + ${WEBP_INCLUDE_DIRS} + ) list(APPEND LIB ${WEBP_LIBRARIES} ) - add_definitions(-DWITH_WEBP) + add_definitions(-DWITH_WEBP) endif() list(APPEND INC diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 512dc674fc7..2f0d2f9b449 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -181,7 +181,6 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, int width, int height, const struct ImBuf *ibuf, - bool compress_as_srgb, bool store_premultiplied); void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer, int offset_x, @@ -519,10 +518,10 @@ enum { * \{ */ void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table, - const int width, - const float min, - const float max); -void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width); + int width, + float min, + float max); +void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, int width); /** \} */ diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 16cf0e2125e..1b32bef0a98 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -41,8 +41,7 @@ typedef struct DDSData { /** * \ingroup imbuf - * This is the abstraction of an image. ImBuf is the basic type used for all - * imbuf operations. + * This is the abstraction of an image. ImBuf is the basic type used for all imbuf operations. * * Also; add new variables to the end to save pain! */ @@ -176,7 +175,7 @@ typedef struct ImBuf { * avoid problems and use int. - campbell */ int x, y; - /** Active amount of bits/bitplanes */ + /** Active amount of bits/bit-planes. */ unsigned char planes; /** Number of channels in `rect_float` (0 = 4 channel default) */ int channels; @@ -276,7 +275,7 @@ typedef struct ImBuf { } ImBuf; /** - * \brief userflags: Flags used internally by blender for imagebuffers + * \brief userflags: Flags used internally by blender for image-buffers. */ enum { diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 67d1aefeacb..9a0a6998fab 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -42,8 +42,8 @@ typedef struct ImFileType { * dimensions of the full-size image in r_width & r_height. */ struct ImBuf *(*load_filepath_thumbnail)(const char *filepath, - const int flags, - const size_t max_thumb_size, + int flags, + size_t max_thumb_size, char colorspace[IM_MAX_SPACE], size_t *r_width, size_t *r_height); @@ -155,8 +155,8 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer, int flags, char colorspace[IM_MAX_SPACE]); struct ImBuf *imb_thumbnail_jpeg(const char *filepath, - const int flags, - const size_t max_thumb_size, + int flags, + size_t max_thumb_size, char colorspace[IM_MAX_SPACE], size_t *r_width, size_t *r_height); @@ -240,11 +240,10 @@ void imb_loadtiletiff( /** * Saves a TIFF file. * - * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA - * respectively) are accepted, and interpreted correctly. Note that the TIFF - * convention is to use pre-multiplied alpha, which can be achieved within - * Blender by setting "Premul" alpha handling. Other alpha conventions are - * not strictly correct, but are permitted anyhow. + * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA respectively) + * are accepted, and interpreted correctly. Note that the TIFF convention is to use + * pre-multiplied alpha, which can be achieved within Blender by setting `premul` alpha handling. + * Other alpha conventions are not strictly correct, but are permitted anyhow. * * \param ibuf: Image buffer. * \param filepath: Name of the TIFF file to create. diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index 6448d6cd76a..1a99d2a34d9 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -121,8 +121,8 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filepath, int use_cineon } if (ibuf->rect_float != NULL && bitspersample != 8) { - /* don't use the float buffer to save 8 bpp picture to prevent color banding - * (there's no dithering algorithm behind the logImageSetDataRGBA function) */ + /* Don't use the float buffer to save 8 BPP picture to prevent color banding + * (there's no dithering algorithm behind the #logImageSetDataRGBA function). */ fbuf = (float *)MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, "fbuf in imb_save_dpx_cineon"); diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index d4c9e78a299..a58c2ba4c44 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -597,7 +597,7 @@ static void colormanage_free_config(void) while (colorspace) { ColorSpace *colorspace_next = colorspace->next; - /* free precomputer processors */ + /* Free precomputed processors. */ if (colorspace->to_scene_linear) { OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear); } @@ -673,7 +673,7 @@ void colormanagement_init(void) #ifdef WIN32 { - /* quite a hack to support loading configuration from path with non-acii symbols */ + /* Quite a hack to support loading configuration from path with non-ACII symbols. */ char short_name[256]; BLI_get_short_name(short_name, configfile); @@ -2211,21 +2211,14 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, const int width, const int height, const struct ImBuf *ibuf, - const bool compress_as_srgb, const bool store_premultiplied) { - /* Convert byte buffer for texture storage on the GPU. These have builtin - * support for converting sRGB to linear, which allows us to store textures - * without precision or performance loss at minimal memory usage. */ + /* Byte buffer storage, only for sRGB and data texture since other + * color space conversions can't be done on the GPU. */ BLI_assert(ibuf->rect && ibuf->rect_float == NULL); + BLI_assert(IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) || + IMB_colormanagement_space_is_data(ibuf->rect_colorspace)); - OCIO_ConstCPUProcessorRcPtr *processor = NULL; - if (compress_as_srgb && ibuf->rect_colorspace && - !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) { - processor = colorspace_to_scene_linear_cpu_processor(ibuf->rect_colorspace); - } - - /* TODO(brecht): make this multi-threaded, or at least process in batches. */ const unsigned char *in_buffer = (unsigned char *)ibuf->rect; const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied; @@ -2235,20 +2228,7 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, const unsigned char *in = in_buffer + in_offset * 4; unsigned char *out = out_buffer + out_offset * 4; - if (processor != NULL) { - /* Convert to scene linear, to sRGB and premultiply. */ - for (int x = 0; x < width; x++, in += 4, out += 4) { - float pixel[4]; - rgba_uchar_to_float(pixel, in); - OCIO_cpuProcessorApplyRGB(processor, pixel); - linearrgb_to_srgb_v3_v3(pixel, pixel); - if (use_premultiply) { - mul_v3_fl(pixel, pixel[3]); - } - rgba_float_to_uchar(out, pixel); - } - } - else if (use_premultiply) { + if (use_premultiply) { /* Premultiply only. */ for (int x = 0; x < width; x++, in += 4, out += 4) { out[0] = (in[0] * in[3]) >> 8; @@ -2279,43 +2259,80 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer, { /* Float texture are stored in scene linear color space, with premultiplied * alpha depending on the image alpha mode. */ - const float *in_buffer = ibuf->rect_float; - const int in_channels = ibuf->channels; - const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied; - - for (int y = 0; y < height; y++) { - const size_t in_offset = (offset_y + y) * ibuf->x + offset_x; - const size_t out_offset = y * width; - const float *in = in_buffer + in_offset * in_channels; - float *out = out_buffer + out_offset * 4; - - if (in_channels == 1) { - /* Copy single channel. */ - for (int x = 0; x < width; x++, in += 1, out += 4) { - out[0] = in[0]; - out[1] = in[0]; - out[2] = in[0]; - out[3] = in[0]; + if (ibuf->rect_float) { + /* Float source buffer. */ + const float *in_buffer = ibuf->rect_float; + const int in_channels = ibuf->channels; + const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied; + + for (int y = 0; y < height; y++) { + const size_t in_offset = (offset_y + y) * ibuf->x + offset_x; + const size_t out_offset = y * width; + const float *in = in_buffer + in_offset * in_channels; + float *out = out_buffer + out_offset * 4; + + if (in_channels == 1) { + /* Copy single channel. */ + for (int x = 0; x < width; x++, in += 1, out += 4) { + out[0] = in[0]; + out[1] = in[0]; + out[2] = in[0]; + out[3] = in[0]; + } } - } - else if (in_channels == 3) { - /* Copy RGB. */ - for (int x = 0; x < width; x++, in += 3, out += 4) { - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = 1.0f; + else if (in_channels == 3) { + /* Copy RGB. */ + for (int x = 0; x < width; x++, in += 3, out += 4) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 1.0f; + } } - } - else if (in_channels == 4) { - /* Copy or convert RGBA. */ - if (use_unpremultiply) { - for (int x = 0; x < width; x++, in += 4, out += 4) { - premul_to_straight_v4_v4(out, in); + else if (in_channels == 4) { + /* Copy or convert RGBA. */ + if (use_unpremultiply) { + for (int x = 0; x < width; x++, in += 4, out += 4) { + premul_to_straight_v4_v4(out, in); + } + } + else { + memcpy(out, in, sizeof(float[4]) * width); } } - else { - memcpy(out, in, sizeof(float[4]) * width); + } + } + else { + /* Byte source buffer. */ + const unsigned char *in_buffer = (unsigned char *)ibuf->rect; + const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied; + + /* TODO(brecht): make this multi-threaded, or at least process in batches. */ + OCIO_ConstCPUProcessorRcPtr *processor = (ibuf->rect_colorspace) ? + colorspace_to_scene_linear_cpu_processor( + ibuf->rect_colorspace) : + NULL; + + for (int y = 0; y < height; y++) { + const size_t in_offset = (offset_y + y) * ibuf->x + offset_x; + const size_t out_offset = y * width; + const unsigned char *in = in_buffer + in_offset * 4; + float *out = out_buffer + out_offset * 4; + + /* Convert to scene linear, to sRGB and premultiply. */ + for (int x = 0; x < width; x++, in += 4, out += 4) { + float pixel[4]; + rgba_uchar_to_float(pixel, in); + if (processor) { + OCIO_cpuProcessorApplyRGB(processor, pixel); + } + else { + srgb_to_linearrgb_v3_v3(pixel, pixel); + } + if (use_premultiply) { + mul_v3_fl(pixel, pixel[3]); + } + copy_v4_v4(out, pixel); } } } @@ -2464,22 +2481,21 @@ static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool IMB_metadata_copy(colormanaged_ibuf, ibuf); return colormanaged_ibuf; } - else { - /* Render pipeline is constructing image buffer itself, - * but it's re-using byte and float buffers from render result make copy of this buffers - * here sine this buffers would be transformed to other color space here. */ - if (ibuf->rect && (ibuf->mall & IB_rect) == 0) { - ibuf->rect = MEM_dupallocN(ibuf->rect); - ibuf->mall |= IB_rect; - } - if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) { - ibuf->rect_float = MEM_dupallocN(ibuf->rect_float); - ibuf->mall |= IB_rectfloat; - } + /* Render pipeline is constructing image buffer itself, + * but it's re-using byte and float buffers from render result make copy of this buffers + * here sine this buffers would be transformed to other color space here. */ + if (ibuf->rect && (ibuf->mall & IB_rect) == 0) { + ibuf->rect = MEM_dupallocN(ibuf->rect); + ibuf->mall |= IB_rect; + } - return ibuf; + if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) { + ibuf->rect_float = MEM_dupallocN(ibuf->rect_float); + ibuf->mall |= IB_rectfloat; } + + return ibuf; } ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index ec25b67af5f..13bf3697946 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -22,7 +22,6 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include <math.h> void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf) { diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index cffa61977f7..06f9202a1c6 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -524,8 +524,8 @@ struct ImBuf *imb_thumbnail_jpeg(const char *filepath, unsigned int i = JPEG_APP1_MAX; /* All EXIF data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */ while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) && - !feof(infile) && i--) - ; + !feof(infile) && i--) { + } if (i > 0 && !feof(infile)) { /* We found a JPEG thumbnail inside this image. */ ImBuf *ibuf = NULL; diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 54ef5438c23..0414fa1268d 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -174,14 +174,14 @@ class IMMapStream : public Imf::IStream { imb_mmap_lock(); _mmap_file = BLI_mmap_open(file); imb_mmap_unlock(); - if (_mmap_file == NULL) { + if (_mmap_file == nullptr) { throw IEX_NAMESPACE::InputExc("BLI_mmap_open failed"); } close(file); _exrbuf = (unsigned char *)BLI_mmap_get_pointer(_mmap_file); } - ~IMMapStream() + ~IMMapStream() override { imb_mmap_lock(); BLI_mmap_free(_mmap_file); @@ -512,7 +512,7 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags /* we store first everything in half array */ std::vector<RGBAZ> pixels(height * width); - RGBAZ *to = &pixels[0]; + RGBAZ *to = pixels.data(); int xstride = sizeof(RGBAZ); int ystride = xstride * width; @@ -1010,7 +1010,7 @@ void IMB_exrtile_begin_write( /* manually create ofstream, so we can handle utf-8 filepaths on windows */ try { data->ofile_stream = new OFileStream(filepath); - data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size()); + data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size()); } catch (const std::exception &) { delete data->mpofile; @@ -2209,7 +2209,7 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath, if (file->header().hasPreviewImage()) { const Imf::PreviewImage &preview = file->header().previewImage(); ImBuf *ibuf = IMB_allocFromBuffer( - (unsigned int *)preview.pixels(), NULL, preview.width(), preview.height(), 4); + (unsigned int *)preview.pixels(), nullptr, preview.width(), preview.height(), 4); delete file; delete stream; IMB_flipy(ibuf); diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h index a62c87428b6..40a724c9f42 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.h +++ b/source/blender/imbuf/intern/openexr/openexr_api.h @@ -27,8 +27,8 @@ bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags); struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char *colorspace); struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath, - const int flags, - const size_t max_thumb_size, + int flags, + size_t max_thumb_size, char colorspace[], size_t *r_width, size_t *r_height); diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c index 52756891f21..2a0baaf6172 100644 --- a/source/blender/imbuf/intern/stereoimbuf.c +++ b/source/blender/imbuf/intern/stereoimbuf.c @@ -702,21 +702,21 @@ int *IMB_stereo3d_from_rect(const ImageFormatData *im_format, int *rect_left, int *rect_right) { - int *r_rect; + int *rect_result; Stereo3DData s3d_data = {{NULL}}; size_t width, height; const bool is_float = im_format->depth > 8; IMB_stereo3d_write_dimensions( im_format->stereo3d_format.display_mode, false, x, y, &width, &height); - r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__); + rect_result = MEM_mallocN(channels * sizeof(int) * width * height, __func__); imb_stereo3d_data_init( - &s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL); + &s3d_data, is_float, x, y, channels, rect_left, rect_right, rect_result, NULL, NULL, NULL); imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format); - imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels); + imb_stereo3d_squeeze_rect(rect_result, &im_format->stereo3d_format, x, y, channels); - return r_rect; + return rect_result; } float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format, @@ -726,21 +726,30 @@ float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format, float *rectf_left, float *rectf_right) { - float *r_rectf; + float *rectf_result; Stereo3DData s3d_data = {{NULL}}; size_t width, height; const bool is_float = im_format->depth > 8; IMB_stereo3d_write_dimensions( im_format->stereo3d_format.display_mode, false, x, y, &width, &height); - r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__); + rectf_result = MEM_mallocN(channels * sizeof(float) * width * height, __func__); - imb_stereo3d_data_init( - &s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf); + imb_stereo3d_data_init(&s3d_data, + is_float, + x, + y, + channels, + NULL, + NULL, + NULL, + rectf_left, + rectf_right, + rectf_result); imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format); - imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels); + imb_stereo3d_squeeze_rectf(rectf_result, &im_format->stereo3d_format, x, y, channels); - return r_rectf; + return rectf_result; } ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right) diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index f2c9c82fa66..6f39009d38d 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -30,7 +30,6 @@ #include "IMB_thumbs.h" #include <ctype.h> -#include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> @@ -514,7 +513,7 @@ void IMB_thumb_delete(const char *filepath, ThumbSize size) } } -ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source) +ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source) { char thumb_path[FILE_MAX]; char thumb_name[40]; @@ -526,7 +525,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source ImBuf *img = NULL; char *blen_group = NULL, *blen_id = NULL; - path = file_path = org_path; + path = file_path = filepath; if (source == THB_SOURCE_BLEND) { if (BLO_library_path_explode(path, path_buff, &blen_group, &blen_id)) { if (blen_group) { diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 1372aa31713..2f13ef409e3 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -8,15 +8,15 @@ * Provides TIFF file loading and saving for Blender, via libtiff. * * The task of loading is complicated somewhat by the fact that Blender has - * already loaded the file into a memory buffer. libtiff is not well + * already loaded the file into a memory buffer. libtiff is not well * configured to handle files in memory, so a client wrapper is written to - * surround the memory and turn it into a virtual file. Currently, reading - * of TIFF files is done using libtiff's RGBAImage support. This is a + * surround the memory and turn it into a virtual file. Currently, reading + * of TIFF files is done using libtiff's RGBAImage support. This is a * high-level routine that loads all images as 32-bit RGBA, handling all the * required conversions between many different TIFF types internally. * * Saving supports RGB, RGBA and BW (gray-scale) images correctly, with - * 8 bits per channel in all cases. The "deflate" compression algorithm is + * 8 bits per channel in all cases. The "deflate" compression algorithm is * used to compress images. */ @@ -151,8 +151,8 @@ static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n) /** * Writes data to an in-memory TIFF file. * - * NOTE: The current Blender implementation should not need this function. It - * is simply a stub. + * NOTE: The current Blender implementation should not need this function. + * It is simply a stub. */ static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n) { @@ -176,7 +176,7 @@ static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n) * error). * * \return Resulting offset location within the file, measured in bytes from - * the beginning of the file. (-1) indicates an error. + * the beginning of the file. (-1) indicates an error. */ static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) { @@ -215,8 +215,8 @@ static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence) * Closes (virtually) an in-memory TIFF file. * * NOTE: All this function actually does is sets the data pointer within the - * TIFF file to NULL. That should trigger assertion errors if attempts - * are made to access the file after that point. However, no such + * TIFF file to NULL. That should trigger assertion errors if attempts + * are made to access the file after that point. However, no such * attempts should ever be made (in theory). * * \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile). @@ -734,7 +734,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags) int x, y, from_i, to_i, i; int compress_mode = COMPRESSION_NONE; - /* check for a valid number of bytes per pixel. Like the PNG writer, + /* check for a valid number of bytes per pixel. Like the PNG writer, * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding * to gray, RGB, RGBA respectively. */ samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3); @@ -838,7 +838,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags) TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); } - /* copy pixel data. While copying, we flip the image vertically. */ + /* copy pixel data. While copying, we flip the image vertically. */ const int channels_in_float = ibuf->channels ? ibuf->channels : 4; for (x = 0; x < ibuf->x; x++) { for (y = 0; y < ibuf->y; y++) { diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc index edb47c8c7ce..1499c1071e3 100644 --- a/source/blender/imbuf/intern/transform.cc +++ b/source/blender/imbuf/intern/transform.cc @@ -293,30 +293,37 @@ class Sampler { NumChannels == 4) { const float wrapped_u = uv_wrapper.modify_u(source, u); const float wrapped_v = uv_wrapper.modify_v(source, v); - bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v); + bilinear_interpolation_color_fl(source, nullptr, r_sample.data(), wrapped_u, wrapped_v); } else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, unsigned char> && NumChannels == 4) { const float wrapped_u = uv_wrapper.modify_u(source, u); const float wrapped_v = uv_wrapper.modify_v(source, v); - nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v); + nearest_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v); } else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, unsigned char> && NumChannels == 4) { const float wrapped_u = uv_wrapper.modify_u(source, u); const float wrapped_v = uv_wrapper.modify_v(source, v); - bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v); + bilinear_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v); } else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) { if constexpr (std::is_same_v<UVWrapping, WrapRepeatUV>) { - BLI_bilinear_interpolation_wrap_fl( - source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true); + BLI_bilinear_interpolation_wrap_fl(source->rect_float, + r_sample.data(), + source->x, + source->y, + NumChannels, + u, + v, + true, + true); } else { const float wrapped_u = uv_wrapper.modify_u(source, u); const float wrapped_v = uv_wrapper.modify_v(source, v); BLI_bilinear_interpolation_fl(source->rect_float, - &r_sample[0], + r_sample.data(), source->x, source->y, NumChannels, @@ -390,11 +397,11 @@ class ChannelConverter { BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels."); BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels."); - copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]); + copy_v4_v4_uchar(pixel_pointer.get_pointer(), sample.data()); } else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 && DestinationNumChannels == 4) { - copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]); + copy_v4_v4(pixel_pointer.get_pointer(), sample.data()); } else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 && DestinationNumChannels == 4) { diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index 8e004938a89..5feb0ceb515 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -28,17 +28,30 @@ static void imb_gpu_get_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format) { const bool float_rect = (ibuf->rect_float != NULL); - const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) && - !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)); - high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth); - - *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE; if (float_rect) { - *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F; + /* 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; } else { - *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8; + 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; + } + 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; + } + else { + /* Other colorspace, store as half float texture to avoid precision loss. */ + *r_data_format = GPU_DATA_FLOAT; + *r_texture_format = GPU_RGBA16F; + } } } @@ -74,7 +87,6 @@ static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat * static void *imb_gpu_get_data(const ImBuf *ibuf, const bool do_rescale, const int rescale_size[2], - const bool compress_as_srgb, const bool store_premultiplied, bool *r_freedata) { @@ -99,14 +111,16 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, } } else { - /* Byte image is in original colorspace from the file. If the file is sRGB - * scene linear, or non-color data no conversion is needed. Otherwise we - * compress as scene linear + sRGB transfer function to avoid precision loss - * in common cases. + /* Byte image is in original colorspace from the file, and may need conversion. * * We must also convert to premultiplied for correct texture interpolation * and consistency with float images. */ - if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { + if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { + /* Non-color data, just store buffer as is. */ + } + 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__); *r_freedata = freedata = true; @@ -120,7 +134,24 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, * 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, compress_as_srgb, store_premultiplied); + (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied); + } + else { + /* Other colorspace, store as float texture to avoid precision loss. */ + data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__); + *r_freedata = freedata = true; + + if (data_rect == NULL) { + return NULL; + } + + /* Texture storage of images is defined by the alpha mode of the image. The + * downside of this is that there can be artifacts near alpha edges. However, + * 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_float_texture( + (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied); } } @@ -181,10 +212,9 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex, eGPUTextureFormat tex_format; imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format); - const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8); bool freebuf = false; - void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf); + void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf); /* Update Texture. */ GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1); @@ -238,7 +268,6 @@ GPUTexture *IMB_create_gpu_texture(const char *name, eGPUTextureFormat tex_format; imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format); - const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8); bool freebuf = false; /* Create Texture. */ @@ -250,7 +279,7 @@ GPUTexture *IMB_create_gpu_texture(const char *name, do_rescale = true; } BLI_assert(tex != NULL); - void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf); + void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf); GPU_texture_update(tex, data_format, data); GPU_texture_anisotropic_filter(tex, true); diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt index b5f2694c2da..8b20b50a181 100644 --- a/source/blender/io/CMakeLists.txt +++ b/source/blender/io/CMakeLists.txt @@ -1,8 +1,21 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright 2020 Blender Foundation. All rights reserved. -add_subdirectory(common) -add_subdirectory(wavefront_obj) +if(WITH_IO_WAVEFRONT_OBJ OR WITH_IO_STL OR WITH_IO_GPENCIL OR WITH_ALEMBIC OR WITH_USD) + add_subdirectory(common) +endif() + +if(WITH_IO_WAVEFRONT_OBJ) + add_subdirectory(wavefront_obj) +endif() + +if(WITH_IO_STL) + add_subdirectory(stl) +endif() + +if(WITH_IO_GPENCIL) + add_subdirectory(gpencil) +endif() if(WITH_ALEMBIC) add_subdirectory(alembic) @@ -19,5 +32,3 @@ endif() if(WITH_USD) add_subdirectory(usd) endif() - -add_subdirectory(gpencil) diff --git a/source/blender/io/alembic/exporter/abc_custom_props.cc b/source/blender/io/alembic/exporter/abc_custom_props.cc index 23a39ca2ee6..c5cc4631e18 100644 --- a/source/blender/io/alembic/exporter/abc_custom_props.cc +++ b/source/blender/io/alembic/exporter/abc_custom_props.cc @@ -150,7 +150,7 @@ void CustomPropertiesExporter::write_idparray_of_strings(const IDProperty *idp_a } /* Alembic needs a pointer to the first value of the array. */ - const std::string *array_of_strings = &strings[0]; + const std::string *array_of_strings = strings.data(); set_array_property<OStringArrayProperty, std::string>( idp_array->name, array_of_strings, strings.size()); } @@ -204,7 +204,7 @@ void CustomPropertiesExporter::write_idparray_flattened_typed(const IDProperty * } set_array_property<ABCPropertyType, BlenderValueType>( - idp_array->name, &matrix_values[0], matrix_values.size()); + idp_array->name, matrix_values.data(), matrix_values.size()); } template<typename ABCPropertyType, typename BlenderValueType> diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 633611cf1a6..2820a128072 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -257,7 +257,7 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig & /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them * unnormalized, so we need to unnormalize (invert transform) them. */ BKE_mesh_orco_verts_transform( - mesh, reinterpret_cast<float(*)[3]>(&coords[0]), mesh->totvert, true); + mesh, reinterpret_cast<float(*)[3]>(coords.data()), mesh->totvert, true); if (!config.abc_orco.valid()) { /* Create the Alembic property and keep a reference so future frames can reuse it. */ @@ -273,7 +273,7 @@ void write_custom_data(const OCompoundProperty &prop, CustomData *data, int data_type) { - CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); + eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type); if (!CustomData_has_layer(data, cd_data_type)) { return; diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 98a3bdc0ec8..d5bfabf14b6 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -372,7 +372,7 @@ BLI_INLINE void read_uvs_params(CDStreamConfig &config, static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) { - CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); + eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type); /* unsupported custom data type -- don't do anything. */ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_PROP_BYTE_COLOR)) { diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index 0d4e1d04db0..1fb535a57f2 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -573,12 +573,10 @@ static void import_endjob(void *user_data) ImportJobData *data = static_cast<ImportJobData *>(user_data); - std::vector<AbcObjectReader *>::iterator iter; - /* Delete objects on cancellation. */ if (data->was_cancelled) { - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - Object *ob = (*iter)->object(); + for (AbcObjectReader *reader : data->readers) { + Object *ob = reader->object(); /* It's possible that cancellation occurred between the creation of * the reader and the creation of the Blender object. */ @@ -590,7 +588,6 @@ static void import_endjob(void *user_data) } } else { - /* Add object to scene. */ Base *base; LayerCollection *lc; ViewLayer *view_layer = data->view_layer; @@ -599,11 +596,17 @@ static void import_endjob(void *user_data) lc = BKE_layer_collection_get_active(view_layer); - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - Object *ob = (*iter)->object(); - + /* Add all objects to the collection (don't do sync for each object). */ + BKE_layer_collection_resync_forbid(); + for (AbcObjectReader *reader : data->readers) { + Object *ob = reader->object(); BKE_collection_object_add(data->bmain, lc->collection, ob); - + } + /* Sync the collection, and do view layer operations. */ + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync(data->bmain); + for (AbcObjectReader *reader : data->readers) { + Object *ob = reader->object(); base = BKE_view_layer_base_find(view_layer, ob); /* TODO: is setting active needed? */ BKE_view_layer_base_select_and_set_active(view_layer, base); @@ -625,8 +628,7 @@ static void import_endjob(void *user_data) } } - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - AbcObjectReader *reader = *iter; + for (AbcObjectReader *reader : data->readers) { reader->decref(); if (reader->refcount() == 0) { diff --git a/source/blender/io/avi/AVI_avi.h b/source/blender/io/avi/AVI_avi.h index e3af171355d..0857b9191b2 100644 --- a/source/blender/io/avi/AVI_avi.h +++ b/source/blender/io/avi/AVI_avi.h @@ -235,7 +235,8 @@ AviError AVI_close_compress(AviMovie *movie); */ AviError AVI_set_compress_option( AviMovie *movie, int option_type, int stream, AviOption option, void *opt_data); -/* Hmmm... there should be some explanation about what these mean */ + +/* TODO: there should be some explanation about what these mean. */ /** * Compression option, for use in avi_set_compress_option */ diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp index 29c17b500f3..cbb30ccf51d 100644 --- a/source/blender/io/collada/BCAnimationSampler.cpp +++ b/source/blender/io/collada/BCAnimationSampler.cpp @@ -225,24 +225,26 @@ bool BCAnimationSampler::is_animated_by_constraint(Object *ob, for (con = (bConstraint *)conlist->first; con; con = con->next) { ListBase targets = {nullptr, nullptr}; - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (!bc_validateConstraints(con)) { continue; } - if (cti && cti->get_constraint_targets) { + if (BKE_constraint_targets_get(con, &targets)) { bConstraintTarget *ct; Object *obtar; - cti->get_constraint_targets(con, &targets); + bool found = false; + for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { obtar = ct->tar; if (obtar) { if (animated_objects.find(obtar) != animated_objects.end()) { - return true; + found = true; + break; } } } + BKE_constraint_targets_flush(con, &targets, true); + return found; } } return false; diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp index fc97110611a..d48e46ca115 100644 --- a/source/blender/io/collada/BCMath.cpp +++ b/source/blender/io/collada/BCMath.cpp @@ -49,11 +49,7 @@ BCMatrix::BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis float mrot[3][3]; float mat[4][4]; mat3_from_axis_conversion( - BC_DEFAULT_FORWARD, BC_DEFAULT_UP, global_forward_axis, global_up_axis, mrot); - - /* TODO: Verify that `mat3_from_axis_conversion()` returns a transposed matrix */ - transpose_m3(mrot); - + global_forward_axis, global_up_axis, BC_DEFAULT_FORWARD, BC_DEFAULT_UP, mrot); copy_m4_m3(mat, mrot); set_transform(mat); } diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h index 85f960abfe6..416b5728b66 100644 --- a/source/blender/io/collada/MeshImporter.h +++ b/source/blender/io/collada/MeshImporter.h @@ -72,7 +72,7 @@ class MeshImporter : public MeshImporterBase { std::map<std::string, std::string> mesh_geom_map; /* needed for correct shape key naming */ std::map<COLLADAFW::UniqueId, Mesh *> uid_mesh_map; /* geometry unique id-to-mesh map */ - std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom uid-to-object */ + std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom UID-to-object */ std::vector<Object *> imported_objects; /* list of imported objects */ /* this structure is used to assign material indices to polygons @@ -86,7 +86,7 @@ class MeshImporter : public MeshImporterBase { /* crazy name! */ std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; /* < materials that have already been mapped to a geometry. - * A pair/of geom uid and mat uid, one geometry can have several materials */ + * A pair/of geom UID and mat UID, one geometry can have several materials. */ std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom; bool set_poly_indices( diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp index ea95729666a..1b1da110573 100644 --- a/source/blender/io/collada/SceneExporter.cpp +++ b/source/blender/io/collada/SceneExporter.cpp @@ -191,24 +191,19 @@ void SceneExporter::writeNode(Object *ob) /* not ideal: add the target object name as another parameter. * No real mapping in the `.dae`. * Need support for multiple target objects also. */ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {nullptr, nullptr}; - if (cti && cti->get_constraint_targets) { + ListBase targets = {nullptr, nullptr}; + if (BKE_constraint_targets_get(con, &targets)) { bConstraintTarget *ct; Object *obtar; - cti->get_constraint_targets(con, &targets); - for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { obtar = ct->tar; std::string tar_id((obtar) ? id_name(obtar) : ""); colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id); } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, true); - } + BKE_constraint_targets_flush(con, &targets, true); } con = con->next; diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt index e80bd850825..a6818c0bf5d 100644 --- a/source/blender/io/common/CMakeLists.txt +++ b/source/blender/io/common/CMakeLists.txt @@ -8,6 +8,7 @@ set(INC ../../depsgraph ../../makesdna ../../../../intern/guardedalloc + ../../makesrna ) set(INC_SYS @@ -19,12 +20,14 @@ set(SRC intern/dupli_persistent_id.cc intern/object_identifier.cc intern/path_util.cc + intern/orientation.c IO_abstract_hierarchy_iterator.h IO_dupli_persistent_id.hh IO_path_util.hh IO_path_util_types.h IO_types.h + IO_orientation.h intern/dupli_parent_finder.hh ) diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h index 3371501db95..a67cfe6a9d6 100644 --- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h +++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h @@ -59,9 +59,8 @@ struct HierarchyContext { * * The export hierarchy is kept as close to the hierarchy in Blender as possible. As such, an * object that serves as a parent for another object, but which should NOT be exported itself, is - * exported only as transform (i.e. as empty). This happens with objects that are part of a - * holdout collection (which prevents them from being exported) but also parent of an exported - * object. */ + * exported only as transform (i.e. as empty). This happens with objects that are invisible when + * exporting with "Visible Only" enabled, for example. */ bool weak_export; /* When true, this object should check its parents for animation data when determining whether diff --git a/source/blender/io/common/IO_orientation.h b/source/blender/io/common/IO_orientation.h new file mode 100644 index 00000000000..09fcbc7045c --- /dev/null +++ b/source/blender/io/common/IO_orientation.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "RNA_types.h" + +typedef enum { + IO_AXIS_X = 0, + IO_AXIS_Y = 1, + IO_AXIS_Z = 2, + IO_AXIS_NEGATIVE_X = 3, + IO_AXIS_NEGATIVE_Y = 4, + IO_AXIS_NEGATIVE_Z = 5, +} eIOAxis; + +extern const EnumPropertyItem io_transform_axis[]; diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc index 82bb1c57833..1fbddc45964 100644 --- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc @@ -267,6 +267,11 @@ void AbstractHierarchyIterator::export_graph_construct() { Scene *scene = DEG_get_evaluated_scene(depsgraph_); + /* Add a "null" root node with no children immediately for the case where the top-most node in + * the scene is not being exported and a root node otherwise wouldn't get added. */ + ExportGraph::key_type root_node_id = ObjectIdentifier::for_real_object(nullptr); + export_graph_[root_node_id] = ExportChildren(); + DEG_OBJECT_ITER_BEGIN (depsgraph_, object, DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | diff --git a/source/blender/io/common/intern/orientation.c b/source/blender/io/common/intern/orientation.c new file mode 100644 index 00000000000..0ffbaa8fe8e --- /dev/null +++ b/source/blender/io/common/intern/orientation.c @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "RNA_types.h" + +#include "IO_orientation.h" + +const EnumPropertyItem io_transform_axis[] = { + {IO_AXIS_X, "X", 0, "X", "Positive X axis"}, + {IO_AXIS_Y, "Y", 0, "Y", "Positive Y axis"}, + {IO_AXIS_Z, "Z", 0, "Z", "Positive Z axis"}, + {IO_AXIS_NEGATIVE_X, "NEGATIVE_X", 0, "-X", "Negative X axis"}, + {IO_AXIS_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y", "Negative Y axis"}, + {IO_AXIS_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z", "Negative Z axis"}, + {0, NULL, 0, NULL, NULL}}; diff --git a/source/blender/io/common/intern/path_util.cc b/source/blender/io/common/intern/path_util.cc index 902cf552bf0..18632b410f8 100644 --- a/source/blender/io/common/intern/path_util.cc +++ b/source/blender/io/common/intern/path_util.cc @@ -39,7 +39,7 @@ std::string path_reference(StringRefNull filepath, if (mode == PATH_REFERENCE_ABSOLUTE) { return filepath_abs; } - else if (mode == PATH_REFERENCE_RELATIVE) { + if (mode == PATH_REFERENCE_RELATIVE) { char rel_path[PATH_MAX]; BLI_strncpy(rel_path, filepath_abs, PATH_MAX); BLI_path_rel(rel_path, base_dst.c_str()); @@ -49,7 +49,7 @@ std::string path_reference(StringRefNull filepath, } return rel_path + 2; /* Skip blender's internal "//" prefix. */ } - else if (mode == PATH_REFERENCE_STRIP) { + if (mode == PATH_REFERENCE_STRIP) { return BLI_path_basename(filepath_abs); } BLI_assert_msg(false, "Invalid path reference mode"); diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt new file mode 100644 index 00000000000..e0c48bbbf7e --- /dev/null +++ b/source/blender/io/stl/CMakeLists.txt @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(INC + . + ./importer + ../common + ../../blenkernel + ../../blenlib + ../../bmesh + ../../bmesh/intern + ../../depsgraph + ../../editors/include + ../../makesdna + ../../makesrna + ../../nodes + ../../windowmanager + ../../../../extern/fast_float + ../../../../intern/guardedalloc +) + +set(INC_SYS + +) + +set(SRC + IO_stl.cc + importer/stl_import_mesh.cc + importer/stl_import_ascii_reader.cc + importer/stl_import_binary_reader.cc + importer/stl_import.cc + + IO_stl.h + importer/stl_import_mesh.hh + importer/stl_import_ascii_reader.hh + importer/stl_import_binary_reader.hh + importer/stl_import.hh +) + +set(LIB + bf_blenkernel + bf_io_common +) + +blender_add_lib(bf_stl "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/io/stl/IO_stl.cc b/source/blender/io/stl/IO_stl.cc new file mode 100644 index 00000000000..b26c1533692 --- /dev/null +++ b/source/blender/io/stl/IO_stl.cc @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include "BLI_timeit.hh" + +#include "IO_stl.h" +#include "stl_import.hh" + +void STL_import(bContext *C, const struct STLImportParams *import_params) +{ + SCOPED_TIMER("STL Import"); + blender::io::stl::importer_main(C, *import_params); +} diff --git a/source/blender/io/stl/IO_stl.h b/source/blender/io/stl/IO_stl.h new file mode 100644 index 00000000000..bbe537948e8 --- /dev/null +++ b/source/blender/io/stl/IO_stl.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include "BKE_context.h" +#include "BLI_path_util.h" +#include "IO_orientation.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct STLImportParams { + /** Full path to the source STL file to import. */ + char filepath[FILE_MAX]; + eIOAxis forward_axis; + eIOAxis up_axis; + bool use_facet_normal; + bool use_scene_unit; + float global_scale; + bool use_mesh_validate; +}; + +/** + * C-interface for the importer. + */ +void STL_import(bContext *C, const struct STLImportParams *import_params); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc new file mode 100644 index 00000000000..f358598a216 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import.cc @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include <cstdio> + +#include "BKE_customdata.h" +#include "BKE_layer.h" +#include "BKE_mesh.h" +#include "BKE_object.h" + +#include "DNA_collection_types.h" +#include "DNA_scene_types.h" + +#include "BLI_fileops.hh" +#include "BLI_math_vector.h" +#include "BLI_memory_utils.hh" + +#include "DNA_object_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "stl_import.hh" +#include "stl_import_ascii_reader.hh" +#include "stl_import_binary_reader.hh" + +namespace blender::io::stl { + +void importer_main(bContext *C, const STLImportParams &import_params) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + importer_main(bmain, scene, view_layer, import_params); +} + +void importer_main(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + const STLImportParams &import_params) +{ + FILE *file = BLI_fopen(import_params.filepath, "rb"); + if (!file) { + fprintf(stderr, "Failed to open STL file:'%s'.\n", import_params.filepath); + return; + } + BLI_SCOPED_DEFER([&]() { fclose(file); }); + + /* Detect STL file type by comparing file size with expected file size, + * could check if file starts with "solid", but some files do not adhere, + * this is the same as the old Python importer. + */ + uint32_t num_tri = 0; + size_t file_size = BLI_file_size(import_params.filepath); + fseek(file, BINARY_HEADER_SIZE, SEEK_SET); + fread(&num_tri, sizeof(uint32_t), 1, file); + bool is_ascii_stl = (file_size != (BINARY_HEADER_SIZE + 4 + BINARY_STRIDE * num_tri)); + + /* Name used for both mesh and object. */ + char ob_name[FILE_MAX]; + BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX); + BLI_path_extension_replace(ob_name, FILE_MAX, ""); + + Mesh *mesh; + if (is_ascii_stl) { + mesh = read_stl_ascii(import_params.filepath, bmain, ob_name, import_params.use_facet_normal); + } + else { + mesh = read_stl_binary(file, bmain, ob_name, import_params.use_facet_normal); + } + + if (import_params.use_mesh_validate) { + bool verbose_validate = false; +#ifdef DEBUG + verbose_validate = true; +#endif + BKE_mesh_validate(mesh, verbose_validate, false); + } + + BKE_view_layer_base_deselect_all(view_layer); + LayerCollection *lc = BKE_layer_collection_get_active(view_layer); + Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name); + BKE_mesh_assign_object(bmain, obj, mesh); + BKE_collection_object_add(bmain, lc->collection, obj); + Base *base = BKE_view_layer_base_find(view_layer, obj); + BKE_view_layer_base_select_and_set_active(view_layer, base); + + float global_scale = import_params.global_scale; + if ((scene->unit.system != USER_UNIT_NONE) && import_params.use_scene_unit) { + global_scale *= scene->unit.scale_length; + } + float scale_vec[3] = {global_scale, global_scale, global_scale}; + float obmat3x3[3][3]; + unit_m3(obmat3x3); + float obmat4x4[4][4]; + unit_m4(obmat4x4); + /* +Y-forward and +Z-up are the Blender's default axis settings. */ + mat3_from_axis_conversion( + IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, obmat3x3); + copy_m4_m3(obmat4x4, obmat3x3); + rescale_m4(obmat4x4, scale_vec); + BKE_object_apply_mat4(obj, obmat4x4, true, false); + + DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE); + int flags = ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION | + ID_RECALC_BASE_FLAGS; + DEG_id_tag_update_ex(bmain, &obj->id, flags); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + DEG_relations_tag_update(bmain); +} +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import.hh b/source/blender/io/stl/importer/stl_import.hh new file mode 100644 index 00000000000..377544c26af --- /dev/null +++ b/source/blender/io/stl/importer/stl_import.hh @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include "IO_stl.h" + +namespace blender::io::stl { + +/* Main import function used from within Blender. */ +void importer_main(bContext *C, const STLImportParams &import_params); + +/* Used from tests, where full bContext does not exist. */ +void importer_main(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + const STLImportParams &import_params); + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc new file mode 100644 index 00000000000..2edb3c6a114 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include <cstdint> +#include <cstdio> + +#include "BKE_mesh.h" + +#include "BLI_fileops.hh" +#include "BLI_memory_utils.hh" +#include "BLI_string_ref.hh" + +#include "DNA_mesh_types.h" + +/* NOTE: we could use C++17 <charconv> from_chars to parse + * floats, but even if some compilers claim full support, + * their standard libraries are not quite there yet. + * LLVM/libc++ only has a float parser since LLVM 14, + * and gcc/libstdc++ since 11.1. So until at least these are + * the minimum spec, use an external library. */ +#include "fast_float.h" + +#include "stl_import.hh" +#include "stl_import_ascii_reader.hh" +#include "stl_import_mesh.hh" + +namespace blender::io::stl { + +class StringBuffer { + private: + char *start; + const char *end; + + public: + StringBuffer(char *buf, size_t len) + { + start = buf; + end = start + len; + } + + bool is_empty() const + { + return start == end; + } + + void drop_leading_control_chars() + { + while ((start < end) && (*start) <= ' ') { + start++; + } + } + + void drop_leading_non_control_chars() + { + while ((start < end) && (*start) > ' ') { + start++; + } + } + + void drop_line() + { + while (start < end && *start != '\n') { + start++; + } + } + + bool parse_token(const char *token, size_t token_length) + { + drop_leading_control_chars(); + if (end - start < token_length + 1) { + return false; + } + if (memcmp(start, token, token_length) != 0) { + return false; + } + if (start[token_length] > ' ') { + return false; + } + start += token_length + 1; + return true; + } + + void drop_token() + { + drop_leading_non_control_chars(); + drop_leading_control_chars(); + } + + void parse_float(float &out) + { + drop_leading_control_chars(); + /* Skip '+' */ + if (start < end && *start == '+') { + start++; + } + fast_float::from_chars_result res = fast_float::from_chars(start, end, out); + if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) { + out = 0.0f; + } + start = const_cast<char *>(res.ptr); + } +}; + +static inline void parse_float3(StringBuffer &buf, float out[3]) +{ + for (int i = 0; i < 3; i++) { + buf.parse_float(out[i]); + } +} + +Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals) +{ + size_t buffer_len; + void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len); + if (buffer == nullptr) { + fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath); + return BKE_mesh_add(bmain, mesh_name); + } + BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); }); + + int num_reserved_tris = 1024; + + StringBuffer str_buf(static_cast<char *>(buffer), buffer_len); + STLMeshHelper stl_mesh(num_reserved_tris, use_custom_normals); + float triangle_buf[3][3]; + float custom_normal_buf[3]; + str_buf.drop_line(); /* Skip header line */ + while (!str_buf.is_empty()) { + if (str_buf.parse_token("vertex", 6)) { + parse_float3(str_buf, triangle_buf[0]); + if (str_buf.parse_token("vertex", 6)) { + parse_float3(str_buf, triangle_buf[1]); + } + if (str_buf.parse_token("vertex", 6)) { + parse_float3(str_buf, triangle_buf[2]); + } + if (use_custom_normals) { + stl_mesh.add_triangle( + triangle_buf[0], triangle_buf[1], triangle_buf[2], custom_normal_buf); + } + else { + stl_mesh.add_triangle(triangle_buf[0], triangle_buf[1], triangle_buf[2]); + } + } + else if (str_buf.parse_token("facet", 5)) { + str_buf.drop_token(); /* Expecting "normal" */ + parse_float3(str_buf, custom_normal_buf); + } + else { + str_buf.drop_token(); + } + } + + return stl_mesh.to_mesh(bmain, mesh_name); +} + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.hh b/source/blender/io/stl/importer/stl_import_ascii_reader.hh new file mode 100644 index 00000000000..e8aed911bf1 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.hh @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include <cstdio> + +#include "BKE_mesh.h" + +#include "stl_import.hh" + +/** + * ASCII STL spec: + * <pre> + * solid name + * facet normal ni nj nk + * outer loop + * vertex v1x v1y v1z + * vertex v2x v2y v2z + * vertex v3x v3y v3z + * endloop + * endfacet + * ... + * endsolid name + * </pre> + */ + +namespace blender::io::stl { + +Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals); + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc new file mode 100644 index 00000000000..6eaed16160e --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include <cstdint> +#include <cstdio> + +#include "BKE_main.h" +#include "BKE_mesh.h" + +#include "BLI_array.hh" +#include "BLI_memory_utils.hh" + +#include "DNA_mesh_types.h" + +#include "stl_import_binary_reader.hh" +#include "stl_import_mesh.hh" + +namespace blender::io::stl { + +#pragma pack(push, 1) +struct STLBinaryTriangle { + float normal[3]; + float v1[3], v2[3], v3[3]; + uint16_t attribute_byte_count; +}; +#pragma pack(pop) + +Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals) +{ + const int chunk_size = 1024; + uint32_t num_tris = 0; + fseek(file, BINARY_HEADER_SIZE, SEEK_SET); + fread(&num_tris, sizeof(uint32_t), 1, file); + if (num_tris == 0) { + return BKE_mesh_add(bmain, mesh_name); + } + + Array<STLBinaryTriangle> tris_buf(chunk_size); + STLMeshHelper stl_mesh(num_tris, use_custom_normals); + size_t num_read_tris; + while ((num_read_tris = fread(tris_buf.data(), sizeof(STLBinaryTriangle), chunk_size, file))) { + for (size_t i = 0; i < num_read_tris; i++) { + if (use_custom_normals) { + stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3, tris_buf[i].normal); + } + else { + stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3); + } + } + } + + return stl_mesh.to_mesh(bmain, mesh_name); +} + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.hh b/source/blender/io/stl/importer/stl_import_binary_reader.hh new file mode 100644 index 00000000000..71d5dbbbe58 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_binary_reader.hh @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include <cstdio> + +#include "BKE_mesh.h" + +/* Binary STL spec.: + * UINT8[80] – Header - 80 bytes + * UINT32 – Number of triangles - 4 bytes + * For each triangle - 50 bytes: + * REAL32[3] – Normal vector - 12 bytes + * REAL32[3] – Vertex 1 - 12 bytes + * REAL32[3] – Vertex 2 - 12 bytes + * REAL32[3] – Vertex 3 - 12 bytes + * UINT16 – Attribute byte count - 2 bytes + */ + +namespace blender::io::stl { + +const size_t BINARY_HEADER_SIZE = 80; +const size_t BINARY_STRIDE = 12 * 4 + 2; + +Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals); + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc new file mode 100644 index 00000000000..b9ed441f0d9 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_mesh.h" + +#include "BLI_array.hh" +#include "BLI_math_vector.h" +#include "BLI_math_vector.hh" +#include "BLI_task.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "stl_import_mesh.hh" + +namespace blender::io::stl { + +STLMeshHelper::STLMeshHelper(int tris_num, bool use_custom_normals) + : use_custom_normals_(use_custom_normals) +{ + degenerate_tris_num_ = 0; + duplicate_tris_num_ = 0; + tris_.reserve(tris_num); + /* Upper bound (all vertices are unique). */ + verts_.reserve(tris_num * 3); + if (use_custom_normals) { + loop_normals_.reserve(tris_num * 3); + } +} + +bool STLMeshHelper::add_triangle(const float3 &a, const float3 &b, const float3 &c) +{ + int v1_id = verts_.index_of_or_add(a); + int v2_id = verts_.index_of_or_add(b); + int v3_id = verts_.index_of_or_add(c); + if ((v1_id == v2_id) || (v1_id == v3_id) || (v2_id == v3_id)) { + degenerate_tris_num_++; + return false; + } + if (!tris_.add({v1_id, v2_id, v3_id})) { + duplicate_tris_num_++; + return false; + } + return true; +} + +void STLMeshHelper::add_triangle(const float3 &a, + const float3 &b, + const float3 &c, + const float3 &custom_normal) +{ + if (add_triangle(a, b, c)) { + loop_normals_.append_n_times(custom_normal, 3); + } +} + +Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) +{ + if (degenerate_tris_num_ > 0) { + std::cout << "STL Importer: " << degenerate_tris_num_ << " degenerate triangles were removed" + << std::endl; + } + if (duplicate_tris_num_ > 0) { + std::cout << "STL Importer: " << duplicate_tris_num_ << " duplicate triangles were removed" + << std::endl; + } + + Mesh *mesh = BKE_mesh_add(bmain, mesh_name); + /* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */ + id_us_min(&mesh->id); + + mesh->totvert = verts_.size(); + mesh->mvert = static_cast<MVert *>( + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert)); + for (int i = 0; i < mesh->totvert; i++) { + copy_v3_v3(mesh->mvert[i].co, verts_[i]); + } + + mesh->totpoly = tris_.size(); + mesh->totloop = tris_.size() * 3; + mesh->mpoly = static_cast<MPoly *>( + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly)); + mesh->mloop = static_cast<MLoop *>( + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop)); + + threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) { + for (const int i : tris_range) { + mesh->mpoly[i].loopstart = 3 * i; + mesh->mpoly[i].totloop = 3; + + mesh->mloop[3 * i].v = tris_[i].v1; + mesh->mloop[3 * i + 1].v = tris_[i].v2; + mesh->mloop[3 * i + 2].v = tris_[i].v3; + } + }); + + /* NOTE: edges must be calculated first before setting custom normals. */ + BKE_mesh_calc_edges(mesh, false, false); + + if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) { + BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data())); + mesh->flag |= ME_AUTOSMOOTH; + } + + return mesh; +} + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh new file mode 100644 index 00000000000..f1c0d2126a9 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_mesh.hh @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include <cstdint> + +#include "BLI_math_vec_types.hh" +#include "BLI_set.hh" +#include "BLI_vector.hh" +#include "BLI_vector_set.hh" + +#include "DNA_mesh_types.h" + +namespace blender::io::stl { +class Triangle { + public: + int v1, v2, v3; + /* Based on an old version of Python's frozen-set hash + * https://web.archive.org/web/20220520211017/https://stackoverflow.com/questions/20832279/python-frozenset-hashing-algorithm-implementation + */ + uint64_t hash() const + { + uint64_t res = 1927868237UL; + res *= 4; + res ^= (v1 ^ (v1 << 16) ^ 89869747UL) * 3644798167UL; + res ^= (v2 ^ (v2 << 16) ^ 89869747UL) * 3644798167UL; + res ^= (v3 ^ (v3 << 16) ^ 89869747UL) * 3644798167UL; + return res * 69069U + 907133923UL; + } + friend bool operator==(const Triangle &a, const Triangle &b) + { + bool i = (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3); + bool j = (a.v1 == b.v1) && (a.v3 == b.v2) && (a.v2 == b.v3); + bool k = (a.v2 == b.v1) && (a.v1 == b.v2) && (a.v3 == b.v3); + + bool l = (a.v2 == b.v1) && (a.v3 == b.v2) && (a.v1 == b.v3); + bool m = (a.v3 == b.v1) && (a.v1 == b.v2) && (a.v2 == b.v3); + bool n = (a.v3 == b.v1) && (a.v2 == b.v2) && (a.v1 == b.v3); + + return i || j || k || l || m || n; + } +}; + +class STLMeshHelper { + private: + VectorSet<float3> verts_; + VectorSet<Triangle> tris_; + Vector<float3> loop_normals_; + int degenerate_tris_num_; + int duplicate_tris_num_; + const bool use_custom_normals_; + + public: + STLMeshHelper(int tris_num, bool use_custom_normals); + + /* Creates a new triangle from specified vertex locations, + * duplicate vertices and triangles are merged. + */ + bool add_triangle(const float3 &a, const float3 &b, const float3 &c); + void add_triangle(const float3 &a, + const float3 &b, + const float3 &c, + const float3 &custom_normal); + Mesh *to_mesh(Main *bmain, char *mesh_name); +}; + +} // namespace blender::io::stl diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc index 29b256125f0..4118205d87f 100644 --- a/source/blender/io/usd/intern/usd_capi_import.cc +++ b/source/blender/io/usd/intern/usd_capi_import.cc @@ -277,7 +277,6 @@ static void import_endjob(void *customdata) } } else if (data->archive) { - /* Add object to scene. */ Base *base; LayerCollection *lc; ViewLayer *view_layer = data->view_layer; @@ -286,20 +285,30 @@ static void import_endjob(void *customdata) lc = BKE_layer_collection_get_active(view_layer); + /* Add all objects to the collection (don't do sync for each object). */ + BKE_layer_collection_resync_forbid(); for (USDPrimReader *reader : data->archive->readers()) { - if (!reader) { continue; } - Object *ob = reader->object(); - if (!ob) { continue; } - BKE_collection_object_add(data->bmain, lc->collection, ob); + } + /* Sync the collection, and do view layer operations. */ + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync(data->bmain); + for (USDPrimReader *reader : data->archive->readers()) { + if (!reader) { + continue; + } + Object *ob = reader->object(); + if (!ob) { + continue; + } base = BKE_view_layer_base_find(view_layer, ob); /* TODO: is setting active needed? */ BKE_view_layer_base_select_and_set_active(view_layer, base); diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index e2562eca69b..46749b03169 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -62,11 +62,55 @@ static void build_mat_map(const Main *bmain, std::map<std::string, Material *> * } } +static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim) +{ + return pxr::UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial(); +} + +/* Returns an existing Blender material that corresponds to the USD + * material with with the given path. Returns null if no such material + * exists. */ +static Material *find_existing_material( + const pxr::SdfPath &usd_mat_path, + const USDImportParams ¶ms, + const std::map<std::string, Material *> &mat_map, + const std::map<std::string, std::string> &usd_path_to_mat_name) +{ + if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) { + /* Check if we've already created the Blender material with a modified name. */ + std::map<std::string, std::string>::const_iterator path_to_name_iter = + usd_path_to_mat_name.find(usd_mat_path.GetAsString()); + + if (path_to_name_iter != usd_path_to_mat_name.end()) { + std::string mat_name = path_to_name_iter->second; + std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name); + if (mat_iter != mat_map.end()) { + return mat_iter->second; + } + /* We can't find the Blender material which was previously created for this USD + * material, which should never happen. */ + BLI_assert_unreachable(); + } + } + else { + std::string mat_name = usd_mat_path.GetName(); + std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name); + + if (mat_iter != mat_map.end()) { + return mat_iter->second; + } + } + + return nullptr; +} + static void assign_materials(Main *bmain, Object *ob, const std::map<pxr::SdfPath, int> &mat_index_map, const USDImportParams ¶ms, - pxr::UsdStageRefPtr stage) + pxr::UsdStageRefPtr stage, + std::map<std::string, Material *> &mat_name_to_mat, + std::map<std::string, std::string> &usd_path_to_mat_name) { if (!(stage && bmain && ob)) { return; @@ -87,20 +131,13 @@ static void assign_materials(Main *bmain, return; } - /* TODO(kevin): use global map? */ - std::map<std::string, Material *> mat_map; - build_mat_map(bmain, &mat_map); - blender::io::usd::USDMaterialReader mat_reader(params, bmain); for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) { - std::string mat_name = it->first.GetName(); - std::map<std::string, Material *>::iterator mat_iter = mat_map.find(mat_name); - - Material *assigned_mat = nullptr; - - if (mat_iter == mat_map.end()) { + Material *assigned_mat = find_existing_material( + it->first, params, mat_name_to_mat, usd_path_to_mat_name); + if (!assigned_mat) { /* Blender material doesn't exist, so create it now. */ /* Look up the USD material. */ @@ -122,11 +159,14 @@ static void assign_materials(Main *bmain, continue; } - mat_map[mat_name] = assigned_mat; - } - else { - /* We found an existing Blender material. */ - assigned_mat = mat_iter->second; + const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->id.name + 2); + mat_name_to_mat[mat_name] = assigned_mat; + + if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) { + /* Record the name of the Blender material we created for the USD material + * with the given path. */ + usd_path_to_mat_name[it->first.GetAsString()] = mat_name; + } } if (assigned_mat) { @@ -134,7 +174,7 @@ static void assign_materials(Main *bmain, } else { /* This shouldn't happen. */ - std::cout << "WARNING: Couldn't assign material " << mat_name << std::endl; + std::cout << "WARNING: Couldn't assign material " << it->first << std::endl; } } } @@ -143,7 +183,7 @@ static void assign_materials(Main *bmain, static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type) { - CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); + eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type); void *cd_ptr; CustomData *loopdata; int numloops; @@ -710,11 +750,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, int current_mat = 0; if (!subsets.empty()) { for (const pxr::UsdGeomSubset &subset : subsets) { - pxr::UsdShadeMaterialBindingAPI subset_api = pxr::UsdShadeMaterialBindingAPI( - subset.GetPrim()); - - pxr::UsdShadeMaterial subset_mtl = subset_api.ComputeBoundMaterial(); + pxr::UsdShadeMaterial subset_mtl = utils::compute_bound_material(subset.GetPrim()); if (!subset_mtl) { continue; } @@ -743,10 +780,9 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, } if (r_mat_map->empty()) { - pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim_); - - if (pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial()) { + pxr::UsdShadeMaterial mtl = utils::compute_bound_material(prim_); + if (mtl) { pxr::SdfPath mtl_path = mtl.GetPath(); if (!mtl_path.IsEmpty()) { @@ -764,7 +800,17 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot std::map<pxr::SdfPath, int> mat_map; assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, &mat_map); - utils::assign_materials(bmain, object_, mat_map, this->import_params_, this->prim_.GetStage()); + /* Build material name map if it's not built yet. */ + if (this->settings_->mat_name_to_mat.empty()) { + utils::build_mat_map(bmain, &this->settings_->mat_name_to_mat); + } + utils::assign_materials(bmain, + object_, + mat_map, + this->import_params_, + this->prim_.GetStage(), + this->settings_->mat_name_to_mat, + this->settings_->usd_path_to_mat_name); } Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h index fdf6247de16..c44c4a14ad7 100644 --- a/source/blender/io/usd/intern/usd_reader_prim.h +++ b/source/blender/io/usd/intern/usd_reader_prim.h @@ -7,7 +7,11 @@ #include <pxr/usd/usd/prim.h> +#include <map> +#include <string> + struct Main; +struct Material; struct Object; namespace blender::io::usd { @@ -33,6 +37,17 @@ struct ImportSettings { CacheFile *cache_file; + /* Map a USD material prim path to a Blender material name. + * This map is updated by readers during stage traversal. + * This field is mutable because it is used to keep track + * of what the importer is doing. This is necessary even + * when all the other import settings are to remain const. */ + mutable std::map<std::string, std::string> usd_path_to_mat_name; + /* Map a material name to Blender material. + * This map is updated by readers during stage traversal, + * and is mutable similar to the map above. */ + mutable std::map<std::string, Material *> mat_name_to_mat; + ImportSettings() : do_convert_mat(false), from_up(0), diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc index 857896b9330..6862f3835cf 100644 --- a/source/blender/io/usd/intern/usd_writer_material.cc +++ b/source/blender/io/usd/intern/usd_writer_material.cc @@ -590,6 +590,7 @@ static std::string get_tex_image_asset_path(bNode *node, BLI_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX); BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, nullptr); } + BLI_str_replace_char(exp_path, '\\', '/'); return exp_path; } @@ -608,7 +609,7 @@ static std::string get_tex_image_asset_path(bNode *node, if (!BLI_path_is_rel(rel_path)) { return path; } - + BLI_str_replace_char(rel_path, '\\', '/'); return rel_path + 2; } diff --git a/source/blender/io/usd/intern/usd_writer_volume.cc b/source/blender/io/usd/intern/usd_writer_volume.cc index 4126be6966a..6300e5c657c 100644 --- a/source/blender/io/usd/intern/usd_writer_volume.cc +++ b/source/blender/io/usd/intern/usd_writer_volume.cc @@ -100,7 +100,7 @@ std::optional<std::string> USDVolumeWriter::resolve_vdb_file(const Volume *volum vdb_file_path = construct_vdb_file_path(volume); if (!BKE_volume_save( - volume, usd_export_context_.bmain, NULL, vdb_file_path.value_or("").c_str())) { + volume, usd_export_context_.bmain, nullptr, vdb_file_path.value_or("").c_str())) { return std::nullopt; } } diff --git a/source/blender/io/usd/tests/usd_imaging_test.cc b/source/blender/io/usd/tests/usd_imaging_test.cc index 497319c59bd..5cd3c042e59 100644 --- a/source/blender/io/usd/tests/usd_imaging_test.cc +++ b/source/blender/io/usd/tests/usd_imaging_test.cc @@ -42,8 +42,8 @@ TEST_F(USDImagingTest, CapsuleAdapterTest) } pxr::UsdImagingCapsuleAdapter capsule_adapter; - pxr::VtValue points_value = capsule_adapter.GetMeshPoints(capsule.GetPrim(), - pxr::UsdTimeCode::Default()); + pxr::VtValue points_value = pxr::UsdImagingCapsuleAdapter::GetMeshPoints( + capsule.GetPrim(), pxr::UsdTimeCode::Default()); if (!points_value.IsHolding<pxr::VtArray<pxr::GfVec3f>>()) { FAIL() << "Mesh points value holding unexpected type."; return; @@ -52,7 +52,7 @@ TEST_F(USDImagingTest, CapsuleAdapterTest) pxr::VtArray<pxr::GfVec3f> points = points_value.Get<pxr::VtArray<pxr::GfVec3f>>(); EXPECT_FALSE(points.empty()); - pxr::VtValue topology_value = capsule_adapter.GetMeshTopology(); + pxr::VtValue topology_value = pxr::UsdImagingCapsuleAdapter::GetMeshTopology(); if (!topology_value.IsHolding<pxr::HdMeshTopology>()) { FAIL() << "Mesh topology value holding unexpected type."; diff --git a/source/blender/io/usd/tests/usd_tests_common.h b/source/blender/io/usd/tests/usd_tests_common.h index 7f6ae558354..949348da959 100644 --- a/source/blender/io/usd/tests/usd_tests_common.h +++ b/source/blender/io/usd/tests/usd_tests_common.h @@ -12,7 +12,7 @@ namespace blender::io::usd { * Thus function must be called before instantiating a USD * stage to avoid errors. The returned string is the path to * the USD data files directory from which the plugins were - * loaded. If the USD data files directory can't be determined, + * loaded. If the USD data files directory can't be determined, * plugin registration is skipped and the empty string is * returned. */ std::string register_usd_plugins_for_tests(); diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index 2e4dcb0da94..a07315d8b4e 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -15,6 +15,13 @@ struct CacheReader; struct Object; struct bContext; +/* Behavior when the name of an imported material + * conflicts with an existing material. */ +typedef enum eUSDMtlNameCollisionMode { + USD_MTL_NAME_COLLISION_MAKE_UNIQUE = 0, + USD_MTL_NAME_COLLISION_REFERENCE_EXISTING = 1, +} eUSDMtlNameCollisionMode; + struct USDExportParams { bool export_animation; bool export_hair; @@ -57,6 +64,7 @@ struct USDImportParams { bool import_usd_preview; bool set_material_blend; float light_intensity_scale; + eUSDMtlNameCollisionMode mtl_name_collision_mode; }; /* The USD_export takes a as_background_job parameter, and returns a boolean. diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h index bebad06d37f..b4a00deb99c 100644 --- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h @@ -9,30 +9,13 @@ #include "BKE_context.h" #include "BLI_path_util.h" #include "DEG_depsgraph.h" +#include "IO_orientation.h" #include "IO_path_util_types.h" #ifdef __cplusplus extern "C" { #endif -typedef enum { - OBJ_AXIS_X_UP = 0, - OBJ_AXIS_Y_UP = 1, - OBJ_AXIS_Z_UP = 2, - OBJ_AXIS_NEGATIVE_X_UP = 3, - OBJ_AXIS_NEGATIVE_Y_UP = 4, - OBJ_AXIS_NEGATIVE_Z_UP = 5, -} eTransformAxisUp; - -typedef enum { - OBJ_AXIS_X_FORWARD = 0, - OBJ_AXIS_Y_FORWARD = 1, - OBJ_AXIS_Z_FORWARD = 2, - OBJ_AXIS_NEGATIVE_X_FORWARD = 3, - OBJ_AXIS_NEGATIVE_Y_FORWARD = 4, - OBJ_AXIS_NEGATIVE_Z_FORWARD = 5, -} eTransformAxisForward; - static const int TOTAL_AXES = 3; struct OBJExportParams { @@ -52,8 +35,8 @@ struct OBJExportParams { int end_frame; /* Geometry Transform options. */ - eTransformAxisForward forward_axis; - eTransformAxisUp up_axis; + eIOAxis forward_axis; + eIOAxis up_axis; float scaling_factor; /* File Write Options. */ @@ -62,6 +45,7 @@ struct OBJExportParams { eEvaluationMode export_eval_mode; bool export_uv; bool export_normals; + bool export_colors; bool export_materials; bool export_triangulated_mesh; bool export_curves_as_nurbs; @@ -86,8 +70,9 @@ struct OBJImportParams { char filepath[FILE_MAX]; /** Value 0 disables clamping. */ float clamp_size; - eTransformAxisForward forward_axis; - eTransformAxisUp up_axis; + eIOAxis forward_axis; + eIOAxis up_axis; + bool import_vertex_groups; bool validate_meshes; }; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 11d1bafdafe..cb95c561547 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -8,7 +8,9 @@ #include <cstdio> #include "BKE_blender_version.h" +#include "BKE_geometry_set.hh" +#include "BLI_color.hh" #include "BLI_enumerable_thread_specific.hh" #include "BLI_path_util.h" #include "BLI_task.hh" @@ -241,13 +243,38 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh, } void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, - const OBJMesh &obj_mesh_data) const + const OBJMesh &obj_mesh_data, + bool write_colors) const { const int tot_count = obj_mesh_data.tot_vertices(); - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { - float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); - buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]); - }); + + Mesh *mesh = obj_mesh_data.get_mesh(); + CustomDataLayer *colors_layer = nullptr; + if (write_colors) { + colors_layer = BKE_id_attributes_active_color_get(&mesh->id); + } + if (write_colors && (colors_layer != nullptr)) { + MeshComponent component; + component.replace(mesh, GeometryOwnershipType::ReadOnly); + VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>( + colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f}); + + BLI_assert(tot_count == attribute.size()); + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); + ColorGeometry4f linear = attribute.get(i); + float srgb[3]; + linearrgb_to_srgb_v3_v3(srgb, linear); + buf.write<eOBJSyntaxElement::vertex_coords_color>( + vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]); + }); + } + else { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); + buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]); + }); + } } void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh index 77da7b44276..97c23484426 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh @@ -72,9 +72,11 @@ class OBJWriter : NonMovable, NonCopyable { */ void write_mtllib_name(const StringRefNull mtl_filepath) const; /** - * Write vertex coordinates for all vertices as "v x y z". + * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b". */ - void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const; + void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, + const OBJMesh &obj_mesh_data, + bool write_colors) const; /** * Write UV vertex coordinates for all vertices as `vt u v`. * \note UV indices are stored here, but written with polygons later. diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh index f0263989bfc..5413c9969e3 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh @@ -30,6 +30,7 @@ enum class eFileType { enum class eOBJSyntaxElement { vertex_coords, + vertex_coords_color, uv_vertex_coords, normal, poly_element_begin, @@ -130,6 +131,9 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key case eOBJSyntaxElement::vertex_coords: { return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>}; } + case eOBJSyntaxElement::vertex_coords_color: { + return {"v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", 6, is_type_float<T...>}; + } case eOBJSyntaxElement::uv_vertex_coords: { return {"vt {:.6f} {:.6f}\n", 2, is_type_float<T...>}; } 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 c2a9e0574eb..e2ecda32717 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -117,15 +117,12 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval() return {triangulated, true}; } -void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward, - const eTransformAxisUp up) +void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) { float axes_transform[3][3]; unit_m3(axes_transform); /* +Y-forward and +Z-up are the default Blender axis settings. */ - mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); - /* mat3_from_axis_conversion returns a transposed matrix! */ - transpose_m3(axes_transform); + mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform); mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat); /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */ mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]); @@ -290,7 +287,7 @@ void OBJMesh::store_uv_coords_and_indices() const MLoop *mloop = export_mesh_eval_->mloop; const int totpoly = export_mesh_eval_->totpoly; const int totvert = export_mesh_eval_->totvert; - const MLoopUV *mloopuv = static_cast<MLoopUV *>( + const MLoopUV *mloopuv = static_cast<const MLoopUV *>( CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV)); if (!mloopuv) { tot_uv_vertices_ = 0; @@ -382,8 +379,8 @@ void OBJMesh::store_normal_coords_and_indices() normal_to_index.reserve(export_mesh_eval_->totpoly); loop_to_normal_index_.resize(export_mesh_eval_->totloop); loop_to_normal_index_.fill(-1); - const float( - *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL)); + const float(*lnors)[3] = static_cast<const float(*)[3]>( + CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL)); for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) { const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH); @@ -453,7 +450,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index, BLI_assert(poly_index < export_mesh_eval_->totpoly); BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_)); - const MDeformVert *dvert_layer = static_cast<MDeformVert *>( + const MDeformVert *dvert_layer = static_cast<const MDeformVert *>( CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT)); if (!dvert_layer) { return NOT_FOUND; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index f47ca423dbc..ee2e6227700 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -241,6 +241,11 @@ class OBJMesh : NonCopyable { return i < 0 || i >= poly_order_.size() ? i : poly_order_[i]; } + Mesh *get_mesh() const + { + return export_mesh_eval_; + } + private: /** * Free the mesh if _the exporter_ created it. @@ -256,6 +261,6 @@ class OBJMesh : NonCopyable { /** * Set the final transform after applying axes settings and an Object's world transform. */ - void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up); + void set_world_axes_transform(eIOAxis forward, eIOAxis up); }; } // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc index c247048ce13..172a59e5341 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc @@ -25,15 +25,12 @@ OBJCurve::OBJCurve(const Depsgraph *depsgraph, set_world_axes_transform(export_params.forward_axis, export_params.up_axis); } -void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward, - const eTransformAxisUp up) +void OBJCurve::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) { float axes_transform[3][3]; unit_m3(axes_transform); /* +Y-forward and +Z-up are the Blender's default axis settings. */ - mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); - /* mat3_from_axis_conversion returns a transposed matrix! */ - transpose_m3(axes_transform); + mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform); mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat); /* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */ mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh index fe826725daf..65389d44f59 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh @@ -56,7 +56,7 @@ class OBJCurve : NonCopyable { /** * Set the final transform after applying axes settings and an Object's world transform. */ - void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up); + void set_world_axes_transform(eIOAxis forward, eIOAxis up); }; } // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc index b6e636b389d..b0938084efb 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc @@ -195,7 +195,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me auto &fh = buffers[i]; obj_writer.write_object_name(fh, obj); - obj_writer.write_vertex_coords(fh, obj); + obj_writer.write_vertex_coords(fh, obj, export_params.export_colors); if (obj.tot_polygons() > 0) { if (export_params.export_smooth_groups) { diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc index 7019e67419e..f33753d720d 100644 --- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc +++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc @@ -99,13 +99,8 @@ void transform_object(Object *object, const OBJImportParams &import_params) float obmat[4][4]; unit_m4(obmat); /* +Y-forward and +Z-up are the default Blender axis settings. */ - mat3_from_axis_conversion(import_params.forward_axis, - import_params.up_axis, - OBJ_AXIS_Y_FORWARD, - OBJ_AXIS_Z_UP, - axes_transform); - /* mat3_from_axis_conversion returns a transposed matrix! */ - transpose_m3(axes_transform); + mat3_from_axis_conversion( + IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, axes_transform); copy_m4_m3(obmat, axes_transform); BKE_object_apply_mat4(object, obmat, true, false); diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index c7990028312..3cc17e7d8e6 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -5,12 +5,16 @@ */ #include "BLI_map.hh" +#include "BLI_math_color.h" +#include "BLI_math_vector.h" #include "BLI_string_ref.hh" #include "BLI_vector.hh" #include "obj_import_file_reader.hh" #include "obj_import_string_utils.hh" +#include <charconv> + namespace blender::io::obj { using std::string; @@ -34,6 +38,7 @@ static Geometry *create_geometry(Geometry *const prev_geometry, g->geom_type_ = new_type; g->geometry_name_ = name.is_empty() ? "New object" : name; g->vertex_start_ = global_vertices.vertices.size(); + g->vertex_color_start_ = global_vertices.vertex_colors.size(); r_offset.set_index_offset(g->vertex_start_); return g; }; @@ -71,9 +76,51 @@ static void geom_add_vertex(Geometry *geom, GlobalVertices &r_global_vertices) { float3 vert; - parse_floats(p, end, 0.0f, vert, 3); + p = parse_floats(p, end, 0.0f, vert, 3); r_global_vertices.vertices.append(vert); geom->vertex_count_++; + /* OBJ extension: `xyzrgb` vertex colors, when the vertex position + * is followed by 3 more RGB color components. See + * http://paulbourke.net/dataformats/obj/colour.html */ + if (p < end) { + float3 srgb; + p = parse_floats(p, end, -1.0f, srgb, 3); + if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) { + float3 linear; + srgb_to_linearrgb_v3_v3(linear, srgb); + r_global_vertices.vertex_colors.append(linear); + geom->vertex_color_count_++; + } + } +} + +static void geom_add_mrgb_colors(Geometry *geom, + const char *p, + const char *end, + GlobalVertices &r_global_vertices) +{ + /* MRGB color extension, in the form of + * "#MRGB MMRRGGBBMMRRGGBB ..." + * http://paulbourke.net/dataformats/obj/colour.html */ + p = drop_whitespace(p, end); + const int mrgb_length = 8; + while (p + mrgb_length <= end) { + uint32_t value = 0; + std::from_chars_result res = std::from_chars(p, p + mrgb_length, value, 16); + if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) { + return; + } + unsigned char srgb[4]; + srgb[0] = (value >> 16) & 0xFF; + srgb[1] = (value >> 8) & 0xFF; + srgb[2] = value & 0xFF; + srgb[3] = 0xFF; + float linear[4]; + srgb_to_linearrgb_uchar4(linear, srgb); + r_global_vertices.vertex_colors.append({linear[0], linear[1], linear[2]}); + geom->vertex_color_count_++; + p += mrgb_length; + } } static void geom_add_vertex_normal(Geometry *geom, @@ -83,6 +130,10 @@ static void geom_add_vertex_normal(Geometry *geom, { float3 normal; parse_floats(p, end, 0.0f, normal, 3); + /* Normals can be printed with only several digits in the file, + * making them ever-so-slightly non unit length. Make sure they are + * normalized. */ + normalize_v3(normal); r_global_vertices.vertex_normals.append(normal); geom->has_vertex_normals_ = true; } @@ -124,7 +175,7 @@ static void geom_add_polygon(Geometry *geom, curr_face.material_index = material_index; if (group_index >= 0) { curr_face.vertex_group_index = group_index; - geom->use_vertex_groups_ = true; + geom->has_vertex_groups_ = true; } const int orig_corners_size = geom->face_corners_.size(); @@ -149,7 +200,7 @@ static void geom_add_polygon(Geometry *geom, if (p < end && *p == '/') { ++p; p = parse_int(p, end, INT32_MAX, corner.vertex_normal_index, false); - got_normal = corner.uv_vert_index != INT32_MAX; + got_normal = corner.vertex_normal_index != INT32_MAX; } } /* Always keep stored indices non-negative and zero-based. */ @@ -172,7 +223,10 @@ static void geom_add_polygon(Geometry *geom, face_valid = false; } } - if (got_normal) { + /* Ignore corner normal index, if the geometry does not have any normals. + * Some obj files out there do have face definitions that refer to normal indices, + * without any normals being present (T98782). */ + if (got_normal && geom->has_vertex_normals_) { corner.vertex_normal_index += corner.vertex_normal_index < 0 ? global_vertices.vertex_normals.size() : -1; @@ -343,9 +397,14 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, return; } + /* Use the filename as the default name given to the initial object. */ + char ob_name[FILE_MAXFILE]; + BLI_strncpy(ob_name, BLI_path_basename(import_params_.filepath), FILE_MAXFILE); + BLI_path_extension_replace(ob_name, FILE_MAXFILE, ""); + VertexIndexOffset offsets; Geometry *curr_geom = create_geometry( - nullptr, GEOM_MESH, "", r_global_vertices, r_all_geometries, offsets); + nullptr, GEOM_MESH, ob_name, r_global_vertices, r_all_geometries, offsets); /* State variables: once set, they remain the same for the remaining * elements in the object. */ @@ -477,6 +536,9 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, else if (parse_keyword(p, end, "mtllib")) { add_mtl_library(StringRef(p, end).trim()); } + else if (parse_keyword(p, end, "#MRGB")) { + geom_add_mrgb_colors(curr_geom, p, end, r_global_vertices); + } /* Comments. */ else if (*p == '#') { /* Nothing to do. */ 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 8d560bd2c8c..aa38a4d6715 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -8,7 +8,9 @@ #include "DNA_mesh_types.h" #include "DNA_scene_types.h" +#include "BKE_attribute.h" #include "BKE_customdata.h" +#include "BKE_deform.h" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_node_tree_update.h" @@ -46,10 +48,11 @@ Object *MeshFromGeometry::create_mesh(Main *bmain, obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str()); create_vertices(mesh); - create_polys_loops(obj, mesh); + create_polys_loops(mesh, import_params.import_vertex_groups); create_edges(mesh); create_uv_verts(mesh); create_normals(mesh); + create_colors(mesh); create_materials(bmain, materials, created_materials, obj); if (import_params.validate_meshes || mesh_geometry_.has_invalid_polys_) { @@ -67,6 +70,9 @@ Object *MeshFromGeometry::create_mesh(Main *bmain, BKE_mesh_nomain_to_mesh(mesh, dst, obj, &CD_MASK_EVERYTHING, true); dst->flag |= autosmooth; + /* Note: vertex groups have to be created after final mesh is assigned to the object. */ + create_vertex_groups(obj); + return obj; } @@ -161,19 +167,13 @@ void MeshFromGeometry::create_vertices(Mesh *mesh) } } -void MeshFromGeometry::create_polys_loops(Object *obj, Mesh *mesh) +void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) { - /* Will not be used if vertex groups are not imported. */ mesh->dvert = nullptr; - float weight = 0.0f; const int64_t total_verts = mesh_geometry_.vertex_count_; - if (total_verts && mesh_geometry_.use_vertex_groups_) { + if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) { mesh->dvert = static_cast<MDeformVert *>( CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, total_verts)); - weight = 1.0f / total_verts; - } - else { - UNUSED_VARS(weight); } const int64_t tot_face_elems{mesh->totpoly}; @@ -206,28 +206,23 @@ void MeshFromGeometry::create_polys_loops(Object *obj, Mesh *mesh) tot_loop_idx++; mloop.v = curr_corner.vert_index; + /* Setup vertex group data, if needed. */ if (!mesh->dvert) { continue; } - /* Iterating over mloop results in finding the same vertex multiple times. - * Another way is to allocate memory for dvert while creating vertices and fill them here. - */ - MDeformVert &def_vert = mesh->dvert[mloop.v]; - if (!def_vert.dw) { - def_vert.dw = static_cast<MDeformWeight *>( - MEM_callocN(sizeof(MDeformWeight), "OBJ Import Deform Weight")); - } - /* Every vertex in a face is assigned the same deform group. */ - int group_idx = curr_face.vertex_group_index; - /* Deform group number (def_nr) must behave like an index into the names' list. */ - *(def_vert.dw) = {static_cast<unsigned int>(group_idx), weight}; + const int group_index = curr_face.vertex_group_index; + MDeformWeight *dw = BKE_defvert_ensure_index(mesh->dvert + mloop.v, group_index); + dw->weight = 1.0f; } } +} - if (!mesh->dvert) { +void MeshFromGeometry::create_vertex_groups(Object *obj) +{ + Mesh *mesh = static_cast<Mesh *>(obj->data); + if (mesh->dvert == nullptr) { return; } - /* Add deform group names. */ for (const std::string &name : mesh_geometry_.group_order_) { BKE_object_defgroup_add_name(obj, name.data()); } @@ -289,7 +284,7 @@ static Material *get_or_create_material(Main *bmain, /* We have not, will have to create it. Create a new default * MTLMaterial too, in case the OBJ file tries to use a material * that was not in the MTL file. */ - const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>()).get(); + const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>()); Material *mat = BKE_material_add(bmain, name.c_str()); ShaderNodetreeWrap mat_wrap{bmain, mtl, mat}; @@ -345,4 +340,26 @@ void MeshFromGeometry::create_normals(Mesh *mesh) MEM_freeN(loop_normals); } +void MeshFromGeometry::create_colors(Mesh *mesh) +{ + /* Nothing to do if we don't have vertex colors. */ + if (mesh_geometry_.vertex_color_count_ < 1) { + return; + } + if (mesh_geometry_.vertex_color_count_ != mesh_geometry_.vertex_count_) { + std::cerr << "Mismatching number of vertices (" << mesh_geometry_.vertex_count_ + << ") and colors (" << mesh_geometry_.vertex_color_count_ << ") on object '" + << mesh_geometry_.geometry_name_ << "', ignoring colors." << std::endl; + return; + } + + CustomDataLayer *color_layer = BKE_id_attribute_new( + &mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr); + float4 *colors = (float4 *)color_layer->data; + for (int i = 0; i < mesh_geometry_.vertex_color_count_; ++i) { + float3 c = global_vertices_.vertex_colors[mesh_geometry_.vertex_color_start_ + i]; + colors[i] = float4(c.x, c.y, c.z, 1.0f); + } +} + } // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh index cf4a2aee394..591a7b81e63 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh @@ -45,10 +45,9 @@ class MeshFromGeometry : NonMovable, NonCopyable { void fixup_invalid_faces(); void create_vertices(Mesh *mesh); /** - * Create polygons for the Mesh, set smooth shading flags, deform group names, - * Materials. + * Create polygons for the Mesh, set smooth shading flags, Materials. */ - void create_polys_loops(Object *obj, Mesh *mesh); + void create_polys_loops(Mesh *mesh, bool use_vertex_groups); /** * Add explicitly imported OBJ edges to the mesh. */ @@ -65,6 +64,8 @@ class MeshFromGeometry : NonMovable, NonCopyable { Map<std::string, Material *> &created_materials, Object *obj); void create_normals(Mesh *mesh); + void create_colors(Mesh *mesh); + void create_vertex_groups(Object *obj); }; } // namespace blender::io::obj 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 b67ba46af03..3d6733d661e 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh +++ b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh @@ -26,6 +26,7 @@ struct GlobalVertices { Vector<float3> vertices; Vector<float2> uv_vertices; Vector<float3> vertex_normals; + Vector<float3> vertex_colors; }; /** @@ -102,6 +103,8 @@ struct Geometry { int vertex_start_ = 0; int vertex_count_ = 0; + int vertex_color_start_ = 0; + int vertex_color_count_ = 0; /** Edges written in the file in addition to (or even without polygon) elements. */ Vector<MEdge> edges_; @@ -110,7 +113,7 @@ struct Geometry { bool has_invalid_polys_ = false; bool has_vertex_normals_ = false; - bool use_vertex_groups_ = false; + bool has_vertex_groups_ = false; NurbsElement nurbs_element_; int total_loops_ = 0; }; 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 8c49af90a82..6aec848573f 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -315,8 +315,8 @@ TEST_F(obj_exporter_regression_test, all_quads) TEST_F(obj_exporter_regression_test, fgons) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden( "io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params); @@ -325,8 +325,8 @@ TEST_F(obj_exporter_regression_test, fgons) TEST_F(obj_exporter_regression_test, edges) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden( "io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params); @@ -335,8 +335,8 @@ TEST_F(obj_exporter_regression_test, edges) TEST_F(obj_exporter_regression_test, vertices) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden( "io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params); @@ -355,8 +355,8 @@ TEST_F(obj_exporter_regression_test, non_uniform_scale) TEST_F(obj_exporter_regression_test, nurbs_as_nurbs) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; compare_obj_export_to_golden( @@ -366,8 +366,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_nurbs) TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; compare_obj_export_to_golden("io_tests/blend_geometry/nurbs_curves.blend", @@ -379,8 +379,8 @@ TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs) TEST_F(obj_exporter_regression_test, nurbs_as_mesh) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = false; compare_obj_export_to_golden( @@ -390,8 +390,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_mesh) TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_triangulated_mesh = true; compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend", @@ -403,8 +403,8 @@ TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) TEST_F(obj_exporter_regression_test, cube_normal_edit) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden("io_tests/blend_geometry/cube_normal_edit.blend", "io_tests/obj/cube_normal_edit.obj", @@ -436,6 +436,19 @@ TEST_F(obj_exporter_regression_test, cubes_positioned) _export.params); } +TEST_F(obj_exporter_regression_test, cubes_vertex_colors) +{ + OBJExportParamsDefault _export; + _export.params.export_colors = true; + _export.params.export_normals = false; + _export.params.export_uv = false; + _export.params.export_materials = false; + compare_obj_export_to_golden("io_tests/blend_geometry/cubes_vertex_colors.blend", + "io_tests/obj/cubes_vertex_colors.obj", + "", + _export.params); +} + TEST_F(obj_exporter_regression_test, cubes_with_textures_strip) { OBJExportParamsDefault _export; @@ -459,8 +472,8 @@ TEST_F(obj_exporter_regression_test, cubes_with_textures_relative) TEST_F(obj_exporter_regression_test, suzanne_all_data) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_smooth_groups = true; compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend", @@ -491,9 +504,10 @@ TEST_F(obj_exporter_regression_test, all_curves_as_nurbs) TEST_F(obj_exporter_regression_test, all_objects) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_smooth_groups = true; + _export.params.export_colors = true; compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend", "io_tests/obj/all_objects.obj", "io_tests/obj/all_objects.mtl", @@ -503,8 +517,8 @@ TEST_F(obj_exporter_regression_test, all_objects) TEST_F(obj_exporter_regression_test, all_objects_mat_groups) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_smooth_groups = true; _export.params.export_material_groups = true; compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend", diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh index ef27a65fb4b..7d3b41ed527 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh @@ -17,8 +17,8 @@ struct OBJExportParamsDefault { params.start_frame = 0; params.end_frame = 1; - params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD; - params.up_axis = OBJ_AXIS_Y_UP; + params.forward_axis = IO_AXIS_NEGATIVE_Z; + params.up_axis = IO_AXIS_Y; params.scaling_factor = 1.f; params.apply_modifiers = true; @@ -26,6 +26,7 @@ struct OBJExportParamsDefault { params.export_selected_objects = false; params.export_uv = true; params.export_normals = true; + params.export_colors = false; params.export_materials = true; params.path_mode = PATH_REFERENCE_AUTO; params.export_triangulated_mesh = false; 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 d7f4ce3d773..eeb81f5e23e 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -39,6 +39,7 @@ struct Expectation { float3 vert_first, vert_last; float3 normal_first; float2 uv_first; + float4 color_first = {-1, -1, -1, -1}; }; class obj_importer_test : public BlendfileLoadingBaseTest { @@ -55,8 +56,10 @@ class obj_importer_test : public BlendfileLoadingBaseTest { OBJImportParams params; params.clamp_size = 0; - params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD; - params.up_axis = OBJ_AXIS_Y_UP; + params.forward_axis = IO_AXIS_NEGATIVE_Z; + params.up_axis = IO_AXIS_Y; + params.validate_meshes = true; + params.import_vertex_groups = false; std::string obj_path = blender::tests::flags_test_asset_dir() + "/io_tests/obj/" + path; strncpy(params.filepath, obj_path.c_str(), FILE_MAX - 1); @@ -98,6 +101,15 @@ class obj_importer_test : public BlendfileLoadingBaseTest { CustomData_get_layer(&mesh->ldata, CD_MLOOPUV)); float2 uv_first = mloopuv ? float2(mloopuv->uv) : float2(0, 0); EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f); + if (exp.color_first.x >= 0) { + const float4 *colors = (const float4 *)(CustomData_get_layer(&mesh->vdata, + CD_PROP_COLOR)); + EXPECT_TRUE(colors != nullptr); + EXPECT_V4_NEAR(colors[0], exp.color_first, 0.0001f); + } + else { + EXPECT_FALSE(CustomData_has_layer(&mesh->vdata, CD_PROP_COLOR)); + } } if (object->type == OB_CURVES_LEGACY) { Curve *curve = static_cast<Curve *>(DEG_get_evaluated_object(depsgraph, object)->data); @@ -111,7 +123,7 @@ class obj_importer_test : public BlendfileLoadingBaseTest { int endpoint = (nurb->flagu & CU_NURB_ENDPOINT) ? 1 : 0; EXPECT_EQ(nurb->orderu, exp.mesh_totpoly_or_curve_order); EXPECT_EQ(endpoint, exp.mesh_totedge_or_curve_endp); - // Cyclic flag is not set by the importer yet + /* Cyclic flag is not set by the importer yet. */ // int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0; // EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic); } @@ -133,7 +145,7 @@ TEST_F(obj_importer_test, import_cube) { Expectation expect[] = { {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, - {"OBNew object", + {"OBcube", OB_MESH, 8, 12, @@ -168,7 +180,7 @@ TEST_F(obj_importer_test, import_nurbs) { Expectation expect[] = { {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, - {"OBNew object", + {"OBnurbs", OB_CURVES_LEGACY, 12, 0, @@ -184,7 +196,7 @@ TEST_F(obj_importer_test, import_nurbs_curves) { Expectation expect[] = { {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, - {"OBNew object", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)}, + {"OBnurbs_curves", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)}, {"OBNurbsCurveDiffWeights", OB_CURVES_LEGACY, 4, @@ -211,7 +223,7 @@ TEST_F(obj_importer_test, import_nurbs_cyclic) { Expectation expect[] = { {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, - {"OBNew object", + {"OBnurbs_cyclic", OB_CURVES_LEGACY, 31, 0, @@ -262,7 +274,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)}, - {"OBNew object", 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); } @@ -434,7 +446,17 @@ TEST_F(obj_importer_test, import_all_objects) float3(16, 1, -1), float3(14, 1, 1), float3(0, 0, 1)}, - {"OBVColCube", OB_MESH, 8, 13, 7, 26, float3(13, 1, -1), float3(11, 1, 1), float3(0, 0, 1)}, + {"OBVColCube", + OB_MESH, + 8, + 13, + 7, + 26, + float3(13, 1, -1), + float3(11, 1, 1), + float3(0, 0, 1), + float2(0, 0), + float4(0.0f, 0.002125f, 1.0f, 1.0f)}, {"OBUVCube", OB_MESH, 8, @@ -490,4 +512,103 @@ TEST_F(obj_importer_test, import_all_objects) import_and_check("all_objects.obj", expect, std::size(expect), 7); } +TEST_F(obj_importer_test, import_cubes_vertex_colors) +{ + Expectation expect[] = { + {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, + {"OBCubeVertexByte", + OB_MESH, + 8, + 12, + 6, + 24, + 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)}, + {"OBCubeVertexFloat", + OB_MESH, + 8, + 12, + 6, + 24, + 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)}, + {"OBCubeCornerByte", + OB_MESH, + 8, + 12, + 6, + 24, + 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)}, + {"OBCubeCornerFloat", + OB_MESH, + 8, + 12, + 6, + 24, + 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)}, + {"OBCubeMultiColorAttribs", + OB_MESH, + 8, + 12, + 6, + 24, + float3(-4.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)}, + {"OBCubeNoColors", + OB_MESH, + 8, + 12, + 6, + 24, + float3(-4.550208f, -1.0f, -1.918042f), + float3(-2.550208f, 1.0f, -3.918042f)}, + }; + import_and_check("cubes_vertex_colors.obj", expect, std::size(expect), 0); +} + +TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb) +{ + Expectation expect[] = {{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, + {"OBCubeXYZRGB", + OB_MESH, + 8, + 12, + 6, + 24, + float3(1, 1, -1), + float3(-1, -1, 1), + float3(0, 0, 0), + float2(0, 0), + float4(0.6038f, 0.3185f, 0.1329f, 1.0f)}, + {"OBCubeMRGB", + OB_MESH, + 8, + 12, + 6, + 24, + float3(4, 1, -1), + float3(2, -1, 1), + float3(0, 0, 0), + float2(0, 0), + float4(0.8714f, 0.6308f, 0.5271f, 1.0f)}}; + import_and_check("cubes_vertex_colors_mrgb.obj", expect, std::size(expect), 0); +} + } // namespace blender::io::obj diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 1989118bef9..451c921c4ef 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -472,7 +472,7 @@ typedef struct Library { ushort tag; char _pad_0[6]; - /* Temp data needed by read/write code, and liboverride recursive resync. */ + /** Temp data needed by read/write code, and lib-override recursive re-synchronized. */ int temp_index; /** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */ short versionfile, subversionfile; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index c1dfab8a041..e2b58cefef6 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -771,7 +771,7 @@ typedef enum eNlaStrip_Blend_Mode { NLASTRIP_MODE_COMBINE, } eNlaStrip_Blend_Mode; -/** NLA Strip Extrpolation Mode. */ +/** NLA Strip Extrapolation Mode. */ typedef enum eNlaStrip_Extrapolate_Mode { /* extend before first frame if no previous strips in track, * and always hold+extend last frame */ diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index f409d1c0442..f2cd49b6dea 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -468,6 +468,7 @@ typedef enum eBrushCurvesSculptTool { CURVES_SCULPT_TOOL_SNAKE_HOOK = 2, CURVES_SCULPT_TOOL_ADD = 3, CURVES_SCULPT_TOOL_GROW_SHRINK = 4, + CURVES_SCULPT_TOOL_SELECTION_PAINT = 5, } eBrushCurvesSculptTool; /** When #BRUSH_ACCUMULATE is used */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 24e77ecf87f..d13496b21f7 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -97,7 +97,7 @@ typedef struct BrushGpencilSettings { /** Simplify adaptive factor */ float simplify_f; - /** Mix colorfactor */ + /** Mix color-factor. */ float vertex_factor; int vertex_mode; diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index e79a53704c9..8ac899df701 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -20,8 +20,8 @@ extern "C" { * Mass-Spring Model to Describe Rigid Cloth Behavior by Xavier Provot. * * I've tried to keep similar, if not exact names for the variables as - * are presented in the paper. Where I've changed the concept slightly, - * as in stepsPerFrame compared to the time step in the paper, I've used + * are presented in the paper. Where I've changed the concept slightly, + * as in `stepsPerFrame` compared to the time step in the paper, I've used * variables with different names to minimize confusion. */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 6557f35970d..8e0ce68f71a 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -105,8 +105,10 @@ typedef struct bConstraintTarget { /* bConstraintTarget -> flag */ typedef enum eConstraintTargetFlag { - /** temporary target-struct that needs to be freed after use */ + /** Temporary target-struct that needs to be freed after use. */ CONSTRAINT_TAR_TEMP = (1 << 0), + /** Temporary target for the custom space reference. */ + CONSTRAINT_TAR_CUSTOM_SPACE = (1 << 1), } eConstraintTargetFlag; /* bConstraintTarget/bConstraintOb -> type */ @@ -247,10 +249,9 @@ typedef struct bArmatureConstraint { typedef struct bTrackToConstraint { struct Object *tar; /** - * I'll be using reserved1 and reserved2 as Track and Up flags, + * NOTE(@theeth): I'll be using reserved1 and reserved2 as Track and Up flags, * not sure if that's what they were intended for anyway. * Not sure either if it would create backward incompatibility if I were to rename them. - * - theeth */ int reserved1; int reserved2; diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h index 2388f04cc39..ed909c283c4 100644 --- a/source/blender/makesdna/DNA_curves_types.h +++ b/source/blender/makesdna/DNA_curves_types.h @@ -141,7 +141,12 @@ typedef struct Curves { * symmetrical geometry. */ char symmetry; - char _pad2[5]; + /** + * #eAttrDomain. The active selection mode domain. At most one selection mode can be active + * at a time. + */ + char selection_domain; + char _pad[4]; /** * Used as base mesh when curves represent e.g. hair or fur. This surface is used in edit modes. @@ -152,6 +157,13 @@ typedef struct Curves { */ struct Object *surface; + /** + * The name of the attribute on the surface #Mesh used to give meaning to the UV attachment + * coordinates stored on each curve. Expected to be a 2D vector attribute on the face corner + * domain. + */ + char *surface_uv_map; + /* Draw Cache. */ void *batch_cache; } Curves; @@ -159,6 +171,7 @@ typedef struct Curves { /** #Curves.flag */ enum { HA_DS_EXPAND = (1 << 0), + CV_SCULPT_SELECTION_ENABLED = (1 << 1), }; /** #Curves.symmetry */ diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index fe06e97946c..bc29de66cf9 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -81,7 +81,7 @@ typedef struct CustomData { } CustomData; /** #CustomData.type */ -typedef enum CustomDataType { +typedef enum eCustomDataType { /* Used by GLSL attributes in the cases when we need a delayed CD type * assignment (in the cases when we don't know in advance which layer * we are addressing). @@ -161,9 +161,9 @@ typedef enum CustomDataType { CD_HAIRLENGTH = 51, CD_NUMTYPES = 52, -} CustomDataType; +} eCustomDataType; -/* Bits for CustomDataMask */ +/* Bits for eCustomDataMask */ #define CD_MASK_MVERT (1 << CD_MVERT) // #define CD_MASK_MSTICKY (1 << CD_MSTICKY) /* DEPRECATED */ #define CD_MASK_MDEFORMVERT (1 << CD_MDEFORMVERT) diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index c20fb180fcd..56963bae3e1 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -1098,7 +1098,7 @@ typedef struct LineartGpencilModifierData { struct LineartCache *cache; /* Keep a pointer to the render buffer so we can call destroy from ModifierData. */ - struct LineartRenderBuffer *render_buffer_ptr; + struct LineartData *la_data_ptr; } LineartGpencilModifierData; diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h index 70ee7c99d01..ef35b72d2ab 100644 --- a/source/blender/makesdna/DNA_ipo_types.h +++ b/source/blender/makesdna/DNA_ipo_types.h @@ -338,7 +338,7 @@ typedef struct Ipo { #define CAM_STA 2 #define CAM_END 3 -/* yafray aperture & focal distance curves */ +/* YAFRAY aperture & focal distance curves. */ #define CAM_YF_APERT 4 #define CAM_YF_FDIST 5 diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h index 9202d7c2d51..f1bf0580b94 100644 --- a/source/blender/makesdna/DNA_light_types.h +++ b/source/blender/makesdna/DNA_light_types.h @@ -120,7 +120,7 @@ typedef struct Light { /* #define LA_NO_DIFF (1 << 11) */ /* not used anywhere */ /* #define LA_NO_SPEC (1 << 12) */ /* not used anywhere */ /* #define LA_SHAD_RAY (1 << 13) */ /* not used anywhere - cleaned */ -/* yafray: light shadowbuffer flag, softlight */ +/* YAFRAY: light shadow-buffer flag, soft-light. */ /* Since it is used with LOCAL light, can't use LA_SHAD */ /* #define LA_YF_SOFT (1 << 14) */ /* not used anymore */ /* #define LA_LAYER_SHADOW (1 << 15) */ /* not used anymore */ diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h index 5b3a23000d7..444a0e6f247 100644 --- a/source/blender/makesdna/DNA_lineart_types.h +++ b/source/blender/makesdna/DNA_lineart_types.h @@ -14,7 +14,7 @@ * Edge flags and usage flags are used by with scene/object/gpencil modifier bits, and those values * needs to stay consistent throughout. */ -/* These flags are used for 1 time calculation, not stroke selection afterwards. */ +/** These flags are used for 1 time calculation, not stroke selection afterwards. */ typedef enum eLineartMainFlags { LRT_INTERSECTION_AS_CONTOUR = (1 << 0), LRT_EVERYTHING_AS_CONTOUR = (1 << 1), @@ -48,9 +48,11 @@ typedef enum eLineartEdgeFlag { LRT_EDGE_FLAG_INTERSECTION = (1 << 4), LRT_EDGE_FLAG_LOOSE = (1 << 5), /* LRT_EDGE_FLAG_FOR_FUTURE = (1 << 7), */ - /* Limited to 8 bits for edge type flag, don't add anymore because BMEdge->head.eflag only has 8 - bits. So unless we changed this into a non-single-bit flag thing, we keep it this way. */ - /** Also used as discarded line mark. */ + /** + * It's a legacy limit of 8 bits for feature lines that come from original mesh edges. It should + * not be needed in current object loading scheme, but might still be relevant if we are to + * implement edit-mesh loading, so don't exceed 8 bits just yet. + */ LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 8), LRT_EDGE_FLAG_CLIPPED = (1 << 9), /** Limited to 16 bits for the entire thing. */ diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h index 8efcef5addf..df4e6f788ff 100644 --- a/source/blender/makesdna/DNA_mask_types.h +++ b/source/blender/makesdna/DNA_mask_types.h @@ -198,6 +198,7 @@ enum { /* SpaceClip->mask_draw_flag */ #define MASK_DRAWFLAG_SMOOTH (1 << 0) #define MASK_DRAWFLAG_OVERLAY (1 << 1) +#define MASK_DRAWFLAG_SPLINE (1 << 2) /* copy of eSpaceImage_UVDT */ /* SpaceClip->mask_draw_type */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index bd202a305ae..1a133127eaf 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -32,6 +32,7 @@ struct MVert; struct Material; struct Mesh; struct SubdivCCG; +struct SubsurfRuntimeData; # # @@ -83,7 +84,7 @@ typedef struct Mesh_Runtime { /** * Data used to efficiently draw the mesh in the viewport, especially useful when - * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.c`. + * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`. */ void *batch_cache; @@ -123,26 +124,18 @@ typedef struct Mesh_Runtime { /** * Settings for lazily evaluating the subdivision on the CPU if needed. These are - * set in the modifier when GPU subdivision can be performed. + * set in the modifier when GPU subdivision can be performed, and owned by the by + * the modifier in the object. */ - SessionUUID subsurf_session_uuid; - char subsurf_resolution; - char subsurf_do_loop_normals; - char subsurf_apply_render; - char subsurf_use_optimal_display; - - /* Cached from the draw code for stats display. */ - int subsurf_totvert; - int subsurf_totedge; - int subsurf_totpoly; - int subsurf_totloop; - char _pad2[2]; + struct SubsurfRuntimeData *subsurf_runtime_data; + void *_pad1; /** * Caches for lazily computed vertex and polygon normals. These are stored here rather than in * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a * const mesh is not thread-safe. */ + char _pad2[6]; char vert_normals_dirty; char poly_normals_dirty; float (*vert_normals)[3]; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 6e3ce7e98a8..f148116eba8 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -178,13 +178,6 @@ typedef enum { SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1, } eSubsurfBoundarySmooth; -typedef struct SubsurfRuntimeData { - /* Cached subdivision surface descriptor, with topology and settings. */ - struct Subdiv *subdiv; - char set_by_draw_code; - char _pad[7]; -} SubsurfRuntimeData; - typedef struct SubsurfModifierData { ModifierData modifier; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index a0738883bf3..25c8a1f1514 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -140,7 +140,7 @@ typedef struct bNodeSocket { short stack_type DNA_DEPRECATED; char display_shape; - /* #AttributeDomain used when the geometry nodes modifier creates an attribute for a group + /* #eAttrDomain used when the geometry nodes modifier creates an attribute for a group * output. */ char attribute_domain; /* Runtime-only cache of the number of input links, for multi-input sockets. */ @@ -1175,7 +1175,7 @@ typedef struct NodeDenoise { } NodeDenoise; typedef struct NodeMapRange { - /* CustomDataType */ + /* eCustomDataType */ uint8_t data_type; /* NodeMapRangeType. */ @@ -1185,14 +1185,14 @@ typedef struct NodeMapRange { } NodeMapRange; typedef struct NodeRandomValue { - /* CustomDataType. */ + /* eCustomDataType. */ uint8_t data_type; } NodeRandomValue; typedef struct NodeAccumulateField { - /* CustomDataType. */ + /* eCustomDataType. */ uint8_t data_type; - /* AttributeDomain. */ + /* eAttrDomain. */ uint8_t domain; } NodeAccumulateField; @@ -1362,9 +1362,9 @@ typedef struct NodeGeometryCurveSample { } NodeGeometryCurveSample; typedef struct NodeGeometryTransferAttribute { - /* CustomDataType. */ + /* eCustomDataType. */ int8_t data_type; - /* AttributeDomain. */ + /* eAttrDomain. */ int8_t domain; /* GeometryNodeAttributeTransferMode. */ uint8_t mode; @@ -1375,7 +1375,7 @@ typedef struct NodeGeometryRaycast { /* GeometryNodeRaycastMapMode. */ uint8_t mapping; - /* CustomDataType. */ + /* eCustomDataType. */ int8_t data_type; /* Deprecated input types in new Ray-cast node. Can be removed when legacy nodes are no longer @@ -1394,21 +1394,21 @@ typedef struct NodeGeometryMeshToPoints { } NodeGeometryMeshToPoints; typedef struct NodeGeometryAttributeCapture { - /* CustomDataType. */ + /* eCustomDataType. */ int8_t data_type; - /* AttributeDomain. */ + /* eAttrDomain. */ int8_t domain; } NodeGeometryAttributeCapture; typedef struct NodeGeometryStoreNamedAttribute { - /* CustomDataType. */ + /* eCustomDataType. */ int8_t data_type; - /* AttributeDomain. */ + /* eAttrDomain. */ int8_t domain; } NodeGeometryStoreNamedAttribute; typedef struct NodeGeometryInputNamedAttribute { - /* CustomDataType. */ + /* eCustomDataType. */ int8_t data_type; } NodeGeometryInputNamedAttribute; @@ -1424,19 +1424,19 @@ typedef struct NodeGeometryStringToCurves { } NodeGeometryStringToCurves; typedef struct NodeGeometryDeleteGeometry { - /* AttributeDomain. */ + /* eAttrDomain. */ int8_t domain; /* GeometryNodeDeleteGeometryMode. */ int8_t mode; } NodeGeometryDeleteGeometry; typedef struct NodeGeometryDuplicateElements { - /* AttributeDomain. */ + /* eAttrDomain. */ int8_t domain; } NodeGeometryDuplicateElements; typedef struct NodeGeometrySeparateGeometry { - /* AttributeDomain. */ + /* eAttrDomain. */ int8_t domain; } NodeGeometrySeparateGeometry; @@ -1446,7 +1446,7 @@ typedef struct NodeGeometryImageTexture { } NodeGeometryImageTexture; typedef struct NodeGeometryViewer { - /* CustomDataType. */ + /* eCustomDataType. */ int8_t data_type; } NodeGeometryViewer; @@ -1915,12 +1915,6 @@ typedef enum GeometryNodeBooleanOperation { GEO_NODE_BOOLEAN_DIFFERENCE = 2, } GeometryNodeBooleanOperation; -typedef enum GeometryNodeSplineType { - GEO_NODE_SPLINE_TYPE_BEZIER = 0, - GEO_NODE_SPLINE_TYPE_NURBS = 1, - GEO_NODE_SPLINE_TYPE_POLY = 2, -} GeometryNodeSplineType; - typedef enum GeometryNodeCurvePrimitiveCircleMode { GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS = 0, GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS = 1 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index f257833efe8..698fbe8ee8f 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -374,7 +374,7 @@ typedef struct Object { /** Dupliface scale. */ float instance_faces_scale; - /** Custom index, for renderpasses. */ + /** Custom index, for render-passes. */ short index; /** Current deformation group, NOTE: index starts at 1. */ unsigned short actdef DNA_DEPRECATED; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 1be27e0354c..1c62a550e60 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -991,6 +991,9 @@ typedef struct Sculpt { // float pivot[3]; XXX not used? int flags; + /* Transform tool. */ + int transform_mode; + int automasking_flags; /* Control tablet input */ @@ -1011,6 +1014,8 @@ typedef struct Sculpt { float constant_detail; float detail_percent; + char _pad[4]; + struct Object *gravity_object; } Sculpt; @@ -1490,18 +1495,19 @@ typedef struct ToolSettings { /* Transform */ char transform_pivot_point; char transform_flag; - /** Snap elements (per spacetype). */ + /** Snap elements (per spacetype), #eSnapMode. */ char snap_mode; char snap_node_mode; char snap_uv_mode; - /** Generic flags (per spacetype). */ + /** Generic flags (per spacetype), #eSnapFlag. */ char snap_flag; char snap_flag_node; char snap_flag_seq; char snap_uv_flag; - /** Default snap source. */ + /** Default snap source, #eSnapSourceSelect. */ + /* TODO(@gfxcoder): Rename `snap_target` to `snap_source_point`, because target is incorrect. */ char snap_target; - /** Snap mask for transform modes. */ + /** Snap mask for transform modes, #eSnapTransformMode. */ char snap_transform_mode_flag; char proportional_edit, prop_mode; @@ -2075,30 +2081,64 @@ enum { }; /** #ToolSettings.snap_flag */ -#define SCE_SNAP (1 << 0) -#define SCE_SNAP_ROTATE (1 << 1) -#define SCE_SNAP_PEEL_OBJECT (1 << 2) -#define SCE_SNAP_PROJECT (1 << 3) -#define SCE_SNAP_NO_SELF (1 << 4) -#define SCE_SNAP_ABS_GRID (1 << 5) -#define SCE_SNAP_BACKFACE_CULLING (1 << 6) - -/** #ToolSettings.snap_target */ -#define SCE_SNAP_TARGET_CLOSEST 0 -#define SCE_SNAP_TARGET_CENTER 1 -#define SCE_SNAP_TARGET_MEDIAN 2 -#define SCE_SNAP_TARGET_ACTIVE 3 +typedef enum eSnapFlag { + SCE_SNAP = (1 << 0), + SCE_SNAP_ROTATE = (1 << 1), + SCE_SNAP_PEEL_OBJECT = (1 << 2), + SCE_SNAP_PROJECT = (1 << 3), + SCE_SNAP_NO_SELF = (1 << 4), + SCE_SNAP_ABS_GRID = (1 << 5), + SCE_SNAP_BACKFACE_CULLING = (1 << 6), +} eSnapFlag; +/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */ +/* TODO: move this macro to a more general place. */ +#ifdef ENUM_OPERATORS +ENUM_OPERATORS(eSnapFlag, SCE_SNAP_BACKFACE_CULLING) +#endif + +/** #ToolSettings.snap_target and #TransSnap.source_select */ +typedef enum eSnapSourceSelect { + SCE_SNAP_SOURCE_CLOSEST = 0, + SCE_SNAP_SOURCE_CENTER = 1, + SCE_SNAP_SOURCE_MEDIAN = 2, + SCE_SNAP_SOURCE_ACTIVE = 3, +} eSnapSourceSelect; + +/** #TransSnap.target_select and #ToolSettings.snap_flag (SCE_SNAP_NO_SELF) */ +typedef enum eSnapTargetSelect { + SCE_SNAP_TARGET_ALL = 0, + SCE_SNAP_TARGET_NOT_SELECTED = 1, + SCE_SNAP_TARGET_NOT_ACTIVE = 2, + SCE_SNAP_TARGET_NOT_EDITED = 3, + SCE_SNAP_TARGET_ONLY_SELECTABLE = 4, +} eSnapTargetSelect; /** #ToolSettings.snap_mode */ -#define SCE_SNAP_MODE_VERTEX (1 << 0) -#define SCE_SNAP_MODE_EDGE (1 << 1) -#define SCE_SNAP_MODE_FACE (1 << 2) -#define SCE_SNAP_MODE_VOLUME (1 << 3) -#define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4) -#define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5) -#define SCE_SNAP_MODE_GEOM \ - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \ - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) +typedef enum eSnapMode { + SCE_SNAP_MODE_NONE = 0, + SCE_SNAP_MODE_VERTEX = (1 << 0), + SCE_SNAP_MODE_EDGE = (1 << 1), + SCE_SNAP_MODE_FACE = (1 << 2), /* TODO(@gfxcoder): Rename to `SCE_SNAP_MODE_FACE_RAYCAST` + when other face snapping methods are added. */ + SCE_SNAP_MODE_VOLUME = (1 << 3), + SCE_SNAP_MODE_EDGE_MIDPOINT = (1 << 4), + SCE_SNAP_MODE_EDGE_PERPENDICULAR = (1 << 5), + SCE_SNAP_MODE_GEOM = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT), + + /** #ToolSettings.snap_node_mode */ + SCE_SNAP_MODE_NODE_X = (1 << 0), + SCE_SNAP_MODE_NODE_Y = (1 << 1), + + /* #ToolSettings.snap_mode and #ToolSettings.snap_node_mode and #ToolSettings.snap_uv_mode */ + SCE_SNAP_MODE_INCREMENT = (1 << 6), + SCE_SNAP_MODE_GRID = (1 << 7), +} eSnapMode; +/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */ +/* TODO: move this macro to a more general place. */ +#ifdef ENUM_OPERATORS +ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_GRID) +#endif /** #SequencerToolSettings.snap_mode */ #define SEQ_SNAP_TO_STRIPS (1 << 0) @@ -2110,22 +2150,12 @@ enum { #define SEQ_SNAP_IGNORE_SOUND (1 << 1) #define SEQ_SNAP_CURRENT_FRAME_TO_STRIPS (1 << 2) -/** #ToolSettings.snap_node_mode */ -#define SCE_SNAP_MODE_NODE_X (1 << 0) -#define SCE_SNAP_MODE_NODE_Y (1 << 1) - -/** - * #ToolSettings.snap_mode and #ToolSettings.snap_node_mode - */ -#define SCE_SNAP_MODE_INCREMENT (1 << 6) -#define SCE_SNAP_MODE_GRID (1 << 7) - /** #ToolSettings.snap_transform_mode_flag */ -enum { +typedef enum eSnapTransformMode { SCE_SNAP_TRANSFORM_MODE_TRANSLATE = (1 << 0), SCE_SNAP_TRANSFORM_MODE_ROTATE = (1 << 1), SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2), -}; +} eSnapTransformMode; /** #ToolSettings.selectmode */ #define SCE_SELECT_VERTEX (1 << 0) /* for mesh */ @@ -2279,6 +2309,12 @@ typedef enum eSculptFlags { SCULPT_HIDE_FACE_SETS = (1 << 17), } eSculptFlags; +/* Sculpt.transform_mode */ +typedef enum eSculptTransformMode { + SCULPT_TRANSFORM_MODE_ALL_VERTICES = 0, + SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC = 1, +} eSculptTrasnformMode; + /** PaintModeSettings.mode */ typedef enum ePaintCanvasSource { /** Paint on the active node of the active material slot. */ diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index a54fd838bbe..db24a775edb 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -161,11 +161,11 @@ typedef struct Sequence { * Frames that use the first frame before data begins, * frames that use the last frame after data ends. */ - int startstill DNA_DEPRECATED, endstill DNA_DEPRECATED; + int startstill, endstill; /** Machine: the strip channel */ int machine; int _pad3; - /** Starting and ending points of the strip in the sequence. */ + /** Starting and ending points of the effect strip. Undefined for other strip types. */ int startdisp, enddisp; float sat; float mul; diff --git a/source/blender/makesdna/DNA_space_defaults.h b/source/blender/makesdna/DNA_space_defaults.h index e826cb4c2ef..6193c8c2ad1 100644 --- a/source/blender/makesdna/DNA_space_defaults.h +++ b/source/blender/makesdna/DNA_space_defaults.h @@ -15,9 +15,10 @@ #define _DNA_DEFAULT_MaskSpaceInfo \ { \ - .draw_flag = 0, \ + .draw_flag = MASK_DRAWFLAG_SPLINE, \ .draw_type = MASK_DT_OUTLINE, \ .overlay_mode = MASK_OVERLAY_ALPHACHANNEL, \ + .blend_factor = 0.7f, \ } #define _DNA_DEFAULT_SpaceClip \ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 85649a31ea4..2905ef06833 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -732,7 +732,8 @@ typedef struct MaskSpaceInfo { char draw_flag; char draw_type; char overlay_mode; - char _pad3[5]; + char _pad3[1]; + float blend_factor; } MaskSpaceInfo; /** #SpaceSeq.gizmo_flag */ @@ -1936,7 +1937,7 @@ typedef struct SpaceSpreadsheet { /* #GeometryComponentType. */ uint8_t geometry_component_type; - /* #AttributeDomain. */ + /* #eAttrDomain. */ uint8_t attribute_domain; /* eSpaceSpreadsheet_ObjectContext. */ uint8_t object_eval_state; @@ -2014,6 +2015,7 @@ typedef enum eSpreadsheetColumnValueType { SPREADSHEET_VALUE_TYPE_INSTANCES = 6, SPREADSHEET_VALUE_TYPE_STRING = 7, SPREADSHEET_VALUE_TYPE_BYTE_COLOR = 8, + SPREADSHEET_VALUE_TYPE_INT8 = 9, } eSpreadsheetColumnValueType; /** diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index b725939dbab..e32d9dbe300 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -397,8 +397,7 @@ typedef struct ColorMapping { /* return value */ #define TEX_INT 0 -#define TEX_RGB (1 << 0) -#define TEX_NOR (1 << 1) +#define TEX_RGB 1 /* pr_texture in material, world, light. */ #define TEX_PR_TEXTURE 0 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 275a89ec680..d00826208be 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -146,6 +146,7 @@ typedef struct ThemeUI { uiWidgetColors wcol_num, wcol_numslider, wcol_tab; uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip; uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu; + uiWidgetColors wcol_view_item; uiWidgetStateColors wcol_state; @@ -314,7 +315,7 @@ typedef struct ThemeSpace { char _pad5[3]; float dash_alpha; - /* syntax for textwindow and nodes */ + /* Syntax for text-window and nodes. */ unsigned char syntaxl[4], syntaxs[4]; /* in nodespace used for backdrop matte */ unsigned char syntaxb[4], syntaxn[4]; /* in nodespace used for color input */ unsigned char syntaxv[4], syntaxc[4]; /* in nodespace used for converter group */ @@ -858,7 +859,7 @@ typedef struct UserDef { float glalphaclip; - /** #eAutokey_Mode, autokeying mode. */ + /** #eAutokey_Mode, auto-keying mode. */ short autokey_mode; /** Flags for autokeying. */ short autokey_flag; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index cfd0c986df9..f7aaa1186db 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -463,14 +463,19 @@ typedef struct wmKeyMap { /** #wmKeyMap.flag */ enum { - KEYMAP_MODAL = (1 << 0), /* modal map, not using operatornames */ - KEYMAP_USER = (1 << 1), /* user keymap */ + /** Modal map, not using operator-names. */ + KEYMAP_MODAL = (1 << 0), + /** User key-map. */ + KEYMAP_USER = (1 << 1), KEYMAP_EXPANDED = (1 << 2), KEYMAP_CHILDREN_EXPANDED = (1 << 3), - KEYMAP_DIFF = (1 << 4), /* diff keymap for user preferences */ - KEYMAP_USER_MODIFIED = (1 << 5), /* keymap has user modifications */ + /** Diff key-map for user preferences. */ + KEYMAP_DIFF = (1 << 4), + /** Key-map has user modifications. */ + KEYMAP_USER_MODIFIED = (1 << 5), KEYMAP_UPDATE = (1 << 6), - KEYMAP_TOOL = (1 << 7), /* keymap for active tool system */ + /** key-map for active tool system. */ + KEYMAP_TOOL = (1 << 7), }; /** diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index e855395482e..67605201a9f 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -490,6 +490,18 @@ char *RNA_path_append( char *RNA_path_back(const char *path); #endif +/** + * Search for the start of the 'rna array index' part of the given `rna_path`. + * + * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first + * character in `rna_path` that is part of the array index for the given property. Return NULL if + * none can be found, e.g. because the property is not an RNA array. + * + * \param array_prop if not NULL, the PropertyRNA assumed to be the last one from the RNA path. + * Only used to ensure it is a valid array property. + */ +const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop); + /* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */ /** diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h index 127c8465243..61c5c1a6c72 100644 --- a/source/blender/makesrna/RNA_enum_items.h +++ b/source/blender/makesrna/RNA_enum_items.h @@ -21,7 +21,7 @@ DEF_ENUM(rna_enum_metaelem_type_items) DEF_ENUM(rna_enum_proportional_falloff_items) DEF_ENUM(rna_enum_proportional_falloff_curve_only_items) -DEF_ENUM(rna_enum_snap_target_items) +DEF_ENUM(rna_enum_snap_source_items) DEF_ENUM(rna_enum_snap_element_items) DEF_ENUM(rna_enum_snap_node_element_items) DEF_ENUM(rna_enum_curve_fit_method_items) @@ -108,7 +108,7 @@ DEF_ENUM(rna_enum_brush_gpencil_types_items) DEF_ENUM(rna_enum_brush_gpencil_vertex_types_items) DEF_ENUM(rna_enum_brush_gpencil_sculpt_types_items) DEF_ENUM(rna_enum_brush_gpencil_weight_types_items) -DEF_ENUM(rna_enum_brush_curves_sculpt_tool_items); +DEF_ENUM(rna_enum_brush_curves_sculpt_tool_items) DEF_ENUM(rna_enum_brush_image_tool_items) DEF_ENUM(rna_enum_axis_xy_items) @@ -147,10 +147,19 @@ DEF_ENUM(rna_enum_keymap_propvalue_items) DEF_ENUM(rna_enum_operator_context_items) DEF_ENUM(rna_enum_wm_report_items) +DEF_ENUM(rna_enum_wm_job_type_items) DEF_ENUM(rna_enum_property_type_items) DEF_ENUM(rna_enum_property_subtype_items) +DEF_ENUM(rna_enum_property_subtype_string_items) +DEF_ENUM(rna_enum_property_subtype_number_items) +DEF_ENUM(rna_enum_property_subtype_number_array_items) DEF_ENUM(rna_enum_property_unit_items) +DEF_ENUM(rna_enum_property_flag_items) +DEF_ENUM(rna_enum_property_flag_enum_items) +DEF_ENUM(rna_enum_property_override_flag_items) +DEF_ENUM(rna_enum_property_override_flag_collection_items) +DEF_ENUM(rna_enum_property_string_search_flag_items) DEF_ENUM(rna_enum_shading_type_items) @@ -201,6 +210,7 @@ DEF_ENUM(rna_enum_attribute_type_items) DEF_ENUM(rna_enum_color_attribute_type_items) DEF_ENUM(rna_enum_attribute_type_with_auto_items) DEF_ENUM(rna_enum_attribute_domain_items) +DEF_ENUM(rna_enum_attribute_curves_domain_items) DEF_ENUM(rna_enum_color_attribute_domain_items) DEF_ENUM(rna_enum_attribute_domain_without_corner_items) DEF_ENUM(rna_enum_attribute_domain_with_auto_items) @@ -218,6 +228,8 @@ DEF_ENUM(rna_enum_transform_orientation_items) DEF_ENUM(rna_enum_velocity_unit_items) +DEF_ENUM(rna_enum_curves_types) + /* Not available to RNA pre-processing (`makesrna`). * Defined in editors for example. */ #ifndef RNA_MAKESRNA diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 75b514cdb13..5346228050a 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -467,6 +467,27 @@ typedef struct EnumPropertyItem { const char *description; } EnumPropertyItem; +/** + * Heading for RNA enum items (shown in the UI). + * + * The description is currently only shown in the Python documentation. + * By convention the value should be a non-empty string or NULL when there is no description + * (never an empty string). + */ +#define RNA_ENUM_ITEM_HEADING(name, description) \ + { \ + 0, "", 0, name, description \ + } + +/** Separator for RNA enum items (shown in the UI). */ +#define RNA_ENUM_ITEM_SEPR \ + { \ + 0, "", 0, NULL, NULL \ + } + +/** Separator for RNA enum that begins a new column in menus (shown in the UI). */ +#define RNA_ENUM_ITEM_SEPR_COLUMN RNA_ENUM_ITEM_HEADING("", NULL) + /* extended versions with PropertyRNA argument */ typedef bool (*BooleanPropertyGetFunc)(struct PointerRNA *ptr, struct PropertyRNA *prop); typedef void (*BooleanPropertySetFunc)(struct PointerRNA *ptr, diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 9980545c19d..af8767a1220 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -237,7 +237,7 @@ if(WITH_IMAGE_HDR) endif() if(WITH_IMAGE_WEBP) - add_definitions(-DWITH_WEBP) + add_definitions(-DWITH_WEBP) endif() if(WITH_AUDASPACE) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 400944d60d4..b5354514205 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3030,7 +3030,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA } if (dparm->next) { - fprintf(f, "\t_data += %d;\n", rna_parameter_size(dparm->prop)); + fprintf(f, "\t_data += %d;\n", rna_parameter_size_pad(rna_parameter_size(dparm->prop))); } } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index b5cf8abaac6..8d2ee0ab534 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -33,41 +33,41 @@ const EnumPropertyItem rna_enum_id_type_items[] = { {ID_AC, "ACTION", ICON_ACTION, "Action", ""}, {ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""}, {ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""}, - {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""}, {ID_CF, "CACHEFILE", ICON_FILE, "Cache File", ""}, + {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""}, + {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""}, {ID_CU_LEGACY, "CURVE", ICON_CURVE_DATA, "Curve", ""}, + {ID_CV, "CURVES", ICON_CURVES_DATA, "Curves", ""}, {ID_VF, "FONT", ICON_FONT_DATA, "Font", ""}, {ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""}, - {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""}, {ID_IM, "IMAGE", ICON_IMAGE_DATA, "Image", ""}, {ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""}, - {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""}, + {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""}, {ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""}, + {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""}, + {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""}, {ID_LS, "LINESTYLE", ICON_LINE_DATA, "Line Style", ""}, - {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""}, {ID_MSK, "MASK", ICON_MOD_MASK, "Mask", ""}, {ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""}, - {ID_MB, "META", ICON_META_DATA, "Metaball", ""}, {ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""}, + {ID_MB, "META", ICON_META_DATA, "Metaball", ""}, {ID_MC, "MOVIECLIP", ICON_TRACKER, "Movie Clip", ""}, {ID_NT, "NODETREE", ICON_NODETREE, "Node Tree", ""}, {ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""}, {ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""}, {ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""}, {ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""}, - {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""}, + {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""}, {ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""}, {ID_SIM, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */ {ID_SO, "SOUND", ICON_SOUND, "Sound", ""}, {ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""}, {ID_TXT, "TEXT", ICON_TEXT, "Text", ""}, {ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""}, - {ID_CV, "CURVES", ICON_CURVES_DATA, "Hair Curves", ""}, - {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""}, {ID_VO, "VOLUME", ICON_VOLUME_DATA, "Volume", ""}, {ID_WM, "WINDOWMANAGER", ICON_WINDOW, "Window Manager", ""}, - {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""}, {ID_WS, "WORKSPACE", ICON_WORKSPACE, "Workspace", ""}, + {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 75579107465..a0b25cf60b2 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -5482,6 +5482,52 @@ static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path) return result; } +const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop) +{ + if (array_prop != NULL) { + if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + BLI_assert(array_prop->arraydimension == 0); + return NULL; + } + if (array_prop->arraydimension == 0) { + return NULL; + } + } + + /* 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. */ + off_t rna_path_len = (off_t)strlen(rna_path); + 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--) { + switch (rna_path[rna_path_len]) { + case '[': + if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') { + return &rna_path[rna_path_len]; + } + last_valid_index_token_start = &rna_path[rna_path_len]; + rna_path_len--; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + return last_valid_index_token_start; + } + } + return last_valid_index_token_start; +} + /* generic path search func * if its needed this could also reference the IDProperty direct */ typedef struct IDP_Chain { @@ -6062,7 +6108,7 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) } if ((index == -1) || (RNA_property_array_check(prop) == false)) { - ret = BLI_sprintfN("%s", data_path); + ret = BLI_strdup(data_path); } else { ret = BLI_sprintfN("%s[%d]", data_path, index); @@ -7084,7 +7130,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, /* allocate data */ for (parm = func->cont.properties.first; parm; parm = parm->next) { - alloc_size += rna_parameter_size(parm); + alloc_size += rna_parameter_size_pad(rna_parameter_size(parm)); if (parm->flag_parameter & PARM_OUTPUT) { parms->ret_count++; @@ -7160,7 +7206,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, } } - data = ((char *)data) + rna_parameter_size(parm); + data = ((char *)data) + rna_parameter_size_pad(size); } return parms; @@ -7184,7 +7230,7 @@ void RNA_parameter_list_free(ParameterList *parms) } } - tot += rna_parameter_size(parm); + tot += rna_parameter_size_pad(rna_parameter_size(parm)); } MEM_freeN(parms->data); @@ -7226,7 +7272,7 @@ void RNA_parameter_list_begin(ParameterList *parms, ParameterIterator *iter) void RNA_parameter_list_next(ParameterIterator *iter) { - iter->offset += iter->size; + iter->offset += rna_parameter_size_pad(iter->size); iter->parm = iter->parm->next; iter->valid = iter->parm != NULL; diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index a1266443631..ac90ec69784 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -168,6 +168,12 @@ static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerR WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } +static void rna_Action_fcurve_clear(bAction *act) +{ + BKE_action_fcurves_clear(act); + WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); +} + static TimeMarker *rna_Action_pose_markers_new(bAction *act, const char name[]) { TimeMarker *marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); @@ -788,6 +794,10 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "F-Curve to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + /* Action.fcurves.clear() */ + func = RNA_def_function(srna, "clear", "rna_Action_fcurve_clear"); + RNA_def_function_ui_description(func, "Remove all F-Curves"); } static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 36706c82366..5e17f22ecf5 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -106,6 +106,11 @@ const EnumPropertyItem rna_enum_color_attribute_domain_items[] = { {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""}, {0, NULL, 0, NULL, NULL}}; +const EnumPropertyItem rna_enum_attribute_curves_domain_items[] = { + {ATTR_DOMAIN_POINT, "POINT", 0, "Control Point", ""}, + {ATTR_DOMAIN_CURVE, "CURVE", 0, "Curve", ""}, + {0, NULL, 0, NULL, NULL}}; + #ifdef RNA_RUNTIME # include "BLI_math.h" @@ -124,7 +129,7 @@ static char *rna_Attribute_path(const PointerRNA *ptr) return BLI_sprintfN("attributes['%s']", layer->name); } -static StructRNA *srna_by_custom_data_layer_type(const CustomDataType type) +static StructRNA *srna_by_custom_data_layer_type(const eCustomDataType type) { switch (type) { case CD_PROP_FLOAT: @@ -158,13 +163,14 @@ static StructRNA *rna_Attribute_refine(PointerRNA *ptr) static void rna_Attribute_name_set(PointerRNA *ptr, const char *value) { - BKE_id_attribute_rename(ptr->owner_id, ptr->data, value, NULL); + const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data; + BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL); } static int rna_Attribute_name_editable(PointerRNA *ptr, const char **r_info) { CustomDataLayer *layer = ptr->data; - if (BKE_id_attribute_required(ptr->owner_id, layer)) { + if (BKE_id_attribute_required(ptr->owner_id, layer->name)) { *r_info = N_("Cannot modify name of required geometry attribute"); return false; } @@ -232,6 +238,12 @@ static int rna_Attribute_domain_get(PointerRNA *ptr) return BKE_id_attribute_domain(ptr->owner_id, ptr->data); } +static bool rna_Attribute_is_internal_get(PointerRNA *ptr) +{ + const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data; + return BKE_attribute_allow_procedural_access(layer->name); +} + static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { ID *id = ptr->owner_id; @@ -347,8 +359,8 @@ static PointerRNA rna_AttributeGroup_new( static void rna_AttributeGroup_remove(ID *id, ReportList *reports, PointerRNA *attribute_ptr) { - CustomDataLayer *layer = (CustomDataLayer *)attribute_ptr->data; - BKE_id_attribute_remove(id, layer, reports); + const CustomDataLayer *layer = (const CustomDataLayer *)attribute_ptr->data; + BKE_id_attribute_remove(id, layer->name, reports); RNA_POINTER_INVALIDATE(attribute_ptr); DEG_id_tag_update(id, ID_RECALC_GEOMETRY); @@ -367,7 +379,7 @@ static int rna_Attributes_noncolor_layer_skip(CollectionPropertyIterator *iter, /* Check valid domain here, too, keep in line with rna_AttributeGroup_color_length(). */ ID *id = iter->parent.owner_id; - AttributeDomain domain = BKE_id_attribute_domain(id, layer); + eAttrDomain domain = BKE_id_attribute_domain(id, layer); if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { return 1; } @@ -527,7 +539,7 @@ static void rna_AttributeGroup_active_color_set(PointerRNA *ptr, static int rna_AttributeGroup_active_color_index_get(PointerRNA *ptr) { - CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id); + const CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id); return BKE_id_attribute_to_index( ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); @@ -930,6 +942,12 @@ static void rna_def_attribute(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Domain", "Domain of the Attribute"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop = RNA_def_property(srna, "is_internal", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Attribute_is_internal_get", NULL); + RNA_def_property_ui_text( + prop, "Is Internal", "The attribute is meant for internal use by Blender"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* types */ rna_def_attribute_float(brna); rna_def_attribute_float_vector(brna); @@ -942,7 +960,7 @@ static void rna_def_attribute(BlenderRNA *brna) rna_def_attribute_int8(brna); } -/* Mesh/PointCloud/Hair.attributes */ +/* Mesh/PointCloud/Curves.attributes */ static void rna_def_attribute_group(BlenderRNA *brna) { StructRNA *srna; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 72f5bd1923c..80a61543b5a 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -98,14 +98,14 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_INFLATE, "INFLATE", ICON_BRUSH_INFLATE, "Inflate", ""}, {SCULPT_TOOL_BLOB, "BLOB", ICON_BRUSH_BLOB, "Blob", ""}, {SCULPT_TOOL_CREASE, "CREASE", ICON_BRUSH_CREASE, "Crease", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""}, {SCULPT_TOOL_FLATTEN, "FLATTEN", ICON_BRUSH_FLATTEN, "Flatten", ""}, {SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""}, {SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""}, {SCULPT_TOOL_MULTIPLANE_SCRAPE, "MULTIPLANE_SCRAPE", ICON_BRUSH_SCRAPE, "Multi-plane Scrape", ""}, {SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""}, {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""}, {SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""}, @@ -115,7 +115,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""}, {SCULPT_TOOL_SLIDE_RELAX, "TOPOLOGY", ICON_BRUSH_GRAB, "Slide Relax", ""}, {SCULPT_TOOL_BOUNDARY, "BOUNDARY", ICON_BRUSH_GRAB, "Boundary", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SCULPT_TOOL_CLOTH, "CLOTH", ICON_BRUSH_SCULPT_DRAW, "Cloth", ""}, {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""}, {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, @@ -243,14 +243,17 @@ const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[] = { {0, NULL, 0, NULL, NULL}, }; +/* clang-format off */ const EnumPropertyItem rna_enum_brush_curves_sculpt_tool_items[] = { - {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_NONE, "Comb Curves", ""}, - {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_NONE, "Delete Curves", ""}, - {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_NONE, "Curves Snake Hook", ""}, - {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_NONE, "Add Curves", ""}, - {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_NONE, "Grow / Shrink Curves", ""}, + {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_BRUSH_CURVES_COMB, "Comb Curves", ""}, + {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_BRUSH_CURVES_DELETE, "Delete Curves", ""}, + {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_CURVES_SNAKE_HOOK, "Curves Snake Hook", ""}, + {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_BRUSH_CURVES_ADD, "Add Curves", ""}, + {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_BRUSH_CURVES_GROW_SHRINK, "Grow / Shrink Curves", ""}, + {CURVES_SCULPT_TOOL_SELECTION_PAINT, "SELECTION_PAINT", ICON_BRUSH_PAINT_SELECT, "Paint Selection", ""}, {0, NULL, 0, NULL, NULL}, }; +/* clang-format on */ #ifndef RNA_RUNTIME static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = { @@ -885,6 +888,7 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, case PAINT_MODE_SCULPT_CURVES: switch (me->curves_sculpt_tool) { case CURVES_SCULPT_TOOL_GROW_SHRINK: + case CURVES_SCULPT_TOOL_SELECTION_PAINT: return prop_direction_items; default: return DummyRNA_DEFAULT_items; @@ -2002,7 +2006,7 @@ static void rna_def_brush(BlenderRNA *brna) static const EnumPropertyItem prop_blend_items[] = { {IMB_BLEND_MIX, "MIX", 0, "Mix", "Use Mix blending mode while painting"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use Darken blending mode while painting"}, {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use Multiply blending mode while painting"}, {IMB_BLEND_COLORBURN, @@ -2015,7 +2019,7 @@ static void rna_def_brush(BlenderRNA *brna) 0, "Linear Burn", "Use Linear Burn blending mode while painting"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use Lighten blending mode while painting"}, {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use Screen blending mode while painting"}, {IMB_BLEND_COLORDODGE, @@ -2024,7 +2028,7 @@ static void rna_def_brush(BlenderRNA *brna) "Color Dodge", "Use Color Dodge blending mode while painting"}, {IMB_BLEND_ADD, "ADD", 0, "Add", "Use Add blending mode while painting"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use Overlay blending mode while painting"}, {IMB_BLEND_SOFTLIGHT, "SOFTLIGHT", @@ -2051,7 +2055,7 @@ static void rna_def_brush(BlenderRNA *brna) 0, "Pin Light", "Use Pin Light blending mode while painting"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {IMB_BLEND_DIFFERENCE, "DIFFERENCE", 0, @@ -2063,7 +2067,7 @@ static void rna_def_brush(BlenderRNA *brna) "Exclusion", "Use Exclusion blending mode while painting"}, {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use Subtract blending mode while painting"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use Hue blending mode while painting"}, {IMB_BLEND_SATURATION, "SATURATION", @@ -2072,7 +2076,7 @@ static void rna_def_brush(BlenderRNA *brna) "Use Saturation blending mode while painting"}, {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use Color blending mode while painting"}, {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Value", "Use Value blending mode while painting"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"}, {IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"}, {0, NULL, 0, NULL, NULL}, diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index dcf0647392e..9628c6b2d65 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -125,6 +125,24 @@ static char *rna_Camera_background_image_path(const PointerRNA *ptr) return NULL; } +char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const PointerRNA *ptr) +{ + const char *user = ptr->data; + Camera *camera = (Camera *)ptr->owner_id; + + int bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, iuser)); + if (bgpic_index >= 0) { + return BLI_sprintfN("background_images[%d].image_user", bgpic_index); + } + + bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, cuser)); + if (bgpic_index >= 0) { + return BLI_sprintfN("background_images[%d].clip_user", bgpic_index); + } + + return NULL; +} + static bool rna_Camera_background_images_override_apply(Main *bmain, PointerRNA *ptr_dst, PointerRNA *ptr_src, @@ -272,6 +290,7 @@ static void rna_def_camera_background_image(BlenderRNA *brna) prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "ImageUser"); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); RNA_def_property_ui_text( prop, diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 8829c655030..1420ef36493 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -29,11 +29,12 @@ /* please keep the names in sync with constraint.c */ const EnumPropertyItem rna_enum_constraint_type_items[] = { - {0, "", 0, N_("Motion Tracking"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Motion Tracking"), NULL), {CONSTRAINT_TYPE_CAMERASOLVER, "CAMERA_SOLVER", ICON_CON_CAMERASOLVER, "Camera Solver", ""}, {CONSTRAINT_TYPE_FOLLOWTRACK, "FOLLOW_TRACK", ICON_CON_FOLLOWTRACK, "Follow Track", ""}, {CONSTRAINT_TYPE_OBJECTSOLVER, "OBJECT_SOLVER", ICON_CON_OBJECTSOLVER, "Object Solver", ""}, - {0, "", 0, N_("Transform"), ""}, + + RNA_ENUM_ITEM_HEADING(N_("Transform"), NULL), {CONSTRAINT_TYPE_LOCLIKE, "COPY_LOCATION", ICON_CON_LOCLIKE, @@ -91,7 +92,8 @@ const EnumPropertyItem rna_enum_constraint_type_items[] = { ICON_CON_TRANSFORM_CACHE, "Transform Cache", "Look up the transformation matrix from an external file"}, - {0, "", 0, N_("Tracking"), ""}, + + RNA_ENUM_ITEM_HEADING(N_("Tracking"), NULL), {CONSTRAINT_TYPE_CLAMPTO, "CLAMP_TO", ICON_CON_CLAMPTO, @@ -127,7 +129,8 @@ const EnumPropertyItem rna_enum_constraint_type_items[] = { ICON_CON_TRACKTO, "Track To", "Legacy tracking constraint prone to twisting artifacts"}, - {0, "", 0, N_("Relationship"), ""}, + + RNA_ENUM_ITEM_HEADING(N_("Relationship"), NULL), {CONSTRAINT_TYPE_ACTION, "ACTION", ICON_ACTION, @@ -192,7 +195,7 @@ static const EnumPropertyItem target_space_pchan_items[] = { "Custom Space", "The transformation of the target is evaluated relative to a custom object/bone/vertex " "group"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {CONSTRAINT_SPACE_POSE, "POSE", 0, @@ -233,7 +236,7 @@ static const EnumPropertyItem owner_space_pchan_items[] = { 0, "Custom Space", "The constraint is applied in local space of a custom object/bone/vertex group"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {CONSTRAINT_SPACE_POSE, "POSE", 0, @@ -595,22 +598,17 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE bool *UNUSED(r_free)) { bConstraint *con = (bConstraint *)ptr->data; - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if (ct->tar && ct->tar->type == OB_ARMATURE) { break; } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 1); - } + BKE_constraint_targets_flush(con, &targets, 1); if (ct) { return target_space_pchan_items; @@ -1623,7 +1621,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna) 0, "Replace", "Replace the original transformation with copied"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {TRANSLIKE_MIX_BEFORE_FULL, "BEFORE_FULL", 0, @@ -1644,7 +1642,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna) "Before Original (Split Channels)", "Apply copied transformation before original, handling location, rotation and scale " "separately, similar to a sequence of three Copy constraints"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {TRANSLIKE_MIX_AFTER_FULL, "AFTER_FULL", 0, @@ -1782,7 +1780,7 @@ static void rna_def_constraint_action(BlenderRNA *brna) "Before Original (Split Channels)", "Apply the action channels before the original transformation, handling location, rotation " "and scale separately"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {ACTCON_MIX_AFTER_FULL, "AFTER_FULL", 0, diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 49b78e90024..fff3f479a3f 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -66,8 +66,8 @@ const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = { * Changes here will likely apply there too. */ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = { - /* interpolation */ - {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"}, + /* Interpolation. */ + RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"), {BEZT_IPO_CONST, "CONSTANT", ICON_IPO_CONSTANT, @@ -84,13 +84,10 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = { "Bezier", "Smooth interpolation between A and B, with some control over curve shape"}, - /* easing */ - {0, - "", - 0, - N_("Easing (by strength)"), - "Predefined inertial transitions, useful for motion graphics (from least to most " - "''dramatic'')"}, + /* Easing. */ + RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"), + "Predefined inertial transitions, useful for motion graphics " + "(from least to most \"dramatic\")"), {BEZT_IPO_SINE, "SINE", ICON_IPO_SINE, @@ -107,7 +104,7 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = { "Circular", "Circular easing (strongest and most dynamic)"}, - {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"}, + RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"), {BEZT_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"}, {BEZT_IPO_BOUNCE, "BOUNCE", diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c index 7cf34db4cf4..bc3e5203ed0 100644 --- a/source/blender/makesrna/intern/rna_curves.c +++ b/source/blender/makesrna/intern/rna_curves.c @@ -18,6 +18,14 @@ #include "WM_types.h" +const EnumPropertyItem rna_enum_curves_types[] = { + {CURVE_TYPE_CATMULL_ROM, "CATMULL_ROM", 0, "Catmull Rom", ""}, + {CURVE_TYPE_POLY, "POLY", 0, "Poly", ""}, + {CURVE_TYPE_BEZIER, "BEZIER", 0, "Bezier", ""}, + {CURVE_TYPE_NURBS, "NURBS", 0, "NURBS", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "BLI_math_vector.h" @@ -292,6 +300,14 @@ static void rna_def_curves(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Surface", "Mesh object that the curves can be attached to"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + prop = RNA_def_property(srna, "surface_uv_map", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "surface_uv_map"); + RNA_def_property_ui_text(prop, + "Surface UV Map", + "The name of the attribute on the surface mesh used to define the " + "attachment of each curve"); + RNA_def_property_update(prop, 0, "rna_Curves_update_draw"); + /* Symmetry. */ prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_X); @@ -308,6 +324,18 @@ static void rna_def_curves(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Z", "Enable symmetry in the Z axis"); RNA_def_property_update(prop, 0, "rna_Curves_update_draw"); + prop = RNA_def_property(srna, "selection_domain", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_attribute_curves_domain_items); + RNA_def_property_ui_text(prop, "Selection Domain", ""); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Curves_update_data"); + + prop = RNA_def_property(srna, "use_sculpt_selection", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CV_SCULPT_SELECTION_ENABLED); + RNA_def_property_ui_text(prop, "Use Sculpt Selection", ""); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Curves_update_draw"); + /* attributes */ rna_def_attributes_common(srna); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index dfb551fcb05..a747a5d11d8 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -4421,6 +4421,16 @@ int rna_parameter_size(PropertyRNA *parm) return sizeof(void *); } +int rna_parameter_size_pad(const int size) +{ + /* Pad parameters in memory so the next parameter is properly aligned. + * This silences warnings in ubsan. More complicated logic to pack parameters + * more tightly in memory is unlikely to improve performance, and aligning + * to the requirements for pointers is enough for all data types we use. */ + const int alignment = sizeof(void *); + return (size + alignment - 1) & ~(alignment - 1); +} + /* Dynamic Enums */ void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item) @@ -4448,7 +4458,7 @@ void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropert void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem) { - static const EnumPropertyItem sepr = {0, "", 0, NULL, NULL}; + static const EnumPropertyItem sepr = RNA_ENUM_ITEM_SEPR; RNA_enum_item_add(items, totitem, &sepr); } diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index e14a291dd01..ac8aebd2fdd 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1776,12 +1776,12 @@ static void rna_def_drivertarget(BlenderRNA *brna) {DTAR_TRANSCHAN_LOCX, "LOC_X", 0, "X Location", ""}, {DTAR_TRANSCHAN_LOCY, "LOC_Y", 0, "Y Location", ""}, {DTAR_TRANSCHAN_LOCZ, "LOC_Z", 0, "Z Location", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {DTAR_TRANSCHAN_ROTX, "ROT_X", 0, "X Rotation", ""}, {DTAR_TRANSCHAN_ROTY, "ROT_Y", 0, "Y Rotation", ""}, {DTAR_TRANSCHAN_ROTZ, "ROT_Z", 0, "Z Rotation", ""}, {DTAR_TRANSCHAN_ROTW, "ROT_W", 0, "W Rotation", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {DTAR_TRANSCHAN_SCALEX, "SCALE_X", 0, "X Scale", ""}, {DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""}, {DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""}, diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 8bbc33d2381..47bed955b54 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -46,7 +46,7 @@ #include "WM_types.h" const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { - {0, "", 0, N_("Modify"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Modify"), NULL), {eGpencilModifierType_Texture, "GP_TEXTURE", ICON_MOD_UVPROJECT, @@ -63,7 +63,8 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Proximity", "Generate Vertex Weights base on distance to object"}, - {0, "", 0, N_("Generate"), ""}, + + RNA_ENUM_ITEM_HEADING(N_("Generate"), NULL), {eGpencilModifierType_Array, "GP_ARRAY", ICON_MOD_ARRAY, @@ -114,7 +115,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { ICON_MOD_SUBSURF, "Subdivide", "Subdivide stroke adding more control points"}, - {0, "", 0, N_("Deform"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Deform"), NULL), {eGpencilModifierType_Armature, "GP_ARMATURE", ICON_MOD_ARMATURE, @@ -147,7 +148,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { ICON_MOD_THICKNESS, "Thickness", "Change stroke thickness"}, - {0, "", 0, N_("Color"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Color"), NULL), {eGpencilModifierType_Color, "GP_COLOR", ICON_MOD_HUE_SATURATION, @@ -1278,8 +1279,8 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna) /* Sample */ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "length"); - RNA_def_property_range(prop, 0, FLT_MAX); - RNA_def_property_ui_range(prop, 0, 1.0, 0.01, 3); + RNA_def_property_range(prop, 0.005, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 1.0, 0.05, 3); RNA_def_property_ui_text(prop, "Length", "Length of each segment"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 269ebe1581f..39f5b6e0e9f 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -182,12 +182,12 @@ static char *rna_ImageUser_path(const PointerRNA *ptr) switch (GS(ptr->owner_id->name)) { case ID_OB: - case ID_TE: { + case ID_TE: return BLI_strdup("image_user"); - } - case ID_NT: { + case ID_NT: return rna_Node_ImageUser_path(ptr); - } + case ID_CA: + return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr); default: break; } @@ -257,6 +257,51 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value) } } +static void rna_UDIMTile_size_get(PointerRNA *ptr, int *values) +{ + ImageTile *tile = (ImageTile *)ptr->data; + Image *image = (Image *)ptr->owner_id; + + ImageUser image_user; + BKE_imageuser_default(&image_user); + image_user.tile = tile->tile_number; + + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock); + if (ibuf) { + values[0] = ibuf->x; + values[1] = ibuf->y; + } + else { + values[0] = 0; + values[1] = 0; + } + + BKE_image_release_ibuf(image, ibuf, lock); +} + +static int rna_UDIMTile_channels_get(PointerRNA *ptr) +{ + ImageTile *tile = (ImageTile *)ptr->data; + Image *image = (Image *)ptr->owner_id; + + ImageUser image_user; + BKE_imageuser_default(&image_user); + image_user.tile = tile->tile_number; + + int channels = 0; + + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock); + if (ibuf) { + channels = ibuf->channels; + } + + BKE_image_release_ibuf(image, ibuf, lock); + + return channels; +} + static void rna_UDIMTile_label_get(PointerRNA *ptr, char *value) { ImageTile *tile = (ImageTile *)ptr->data; @@ -656,6 +701,8 @@ static void rna_def_imageuser(BlenderRNA *brna) "Parameters defining how an Image data-block is used by another data-block"); RNA_def_struct_path_func(srna, "rna_ImageUser_path"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use_auto_refresh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANIM_ALWAYS); RNA_def_property_ui_text(prop, "Auto Refresh", "Always refresh image on frame changes"); @@ -717,6 +764,8 @@ static void rna_def_imageuser(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "tile"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Tile", "Tile in tiled image"); + + RNA_define_lib_overridable(false); } /* image.packed_files */ @@ -826,6 +875,26 @@ static void rna_def_udim_tile(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Number", "Number of the position that this tile covers"); RNA_def_property_int_funcs(prop, NULL, "rna_UDIMTile_tile_number_set", NULL); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); + + prop = RNA_def_int_vector( + srna, + "size", + 2, + NULL, + 0, + 0, + "Size", + "Width and height of the tile buffer in pixels, zero when image data can't be loaded", + 0, + 0); + RNA_def_property_subtype(prop, PROP_PIXEL); + RNA_def_property_int_funcs(prop, "rna_UDIMTile_size_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, "rna_UDIMTile_channels_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Channels", "Number of channels in the tile pixels buffer"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); } static void rna_def_udim_tiles(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 46bb0df5c11..be1e344d73f 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -164,7 +164,10 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he { if (!BKE_image_scale(image, width, height)) { BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2); + return; } + BKE_image_partial_update_mark_full_update(image); + WM_main_add_notifier(NC_IMAGE | NA_EDITED, image); } static int rna_Image_gl_load( diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 058c63f640a..6ca8e668fa0 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -404,6 +404,7 @@ bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct Poi char *rna_TextureSlot_path(const struct PointerRNA *ptr); char *rna_Node_ImageUser_path(const struct PointerRNA *ptr); +char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const struct PointerRNA *ptr); /* Set U.is_dirty and redraw. */ @@ -634,6 +635,7 @@ PointerRNA rna_pointer_inherit_refine(struct PointerRNA *ptr, struct StructRNA * /* Functions */ int rna_parameter_size(struct PropertyRNA *parm); +int rna_parameter_size_pad(const int size); /* XXX, these should not need to be defined here~! */ struct MTex *rna_mtex_texture_slots_add(struct ID *self, diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index 4f88959b5ba..a5b06cabade 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -532,7 +532,7 @@ struct StructRNA { /* property to iterate over properties */ PropertyRNA *iteratorproperty; - /* struct this is derivedfrom */ + /** Struct this is derived from. */ struct StructRNA *base; /* only use for nested structs, where both the parent and child access diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index 2f6fb30dc49..b16d127a643 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -26,6 +26,14 @@ #include "rna_internal.h" +const EnumPropertyItem rna_enum_keyblock_type_items[] = { + {KEY_LINEAR, "KEY_LINEAR", 0, "Linear", ""}, + {KEY_CARDINAL, "KEY_CARDINAL", 0, "Cardinal", ""}, + {KEY_CATMULL_ROM, "KEY_CATMULL_ROM", 0, "Catmull-Rom", ""}, + {KEY_BSPLINE, "KEY_BSPLINE", 0, "BSpline", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include <stddef.h> @@ -789,14 +797,6 @@ static char *rna_ShapeKeyPoint_path(const PointerRNA *ptr) #else -const EnumPropertyItem rna_enum_keyblock_type_items[] = { - {KEY_LINEAR, "KEY_LINEAR", 0, "Linear", ""}, - {KEY_CARDINAL, "KEY_CARDINAL", 0, "Cardinal", ""}, - {KEY_CATMULL_ROM, "KEY_CATMULL_ROM", 0, "Catmull-Rom", ""}, - {KEY_BSPLINE, "KEY_BSPLINE", 0, "BSpline", ""}, - {0, NULL, 0, NULL, NULL}, -}; - static const float tilt_limit = DEG2RADF(21600.0f); static void rna_def_keydata(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 8c9c66bffcf..6ab9d3a46ad 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -339,6 +339,7 @@ static void rna_LayerCollection_update(Main *UNUSED(bmain), Scene *UNUSED(scene) DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + WM_main_add_notifier(NC_IMAGE | ND_LAYER_CONTENT, NULL); } static bool rna_LayerCollection_has_objects(LayerCollection *lc) diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 1de144d81ef..4fb7495bac8 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -25,24 +25,24 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { {MA_RAMP_BLEND, "MIX", 0, "Mix", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MA_RAMP_DARK, "DARKEN", 0, "Darken", ""}, {MA_RAMP_MULT, "MULTIPLY", 0, "Multiply", ""}, {MA_RAMP_BURN, "BURN", 0, "Color Burn", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MA_RAMP_LIGHT, "LIGHTEN", 0, "Lighten", ""}, {MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""}, {MA_RAMP_DODGE, "DODGE", 0, "Color Dodge", ""}, {MA_RAMP_ADD, "ADD", 0, "Add", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""}, {MA_RAMP_SOFT, "SOFT_LIGHT", 0, "Soft Light", ""}, {MA_RAMP_LINEAR, "LINEAR_LIGHT", 0, "Linear Light", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MA_RAMP_DIFF, "DIFFERENCE", 0, "Difference", ""}, {MA_RAMP_SUB, "SUBTRACT", 0, "Subtract", ""}, {MA_RAMP_DIV, "DIVIDE", 0, "Divide", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MA_RAMP_HUE, "HUE", 0, "Hue", ""}, {MA_RAMP_SAT, "SATURATION", 0, "Saturation", ""}, {MA_RAMP_COLOR, "COLOR", 0, "Color", ""}, diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index c71ba55d6a3..5cb07916a3c 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -303,6 +303,13 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr) rna_Mesh_update_draw(bmain, scene, ptr); } +static void rna_Mesh_update_positions_tag(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Mesh *mesh = (Mesh *)ptr->data; + BKE_mesh_tag_coords_changed(mesh); + rna_Mesh_update_data_legacy_deg_tag_all(bmain, scene, ptr); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1110,7 +1117,7 @@ static int rna_MeshPoly_vertices_get_length(const PointerRNA *ptr, { const MPoly *mp = (MPoly *)ptr->data; /* NOTE: raw access uses dummy item, this _could_ crash, - * watch out for this, mface uses it but it can't work here. */ + * watch out for this, #MFace uses it but it can't work here. */ return (length[0] = mp->totloop); } @@ -1743,7 +1750,7 @@ static void rna_def_mvert(BlenderRNA *brna) prop = RNA_def_property(srna, "co", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_ui_text(prop, "Location", ""); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_positions_tag"); prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION); RNA_def_property_array(prop, 3); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 992e306b2bb..4810784b3f7 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -47,7 +47,7 @@ #include "MOD_nodes.h" const EnumPropertyItem rna_enum_object_modifier_type_items[] = { - {0, "", 0, N_("Modify"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Modify"), NULL), {eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, @@ -99,7 +99,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Proximity", "Set the vertex group weights based on the distance to another target object"}, - {0, "", 0, N_("Generate"), ""}, + + RNA_ENUM_ITEM_HEADING(N_("Generate"), NULL), {eModifierType_Array, "ARRAY", ICON_MOD_ARRAY, @@ -193,7 +194,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_MOD_WIREFRAME, "Wireframe", "Convert faces into thickened edges"}, - {0, "", 0, N_("Deform"), ""}, + + RNA_ENUM_ITEM_HEADING(N_("Deform"), NULL), {eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, @@ -272,7 +274,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_VOLUME_DATA, "Volume Displace", "Deform volume based on noise or other vector fields"}, /* TODO: Use correct icon. */ - {0, "", 0, N_("Physics"), ""}, + + RNA_ENUM_ITEM_HEADING(N_("Physics"), NULL), {eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""}, {eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""}, {eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""}, @@ -1366,10 +1369,9 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf( Object *ob_src = dtmd->ob_source; if (ob_src) { - AttributeDomain domain = STREQ(RNA_property_identifier(prop), - "layers_vcol_vert_select_src") ? - ATTR_DOMAIN_POINT : - ATTR_DOMAIN_CORNER; + eAttrDomain domain = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_src") ? + ATTR_DOMAIN_POINT : + ATTR_DOMAIN_CORNER; Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); @@ -1389,7 +1391,7 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf( cdata = &me_eval->ldata; } - CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR}; + eCustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR}; int idx = 0; for (int i = 0; i < 2; i++) { @@ -1489,7 +1491,7 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf( Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */ if (ob_dst && ob_dst->data) { - CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR}; + eCustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR}; Mesh *me_dst = ob_dst->data; CustomData *cdata = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ? @@ -4991,7 +4993,7 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna), 0, "Object", "Use local generated coordinates of another object"}, - {MOD_DISP_MAP_UV, "UV", 0, "UV", "Use coordinates from an UV layer"}, + {MOD_DISP_MAP_UV, "UV", 0, "UV", "Use coordinates from a UV layer"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index e9b49dbe7d1..b5302eca1bf 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -118,6 +118,22 @@ static PointerRNA rna_MovieClip_metadata_get(MovieClip *clip) return ptr; } +static char *rna_MovieClipUser_path(const PointerRNA *ptr) +{ + if (ptr->owner_id) { + /* MovieClipUser *mc_user = ptr->data; */ + + switch (GS(ptr->owner_id->name)) { + case ID_CA: + return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr); + default: + break; + } + } + + return BLI_strdup(""); +} + #else static void rna_def_movieclip_proxy(BlenderRNA *brna) @@ -244,7 +260,7 @@ static void rna_def_movieclip_proxy(BlenderRNA *brna) RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClip_reload_update"); } -static void rna_def_moviecliUser(BlenderRNA *brna) +static void rna_def_movieclipUser(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -263,6 +279,9 @@ static void rna_def_moviecliUser(BlenderRNA *brna) srna, "Movie Clip User", "Parameters defining how a MovieClip data-block is used by another data-block"); + RNA_def_struct_path_func(srna, "rna_MovieClipUser_path"); + + RNA_define_lib_overridable(true); prop = RNA_def_property(srna, "frame_current", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "framenr"); @@ -286,6 +305,8 @@ static void rna_def_moviecliUser(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Render Undistorted", "Render preview using undistorted proxy"); RNA_def_property_update( prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClipUser_proxy_render_settings_update"); + + RNA_define_lib_overridable(false); } static void rna_def_movieClipScopes(BlenderRNA *brna) @@ -435,7 +456,7 @@ void RNA_def_movieclip(BlenderRNA *brna) { rna_def_movieclip(brna); rna_def_movieclip_proxy(brna); - rna_def_moviecliUser(brna); + rna_def_movieclipUser(brna); rna_def_movieClipScopes(brna); } diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 8aa87c1bcaa..978a94ca7b0 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -23,6 +23,49 @@ #include "WM_api.h" #include "WM_types.h" +/* enum defines exported for rna_animation.c */ +const EnumPropertyItem rna_enum_nla_mode_blend_items[] = { + {NLASTRIP_MODE_REPLACE, + "REPLACE", + 0, + "Replace", + "The strip values replace the accumulated results by amount specified by influence"}, + {NLASTRIP_MODE_COMBINE, + "COMBINE", + 0, + "Combine", + "The strip values are combined with accumulated results by appropriately using addition, " + "multiplication, or quaternion math, based on channel type"}, + RNA_ENUM_ITEM_SEPR, + {NLASTRIP_MODE_ADD, + "ADD", + 0, + "Add", + "Weighted result of strip is added to the accumulated results"}, + {NLASTRIP_MODE_SUBTRACT, + "SUBTRACT", + 0, + "Subtract", + "Weighted result of strip is removed from the accumulated results"}, + {NLASTRIP_MODE_MULTIPLY, + "MULTIPLY", + 0, + "Multiply", + "Weighted result of strip is multiplied with the accumulated results"}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_nla_mode_extend_items[] = { + {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"}, + {NLASTRIP_EXTEND_HOLD, + "HOLD", + 0, + "Hold", + "Hold the first frame if no previous strips in track, and always hold last frame"}, + {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include <math.h> @@ -494,49 +537,6 @@ static void rna_NlaTrack_solo_set(PointerRNA *ptr, bool value) #else -/* enum defines exported for rna_animation.c */ -const EnumPropertyItem rna_enum_nla_mode_blend_items[] = { - {NLASTRIP_MODE_REPLACE, - "REPLACE", - 0, - "Replace", - "The strip values replace the accumulated results by amount specified by influence"}, - {NLASTRIP_MODE_COMBINE, - "COMBINE", - 0, - "Combine", - "The strip values are combined with accumulated results by appropriately using addition, " - "multiplication, or quaternion math, based on channel type"}, - {0, "", 0, NULL, NULL}, - {NLASTRIP_MODE_ADD, - "ADD", - 0, - "Add", - "Weighted result of strip is added to the accumulated results"}, - {NLASTRIP_MODE_SUBTRACT, - "SUBTRACT", - 0, - "Subtract", - "Weighted result of strip is removed from the accumulated results"}, - {NLASTRIP_MODE_MULTIPLY, - "MULTIPLY", - 0, - "Multiply", - "Weighted result of strip is multiplied with the accumulated results"}, - {0, NULL, 0, NULL, NULL}, -}; - -const EnumPropertyItem rna_enum_nla_mode_extend_items[] = { - {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"}, - {NLASTRIP_EXTEND_HOLD, - "HOLD", - 0, - "Hold", - "Hold the first frame if no previous strips in track, and always hold last frame"}, - {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame"}, - {0, NULL, 0, NULL, NULL}, -}; - static void rna_def_strip_fcurves(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index a9dec810079..65a8d8bf24a 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -164,20 +164,20 @@ static const EnumPropertyItem rna_enum_vector_rotate_type_items[] = { }; const EnumPropertyItem rna_enum_node_math_items[] = { - {0, "", 0, N_("Functions"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Functions"), NULL), {NODE_MATH_ADD, "ADD", 0, "Add", "A + B"}, {NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"}, {NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"}, {NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"}, {NODE_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_MATH_POWER, "POWER", 0, "Power", "A power B"}, {NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "Logarithm A base B"}, {NODE_MATH_SQRT, "SQRT", 0, "Square Root", "Square root of A"}, {NODE_MATH_INV_SQRT, "INVERSE_SQRT", 0, "Inverse Square Root", "1 / Square root of A"}, {NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"}, {NODE_MATH_EXPONENT, "EXPONENT", 0, "Exponent", "exp(A)"}, - {0, "", 0, N_("Comparison"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Comparison"), NULL), {NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"}, {NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"}, {NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"}, @@ -194,7 +194,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = { 0, "Smooth Maximum", "The maximum from A and B with smoothing C"}, - {0, "", 0, N_("Rounding"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Rounding"), NULL), {NODE_MATH_ROUND, "ROUND", 0, @@ -203,7 +203,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = { {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"}, {NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"}, {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"}, {NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"}, {NODE_MATH_WRAP, "WRAP", 0, "Wrap", "Wrap value to range, wrap(A,B)"}, @@ -213,20 +213,20 @@ const EnumPropertyItem rna_enum_node_math_items[] = { 0, "Ping-Pong", "Wraps a value and reverses every other cycle (A,B)"}, - {0, "", 0, N_("Trigonometric"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Trigonometric"), NULL), {NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"}, {NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"}, {NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"}, {NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"}, {NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"}, {NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "The signed angle arctan(A / B)"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_MATH_SINH, "SINH", 0, "Hyperbolic Sine", "sinh(A)"}, {NODE_MATH_COSH, "COSH", 0, "Hyperbolic Cosine", "cosh(A)"}, {NODE_MATH_TANH, "TANH", 0, "Hyperbolic Tangent", "tanh(A)"}, - {0, "", 0, N_("Conversion"), ""}, + RNA_ENUM_ITEM_HEADING(N_("Conversion"), NULL), {NODE_MATH_RADIANS, "RADIANS", 0, "To Radians", "Convert from degrees to radians"}, {NODE_MATH_DEGREES, "DEGREES", 0, "To Degrees", "Convert from radians to degrees"}, {0, NULL, 0, NULL, NULL}, @@ -238,7 +238,7 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = { {NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entry-wise multiply"}, {NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entry-wise divide"}, {NODE_VECTOR_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A cross B"}, {NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"}, {NODE_VECTOR_MATH_REFLECT, @@ -259,12 +259,12 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = { "Orients a vector A to point away from a surface B as defined by its normal C. " "Returns (dot(B, C) < 0) ? A : -A"}, {NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A dot B"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"}, {NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"}, {NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "A multiplied by Scale"}, {NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entry-wise absolute"}, {NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entry-wise minimum"}, {NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entry-wise maximum"}, @@ -278,7 +278,7 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = { 0, "Snap", "Round A to the largest integer multiple of B less than or equal A"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_SINE, "SINE", 0, "Sine", "Entry-wise sin(A)"}, {NODE_VECTOR_MATH_COSINE, "COSINE", 0, "Cosine", "Entry-wise cos(A)"}, {NODE_VECTOR_MATH_TANGENT, "TANGENT", 0, "Tangent", "Entry-wise tan(A)"}, @@ -289,7 +289,7 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = { {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "True when both inputs are true"}, {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "True when at least one input is true"}, {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Opposite of the input"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_BOOLEAN_MATH_NAND, "NAND", 0, "Not And", "True when at least one input is false"}, {NODE_BOOLEAN_MATH_NOR, "NOR", 0, "Nor", "True when both inputs are false"}, {NODE_BOOLEAN_MATH_XNOR, @@ -302,7 +302,7 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = { 0, "Not Equal", "True when both inputs are different (exclusive or)"}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NODE_BOOLEAN_MATH_IMPLY, "IMPLY", 0, @@ -1610,26 +1610,31 @@ static char *rna_Node_path(const PointerRNA *ptr) char *rna_Node_ImageUser_path(const PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNode *node; - char name_esc[sizeof(node->name) * 2]; + if (!ELEM(ntree->type, NTREE_SHADER, NTREE_CUSTOM)) { + return NULL; + } - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == SH_NODE_TEX_ENVIRONMENT) { - NodeTexEnvironment *data = node->storage; - if (&data->iuser != ptr->data) { - continue; + for (bNode *node = ntree->nodes.first; node; node = node->next) { + switch (node->type) { + case SH_NODE_TEX_ENVIRONMENT: { + NodeTexEnvironment *data = node->storage; + if (&data->iuser != ptr->data) { + continue; + } + break; } - } - else if (node->type == SH_NODE_TEX_IMAGE) { - NodeTexImage *data = node->storage; - if (&data->iuser != ptr->data) { - continue; + case SH_NODE_TEX_IMAGE: { + NodeTexImage *data = node->storage; + if (&data->iuser != ptr->data) { + continue; + } + break; } - } - else { - continue; + default: + continue; } + char name_esc[sizeof(node->name) * 2]; BLI_str_escape(name_esc, node->name, sizeof(name_esc)); return BLI_sprintfN("nodes[\"%s\"].image_user", name_esc); } @@ -9575,18 +9580,14 @@ static void def_geo_distribute_points_on_faces(StructRNA *srna) static void def_geo_curve_spline_type(StructRNA *srna) { - static const EnumPropertyItem type_items[] = { - {GEO_NODE_SPLINE_TYPE_BEZIER, "BEZIER", ICON_NONE, "Bezier", "Set the splines to Bezier"}, - {GEO_NODE_SPLINE_TYPE_NURBS, "NURBS", ICON_NONE, "NURBS", "Set the splines to NURBS"}, - {GEO_NODE_SPLINE_TYPE_POLY, "POLY", ICON_NONE, "Poly", "Set the splines to Poly"}, - {0, NULL, 0, NULL, NULL}}; - PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSplineType", "storage"); prop = RNA_def_property(srna, "spline_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "spline_type"); - RNA_def_property_enum_items(prop, type_items); + RNA_def_property_enum_items(prop, rna_enum_curves_types); + RNA_def_property_ui_text(prop, "Type", "The curve type to change the selected curves to"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index b192a385546..56652a35ecb 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -149,7 +149,7 @@ const EnumPropertyItem rna_enum_object_gpencil_type_items[] = { {GP_EMPTY, "EMPTY", ICON_EMPTY_AXIS, "Blank", "Create an empty grease pencil object"}, {GP_STROKE, "STROKE", ICON_STROKE, "Stroke", "Create a simple stroke with basic colors"}, {GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {GP_LRT_SCENE, "LRT_SCENE", ICON_SCENE_DATA, @@ -256,17 +256,17 @@ const EnumPropertyItem rna_enum_object_type_items[] = { {OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Point Cloud", ""}, {OB_VOLUME, "VOLUME", ICON_OUTLINER_OB_VOLUME, "Volume", ""}, {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {OB_ARMATURE, "ARMATURE", ICON_OUTLINER_OB_ARMATURE, "Armature", ""}, {OB_LATTICE, "LATTICE", ICON_OUTLINER_OB_LATTICE, "Lattice", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {OB_EMPTY, "EMPTY", ICON_OUTLINER_OB_EMPTY, "Empty", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {OB_LAMP, "LIGHT", ICON_OUTLINER_OB_LIGHT, "Light", ""}, {OB_LIGHTPROBE, "LIGHT_PROBE", ICON_OUTLINER_OB_LIGHTPROBE, "Light Probe", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {OB_CAMERA, "CAMERA", ICON_OUTLINER_OB_CAMERA, "Camera", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {OB_SPEAKER, "SPEAKER", ICON_OUTLINER_OB_SPEAKER, "Speaker", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 4108baca2fa..30df8e20e8d 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -698,16 +698,18 @@ bool rna_PoseChannel_constraints_override_apply(Main *bmain, return true; } -static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info) +static int rna_PoseChannel_proxy_editable(PointerRNA *UNUSED(ptr), const char **UNUSED(r_info)) { +# if 0 Object *ob = (Object *)ptr->owner_id; bArmature *arm = ob->data; bPoseChannel *pchan = (bPoseChannel *)ptr->data; - if (false && pchan->bone && (pchan->bone->layer & arm->layer_protected)) { + if (pchan->bone && (pchan->bone->layer & arm->layer_protected)) { *r_info = "Can't edit property of a proxy on a protected layer"; return 0; } +# endif return PROP_EDITABLE; } diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index ae67de9228c..16a4dfe71cf 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -50,56 +50,85 @@ const EnumPropertyItem rna_enum_property_type_items[] = { {0, NULL, 0, NULL, NULL}, }; -/* Keep in sync with RNA_types.h PropertySubType and bpy_props.c's property_subtype_xxx_items */ +/* Wraps multiple enums onto a single line in a way that is difficult to read. + * NOTE: these enums are split up based on their use in `bpy.props` Python module. */ + +/* clang-format off */ +#define RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS \ + {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""}, \ + {PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""}, \ + {PROP_FILENAME, "FILE_NAME", 0, "File Name", ""}, \ + {PROP_BYTESTRING, "BYTE_STRING", 0, "Byte String", ""}, \ + {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"} + +#define RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS \ + {PROP_PIXEL, "PIXEL", 0, "Pixel", ""}, \ + {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""}, \ + {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, \ + {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, \ + {PROP_ANGLE, "ANGLE", 0, "Angle", ""}, \ + {PROP_TIME, "TIME", 0, "Time (Scene Relative)", \ + "Time specified in frames, converted to seconds based on scene frame rate"}, \ + {PROP_TIME_ABSOLUTE, "TIME_ABSOLUTE", 0, "Time (Absolute)", \ + "Time specified in seconds, independent of the scene"}, \ + {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""}, \ + {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""}, \ + {PROP_POWER, "POWER", 0, "Power", ""}, \ + {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""} + +#define RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS \ + {PROP_COLOR, "COLOR", 0, "Color", ""}, \ + {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""}, \ + {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""}, \ + {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""}, \ + {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""}, \ + {PROP_MATRIX, "MATRIX", 0, "Matrix", ""}, \ + {PROP_EULER, "EULER", 0, "Euler Angles", ""}, \ + {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""}, \ + {PROP_AXISANGLE, "AXISANGLE", 0, "Axis-Angle", ""}, \ + {PROP_XYZ, "XYZ", 0, "XYZ", ""}, \ + {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""}, \ + {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color", ""}, \ + {PROP_COORDS, "COORDINATES", 0, "Coordinates", ""}, \ + /* Boolean. */ \ + {PROP_LAYER, "LAYER", 0, "Layer", ""}, \ + {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""} + +/* clang-format on */ + +const EnumPropertyItem rna_enum_property_subtype_string_items[] = { + RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS, + + {PROP_NONE, "NONE", 0, "None", ""}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_property_subtype_number_items[] = { + RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS, + + {PROP_NONE, "NONE", 0, "None", ""}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_property_subtype_number_array_items[] = { + RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS, + + {PROP_NONE, "NONE", 0, "None", ""}, + {0, NULL, 0, NULL, NULL}, +}; + const EnumPropertyItem rna_enum_property_subtype_items[] = { {PROP_NONE, "NONE", 0, "None", ""}, - /* strings */ - {PROP_FILEPATH, "FILEPATH", 0, "File Path", ""}, - {PROP_DIRPATH, "DIRPATH", 0, "Directory Path", ""}, - {PROP_FILENAME, "FILENAME", 0, "File Name", ""}, - {PROP_BYTESTRING, "BYTESTRING", 0, "Byte String", ""}, - {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"}, - - /* numbers */ - {PROP_PIXEL, "PIXEL", 0, "Pixel", ""}, - {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""}, - {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, - {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, - {PROP_ANGLE, "ANGLE", 0, "Angle", ""}, - {PROP_TIME, - "TIME", - 0, - "Time (Scene Relative)", - "Time specified in frames, converted to seconds based on scene frame rate"}, - {PROP_TIME_ABSOLUTE, - "TIME_ABSOLUTE", - 0, - "Time (Absolute)", - "Time specified in seconds, independent of the scene"}, - {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""}, - {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""}, - {PROP_POWER, "POWER", 0, "Power", ""}, - {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""}, - - /* number arrays */ - {PROP_COLOR, "COLOR", 0, "Color", ""}, - {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""}, - {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""}, - {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""}, - {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""}, - {PROP_MATRIX, "MATRIX", 0, "Matrix", ""}, - {PROP_EULER, "EULER", 0, "Euler Angles", ""}, - {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""}, - {PROP_AXISANGLE, "AXISANGLE", 0, "Axis-Angle", ""}, - {PROP_XYZ, "XYZ", 0, "XYZ", ""}, - {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""}, - {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color", ""}, - {PROP_COORDS, "COORDS", 0, "Coordinates", ""}, - - /* booleans */ - {PROP_LAYER, "LAYER", 0, "Layer", ""}, - {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""}, + /* String. */ + RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS, + + /* Number. */ + RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS, + + /* Number array. */ + RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS, + {0, NULL, 0, NULL, NULL}, }; @@ -120,6 +149,69 @@ const EnumPropertyItem rna_enum_property_unit_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_property_flag_items[] = { + {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, + {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""}, + {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""}, + {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""}, + {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to each other", ""}, + {PROP_TEXTEDIT_UPDATE, + "TEXTEDIT_UPDATE", + 0, + "Update on every keystroke in textedit 'mode'", + ""}, + {0, NULL, 0, NULL, NULL}, +}; + +/** Only for enum type properties. */ +const EnumPropertyItem rna_enum_property_flag_enum_items[] = { + {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, + {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""}, + {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""}, + {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""}, + {PROP_ENUM_FLAG, "ENUM_FLAG", 0, "Enum Flag", ""}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_property_override_flag_items[] = { + {PROPOVERRIDE_OVERRIDABLE_LIBRARY, + "LIBRARY_OVERRIDABLE", + 0, + "Library Overridable", + "Make that property editable in library overrides of linked data-blocks"}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_property_override_flag_collection_items[] = { + {PROPOVERRIDE_OVERRIDABLE_LIBRARY, + "LIBRARY_OVERRIDABLE", + 0, + "Library Overridable", + "Make that property editable in library overrides of linked data-blocks"}, + {PROPOVERRIDE_NO_PROP_NAME, + "NO_PROPERTY_NAME", + 0, + "No Name", + "Do not use the names of the items, only their indices in the collection"}, + {PROPOVERRIDE_LIBRARY_INSERTION, + "USE_INSERTION", + 0, + "Use Insertion", + "Allow users to add new items in that collection in library overrides"}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_property_string_search_flag_items[] = { + {PROP_STRING_SEARCH_SORT, "SORT", 0, "Sort Search Results", ""}, + {PROP_STRING_SEARCH_SUGGESTION, + "SUGGESTION", + 0, + "Suggestion", + "Search results are suggestions (other values may be entered)"}, + + {0, NULL, 0, NULL, NULL}, +}; + /** \} */ #ifdef RNA_RUNTIME @@ -941,17 +1033,29 @@ static int rna_EnumPropertyItem_identifier_length(PointerRNA *ptr) static void rna_EnumPropertyItem_name_get(PointerRNA *ptr, char *value) { - strcpy(value, ((EnumPropertyItem *)ptr->data)->name); + const EnumPropertyItem *eprop = ptr->data; + /* Name can be NULL in the case of separators + * which are exposed via `_bpy.rna_enum_items_static`. */ + if (eprop->name) { + strcpy(value, eprop->name); + } + else { + value[0] = '\0'; + } } static int rna_EnumPropertyItem_name_length(PointerRNA *ptr) { - return strlen(((EnumPropertyItem *)ptr->data)->name); + const EnumPropertyItem *eprop = ptr->data; + if (eprop->name) { + return strlen(eprop->name); + } + return 0; } static void rna_EnumPropertyItem_description_get(PointerRNA *ptr, char *value) { - EnumPropertyItem *eprop = (EnumPropertyItem *)ptr->data; + const EnumPropertyItem *eprop = ptr->data; if (eprop->description) { strcpy(value, eprop->description); @@ -968,9 +1072,7 @@ static int rna_EnumPropertyItem_description_length(PointerRNA *ptr) if (eprop->description) { return strlen(eprop->description); } - else { - return 0; - } + return 0; } static int rna_EnumPropertyItem_value_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 0e423b71f1d..cc7df54e648 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -92,11 +92,11 @@ static const EnumPropertyItem uv_sculpt_relaxation_items[] = { }; #endif -const EnumPropertyItem rna_enum_snap_target_items[] = { - {SCE_SNAP_TARGET_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"}, - {SCE_SNAP_TARGET_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"}, - {SCE_SNAP_TARGET_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"}, - {SCE_SNAP_TARGET_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"}, +const EnumPropertyItem rna_enum_snap_source_items[] = { + {SCE_SNAP_SOURCE_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"}, + {SCE_SNAP_SOURCE_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"}, + {SCE_SNAP_SOURCE_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"}, + {SCE_SNAP_SOURCE_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"}, {0, NULL, 0, NULL, NULL}, }; @@ -345,9 +345,9 @@ const EnumPropertyItem rna_enum_curve_fit_method_items[] = { R_IMF_ENUM_JPEG \ R_IMF_ENUM_JPEG2K \ R_IMF_ENUM_TAGA \ - R_IMF_ENUM_TAGA_RAW{0, "", 0, " ", NULL}, \ - R_IMF_ENUM_CINEON R_IMF_ENUM_DPX R_IMF_ENUM_EXR_MULTILAYER R_IMF_ENUM_EXR R_IMF_ENUM_HDR \ - R_IMF_ENUM_TIFF R_IMF_ENUM_WEBP + R_IMF_ENUM_TAGA_RAW \ + RNA_ENUM_ITEM_SEPR_COLUMN, R_IMF_ENUM_CINEON R_IMF_ENUM_DPX R_IMF_ENUM_EXR_MULTILAYER \ + R_IMF_ENUM_EXR R_IMF_ENUM_HDR R_IMF_ENUM_TIFF R_IMF_ENUM_WEBP #ifdef RNA_RUNTIME static const EnumPropertyItem image_only_type_items[] = { @@ -359,11 +359,11 @@ static const EnumPropertyItem image_only_type_items[] = { #endif const EnumPropertyItem rna_enum_image_type_items[] = { - {0, "", 0, N_("Image"), NULL}, + RNA_ENUM_ITEM_HEADING(N_("Image"), NULL), IMAGE_TYPE_ITEMS_IMAGE_ONLY - {0, "", 0, N_("Movie"), NULL}, + RNA_ENUM_ITEM_HEADING(N_("Movie"), NULL), {R_IMF_IMTYPE_AVIJPEG, "AVI_JPEG", ICON_FILE_MOVIE, @@ -447,8 +447,8 @@ const EnumPropertyItem rna_enum_bake_target_items[] = { {R_BAKE_TARGET_VERTEX_COLORS, "VERTEX_COLORS", 0, - "Color Attributes", - "Bake to active color attribute layer on meshes"}, + "Active Color Attribute", + "Bake to the active color attribute on meshes"}, {0, NULL, 0, NULL, NULL}, }; @@ -2712,6 +2712,23 @@ static char *rna_FFmpegSettings_path(const PointerRNA *UNUSED(ptr)) return BLI_strdup("render.ffmpeg"); } +# ifdef WITH_FFMPEG +/* FFMpeg Codec setting update hook. */ +static void rna_FFmpegSettings_codec_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + 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)) { + /* 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. + */ + codec_data->constant_rate_factor = FFM_CRF_NONE; + } +} +# endif + #else /* Grease Pencil Interpolation tool settings */ @@ -3306,9 +3323,12 @@ static void rna_def_tool_settings(BlenderRNA *brna) "Absolute grid alignment while translating (based on the pivot center)"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ + /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid + * previous ambiguity of "target" (now, "source" is geometry to be moved and "target" is + * geometry to which moved geometry is snapped). */ prop = RNA_def_property(srna, "snap_target", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "snap_target"); - RNA_def_property_enum_items(prop, rna_enum_snap_target_items); + RNA_def_property_enum_items(prop, rna_enum_snap_source_items); RNA_def_property_ui_text(prop, "Snap Target", "Which part to snap onto the target"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ @@ -5919,6 +5939,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_enum_items(prop, ffmpeg_codec_items); RNA_def_property_enum_default(prop, AV_CODEC_ID_H264); RNA_def_property_ui_text(prop, "Video Codec", "FFmpeg codec to use for video output"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_update"); prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "video_bitrate"); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 200e1d65caf..3953fc66fc8 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -140,7 +140,7 @@ static void rna_Scene_ray_cast(Scene *scene, depsgraph, NULL, &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, + .snap_target_select = SCE_SNAP_TARGET_ALL, }, origin, direction, diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index ab5e4c2f0d5..3de9e632ff6 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -774,6 +774,20 @@ static void rna_def_sculpt(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem sculpt_transform_mode_items[] = { + {SCULPT_TRANSFORM_MODE_ALL_VERTICES, + "ALL_VERTICES", + 0, + "All Vertices", + "Applies the transformation to all vertices in the mesh"}, + {SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC, + "RADIUS_ELASTIC", + 0, + "Elastic", + "Applies the transformation simulating elasticity using the radius of the cursor"}, + {0, NULL, 0, NULL, NULL}, + }; + StructRNA *srna; PropertyRNA *prop; @@ -912,6 +926,12 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Gravity", "Amount of gravity after each dab"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "transform_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, sculpt_transform_mode_items); + RNA_def_property_ui_text( + prop, "Transform Mode", "How the transformation is going to be applied to the target"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "gravity_object", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 5d583d3edcb..100d90df5d6 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -240,7 +240,7 @@ static int rna_SequenceEditor_sequences_all_lookup_string(PointerRNA *ptr, ID *id = ptr->owner_id; Scene *scene = (Scene *)id; - Sequence *seq = SEQ_sequence_lookup_by_name(scene, key); + Sequence *seq = SEQ_sequence_lookup_seq_by_name(scene, key); if (seq) { RNA_pointer_create(ptr->owner_id, &RNA_Sequence, seq, r_ptr); return true; @@ -289,26 +289,11 @@ static void rna_Sequence_views_format_update(Main *bmain, Scene *scene, PointerR static void do_sequence_frame_change_update(Scene *scene, Sequence *seq) { - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); - Sequence *tseq; - SEQ_time_update_sequence(scene, seqbase, seq); - - /* ensure effects are always fit in length to their input */ - - /* TODO(sergey): probably could be optimized. - * in terms skipping update of non-changing strips - */ - for (tseq = seqbase->first; tseq; tseq = tseq->next) { - if (tseq->seq1 || tseq->seq2 || tseq->seq3) { - SEQ_time_update_sequence(scene, seqbase, tseq); - } - } + ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq); if (SEQ_transform_test_overlap(seqbase, seq)) { - SEQ_transform_seqbase_shuffle(seqbase, seq, scene); /* XXX: BROKEN!, uses context seqbasep. */ + SEQ_transform_seqbase_shuffle(seqbase, seq, scene); } - SEQ_sort(seqbase); if (seq->type == SEQ_TYPE_SOUND_RAM) { DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -341,8 +326,8 @@ static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - SEQ_time_left_handle_frame_set(seq, value); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_time_left_handle_frame_set(scene, seq, value); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); do_sequence_frame_change_update(scene, seq); SEQ_relations_invalidate_cache_composite(scene, seq); } @@ -352,8 +337,8 @@ static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - SEQ_time_right_handle_frame_set(seq, value); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_time_right_handle_frame_set(scene, seq, value); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); do_sequence_frame_change_update(scene, seq); SEQ_relations_invalidate_cache_composite(scene, seq); } @@ -437,7 +422,7 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - SEQ_time_right_handle_frame_set(seq, SEQ_time_left_handle_frame_get(seq) + value); + SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(seq) + value); do_sequence_frame_change_update(scene, seq); SEQ_relations_invalidate_cache_composite(scene, seq); } @@ -459,18 +444,15 @@ static void rna_Sequence_channel_set(PointerRNA *ptr, int value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); + ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq); /* check channel increment or decrement */ const int channel_delta = (value >= seq->machine) ? 1 : -1; seq->machine = value; if (SEQ_transform_test_overlap(seqbase, seq)) { - /* XXX: BROKEN!, uses context seqbasep. */ SEQ_transform_seqbase_shuffle_ex(seqbase, seq, scene, channel_delta); } - SEQ_sort(seqbase); SEQ_relations_invalidate_cache_composite(scene, seq); } @@ -722,8 +704,6 @@ static IDProperty **rna_Sequence_idprops(PointerRNA *ptr) static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main *bmain) { Scene *scene = (Scene *)scene_id; - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); bool has_reloaded; bool can_produce_frames; @@ -731,7 +711,6 @@ static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main SEQ_add_movie_reload_if_needed(bmain, scene, seq, &has_reloaded, &can_produce_frames); if (has_reloaded && can_produce_frames) { - SEQ_time_update_sequence(scene, seqbase, seq); SEQ_relations_invalidate_cache_raw(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -919,9 +898,6 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin Scene *scene = (Scene *)ptr->owner_id; Sequence *seq = (Sequence *)(ptr->data); SEQ_add_reload_new_file(bmain, scene, seq, true); - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); - SEQ_time_update_sequence(scene, seqbase, seq); rna_Sequence_invalidate_raw_update(bmain, scene, ptr); } @@ -1337,8 +1313,7 @@ static void rna_Sequence_separate(ID *id, Sequence *seqm, Main *bmain) Scene *scene = (Scene *)id; /* Find the appropriate seqbase */ - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seqm); + ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seqm); LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqm->seqbase) { SEQ_edit_move_strip_to_seqbase(scene, &seqm->seqbase, seq, seqbase); @@ -1779,33 +1754,33 @@ static void rna_def_strip_color_balance(BlenderRNA *brna) static const EnumPropertyItem blend_mode_items[] = { {SEQ_BLEND_REPLACE, "REPLACE", 0, "Replace", ""}, {SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""}, {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""}, {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""}, {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""}, {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""}, {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""}, {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""}, {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""}, {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""}, {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, {SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", ""}, {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", ""}, {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""}, @@ -3164,23 +3139,23 @@ static void rna_def_color_mix(StructRNA *srna) {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""}, {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""}, {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""}, {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""}, {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""}, {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""}, {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""}, {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""}, {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 36bc50e73fb..52de98be502 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -49,20 +49,6 @@ # include "WM_api.h" -static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, bool do_data) -{ - Scene *scene = (Scene *)id; - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, self); - - if (do_data) { - SEQ_time_update_recursive(scene, self); - // new_tstripdata(self); /* need 2.6x version of this. */ - } - - SEQ_time_update_sequence(scene, seqbase, self); -} - static void rna_Sequence_swap_internal(Sequence *seq_self, ReportList *reports, Sequence *seq_other) @@ -96,8 +82,7 @@ static Sequence *rna_Sequence_split( ID *id, Sequence *seq, Main *bmain, ReportList *reports, int frame, int split_method) { Scene *scene = (Scene *)id; - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); + ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq); const char *error_msg = NULL; Sequence *r_seq = SEQ_edit_strip_split( @@ -576,8 +561,6 @@ static void rna_Sequences_meta_remove( static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char *filename) { Scene *scene = (Scene *)id; - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); StripElem *se; seq->strip->stripdata = se = MEM_reallocN(seq->strip->stripdata, @@ -586,7 +569,6 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char BLI_strncpy(se->name, filename, sizeof(se->name)); seq->len++; - SEQ_time_update_sequence(scene, seqbase, seq); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); return se; @@ -595,8 +577,6 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports, int index) { Scene *scene = (Scene *)id; - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); StripElem *new_seq, *se; if (seq->len == 1) { @@ -629,8 +609,6 @@ static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports, MEM_freeN(seq->strip->stripdata); seq->strip->stripdata = new_seq; - SEQ_time_update_sequence(scene, seqbase, seq); - WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } @@ -669,11 +647,6 @@ void RNA_api_sequence_strip(StructRNA *srna) {0, NULL, 0, NULL, NULL}, }; - func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID); - RNA_def_function_ui_description(func, "Update the strip dimensions"); - parm = RNA_def_boolean(func, "data", false, "Data", "Update strip data"); - func = RNA_def_function(srna, "strip_elem_from_frame", "SEQ_render_give_stripelem"); RNA_def_function_ui_description(func, "Return the strip element from a given frame or None"); parm = RNA_def_int(func, diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c index 2714b4157fd..e38481a845a 100644 --- a/source/blender/makesrna/intern/rna_sound.c +++ b/source/blender/makesrna/intern/rna_sound.c @@ -15,7 +15,7 @@ #include "BKE_sound.h" /* Enumeration for Audio Channels, compatible with eSoundChannels */ -const EnumPropertyItem rna_enum_audio_channels_items[] = { +static const EnumPropertyItem rna_enum_audio_channels_items[] = { {SOUND_CHANNELS_INVALID, "INVALID", ICON_NONE, "Invalid", "Invalid"}, {SOUND_CHANNELS_MONO, "MONO", ICON_NONE, "Mono", "Mono"}, {SOUND_CHANNELS_STEREO, "STEREO", ICON_NONE, "Stereo", "Stereo"}, diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 36e032ffa0d..0b780a3fcc6 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -87,8 +87,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = { /* empty must be here for python, is skipped for UI */ {SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""}, - /* General */ - {0, "", ICON_NONE, "General", ""}, + /* General. */ + RNA_ENUM_ITEM_HEADING("General", NULL), {SPACE_VIEW3D, "VIEW_3D", ICON_VIEW3D, @@ -107,8 +107,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = { {SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequencer", "Video editing tools"}, {SPACE_CLIP, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", "Motion tracking tools"}, - /* Animation */ - {0, "", ICON_NONE, "Animation", ""}, + /* Animation. */ + RNA_ENUM_ITEM_HEADING("Animation", NULL), #if 0 {SPACE_ACTION, "TIMELINE", @@ -124,8 +124,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = { "Edit drivers and keyframe interpolation"}, {SPACE_NLA, "NLA_EDITOR", ICON_NLA, "Nonlinear Animation", "Combine and layer Actions"}, - /* Scripting */ - {0, "", ICON_NONE, "Scripting", ""}, + /* Scripting. */ + RNA_ENUM_ITEM_HEADING("Scripting", NULL), {SPACE_TEXT, "TEXT_EDITOR", ICON_TEXT, @@ -152,8 +152,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = { "Global bar at the bottom of the " "screen for general status information"}, - /* Data */ - {0, "", ICON_NONE, "Data", ""}, + /* Data. */ + RNA_ENUM_ITEM_HEADING("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[] = { - {0, "", ICON_NONE, "General", ""}, + RNA_ENUM_ITEM_HEADING("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", ""}, - {0, "", ICON_NONE, "Light", ""}, + RNA_ENUM_ITEM_HEADING("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", ""}, - {0, "", ICON_NONE, "Effects", ""}, + RNA_ENUM_ITEM_HEADING("Effects", NULL), {EEVEE_RENDER_PASS_BLOOM, "BLOOM", 0, "Bloom", ""}, - {0, "", ICON_NONE, "Data", ""}, + RNA_ENUM_ITEM_HEADING("Data", NULL), {EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""}, {EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""}, - {0, "", ICON_NONE, "Shader AOV", ""}, + RNA_ENUM_ITEM_HEADING("Shader AOV", NULL), {EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""}, {0, NULL, 0, NULL, NULL}, @@ -3483,6 +3483,11 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m RNA_def_property_ui_text(prop, "Display Smooth Splines", ""); RNA_def_property_update(prop, noteflag, NULL); + prop = RNA_def_property(srna, "show_mask_spline", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_SPLINE); + RNA_def_property_ui_text(prop, "Show Mask Spline", ""); + RNA_def_property_update(prop, noteflag, NULL); + prop = RNA_def_property(srna, "show_mask_overlay", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_OVERLAY); RNA_def_property_ui_text(prop, "Show Mask Overlay", ""); @@ -3493,6 +3498,13 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m RNA_def_property_enum_items(prop, overlay_mode_items); RNA_def_property_ui_text(prop, "Overlay Mode", "Overlay mode of rasterized mask"); RNA_def_property_update(prop, noteflag, NULL); + + prop = RNA_def_property(srna, "blend_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "mask_info.blend_factor"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0, 1., 0.1, 1); + RNA_def_property_ui_text(prop, "Blending Factor", "Overlay blending factor of rasterized mask"); + RNA_def_property_update(prop, noteflag, NULL); } static void rna_def_space_image_uv(BlenderRNA *brna) @@ -7818,6 +7830,12 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Integer Value", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); + prop = RNA_def_property(srna, "value_int8", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "value_int"); + RNA_def_property_range(prop, -128, 127); + RNA_def_property_ui_text(prop, "8-Bit Integer Value", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); + prop = RNA_def_property(srna, "value_boolean", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_BOOL_VALUE); RNA_def_property_ui_text(prop, "Boolean Value", ""); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index eff7c0ca136..3b28dc70e9e 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -98,22 +98,22 @@ const EnumPropertyItem rna_enum_texture_type_items[] = { #ifndef RNA_RUNTIME static const EnumPropertyItem blend_type_items[] = { {MTEX_BLEND, "MIX", 0, "Mix", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MTEX_DARK, "DARKEN", 0, "Darken", ""}, {MTEX_MUL, "MULTIPLY", 0, "Multiply", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MTEX_LIGHT, "LIGHTEN", 0, "Lighten", ""}, {MTEX_SCREEN, "SCREEN", 0, "Screen", ""}, {MTEX_ADD, "ADD", 0, "Add", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MTEX_OVERLAY, "OVERLAY", 0, "Overlay", ""}, {MTEX_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""}, {MTEX_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MTEX_DIFF, "DIFFERENCE", 0, "Difference", ""}, {MTEX_SUB, "SUBTRACT", 0, "Subtract", ""}, {MTEX_DIV, "DIVIDE", 0, "Divide", ""}, - {0, "", ICON_NONE, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MTEX_BLEND_HUE, "HUE", 0, "Hue", ""}, {MTEX_BLEND_SAT, "SATURATION", 0, "Saturation", ""}, {MTEX_BLEND_COLOR, "COLOR", 0, "Color", ""}, diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 1d0723851ad..dabb89bcd5e 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -393,7 +393,14 @@ static StructRNA *rna_Panel_register(Main *bmain, if (parent) { pt->parent = parent; - BLI_addtail(&parent->children, BLI_genericNodeN(pt)); + LinkData *pt_child_iter = parent->children.last; + for (; pt_child_iter; pt_child_iter = pt_child_iter->prev) { + PanelType *pt_child = pt_child_iter->data; + if (pt_child->order <= pt->order) { + break; + } + } + BLI_insertlinkafter(&parent->children, pt_child_iter, BLI_genericNodeN(pt)); } { diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b3d4ae80713..40dc1254a7d 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -62,23 +62,23 @@ const EnumPropertyItem rna_enum_preference_section_items[] = { {USER_SECTION_LIGHT, "LIGHTS", 0, "Lights", ""}, {USER_SECTION_EDITING, "EDITING", 0, "Editing", ""}, {USER_SECTION_ANIMATION, "ANIMATION", 0, "Animation", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {USER_SECTION_ADDONS, "ADDONS", 0, "Add-ons", ""}, #if 0 /* def WITH_USERDEF_WORKSPACES */ - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {USER_SECTION_WORKSPACE_CONFIG, "WORKSPACE_CONFIG", 0, "Configuration File", ""}, {USER_SECTION_WORKSPACE_ADDONS, "WORKSPACE_ADDONS", 0, "Add-on Overrides", ""}, {USER_SECTION_WORKSPACE_KEYMAPS, "WORKSPACE_KEYMAPS", 0, "Keymap Overrides", ""}, #endif - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {USER_SECTION_INPUT, "INPUT", 0, "Input", ""}, {USER_SECTION_NAVIGATION, "NAVIGATION", 0, "Navigation", ""}, {USER_SECTION_KEYMAP, "KEYMAP", 0, "Keymap", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""}, {USER_SECTION_SAVE_LOAD, "SAVE_LOAD", 0, "Save & Load", ""}, {USER_SECTION_FILE_PATHS, "FILE_PATHS", 0, "File Paths", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {USER_SECTION_EXPERIMENTAL, "EXPERIMENTAL", 0, "Experimental", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1531,6 +1531,11 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) RNA_def_property_ui_text(prop, "List Item Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "wcol_view_item", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_ui_text(prop, "Data-View Item Colors", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "wcol_state", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "State Colors", ""); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index c80d0e2da39..3ff9e6be3ce 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -24,6 +24,7 @@ #include "rna_internal.h" +#include "WM_api.h" #include "WM_types.h" #ifdef RNA_RUNTIME @@ -36,16 +37,16 @@ static const EnumPropertyItem event_mouse_type_items[] = { {BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5", ""}, {BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6", ""}, {BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {TABLET_STYLUS, "PEN", 0, "Pen", ""}, {TABLET_ERASER, "ERASER", 0, "Eraser", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MOUSEMOVE, "MOUSEMOVE", 0, "Move", ""}, {MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""}, {MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""}, {MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", ""}, {MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""}, {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""}, {WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", ""}, @@ -123,6 +124,23 @@ static const EnumPropertyItem event_ndof_type_items[] = { }; #endif /* RNA_RUNTIME */ +/** + * Job types for use in the `bpy.app.is_job_running(job_type)` call. + * + * This is a subset of the `WM_JOB_TYPE_...` anonymous enum defined in `WM_api.h`. It is + * intentionally kept as a subset, such that by default how jobs are handled is kept as an + * "internal implementation detail" of Blender, rather than a public, reliable part of the API. + * + * This array can be expanded on a case-by-case basis, when there is a clear and testable use case. + */ +const EnumPropertyItem rna_enum_wm_job_type_items[] = { + {WM_JOB_TYPE_RENDER, "RENDER", 0, "Regular rendering", ""}, + {WM_JOB_TYPE_RENDER_PREVIEW, "RENDER_PREVIEW", 0, "Rendering previews", ""}, + {WM_JOB_TYPE_OBJECT_BAKE, "OBJECT_BAKE", 0, "Object Baking", ""}, + {WM_JOB_TYPE_COMPOSITE, "COMPOSITE", 0, "Compositing", ""}, + {0, NULL, 0, NULL, NULL}, +}; + const EnumPropertyItem rna_enum_event_type_items[] = { /* - Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names. * - Intentionally excluded: #CAPSLOCKKEY, #UNKNOWNKEY. @@ -135,22 +153,22 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5 Mouse", "MB5"}, {BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6 Mouse", "MB6"}, {BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7 Mouse", "MB7"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {TABLET_STYLUS, "PEN", 0, "Pen", ""}, {TABLET_ERASER, "ERASER", 0, "Eraser", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {MOUSEMOVE, "MOUSEMOVE", 0, "Mouse Move", "MsMov"}, {INBETWEEN_MOUSEMOVE, "INBETWEEN_MOUSEMOVE", 0, "In-between Move", "MsSubMov"}, {MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", "MsPan"}, {MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", "MsZoom"}, {MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", "MsRot"}, {MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", "MsSmartZoom"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", "WhUp"}, {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", "WhDown"}, {WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", "WhIn"}, {WHEELOUTMOUSE, "WHEELOUTMOUSE", 0, "Wheel Out", "WhOut"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {EVT_AKEY, "A", 0, "A", ""}, {EVT_BKEY, "B", 0, "B", ""}, {EVT_CKEY, "C", 0, "C", ""}, @@ -177,7 +195,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {EVT_XKEY, "X", 0, "X", ""}, {EVT_YKEY, "Y", 0, "Y", ""}, {EVT_ZKEY, "Z", 0, "Z", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {EVT_ZEROKEY, "ZERO", 0, "0", ""}, {EVT_ONEKEY, "ONE", 0, "1", ""}, {EVT_TWOKEY, "TWO", 0, "2", ""}, @@ -188,14 +206,14 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {EVT_SEVENKEY, "SEVEN", 0, "7", ""}, {EVT_EIGHTKEY, "EIGHT", 0, "8", ""}, {EVT_NINEKEY, "NINE", 0, "9", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {EVT_LEFTCTRLKEY, "LEFT_CTRL", 0, "Left Ctrl", "CtrlL"}, {EVT_LEFTALTKEY, "LEFT_ALT", 0, "Left Alt", "AltL"}, {EVT_LEFTSHIFTKEY, "LEFT_SHIFT", 0, "Left Shift", "ShiftL"}, {EVT_RIGHTALTKEY, "RIGHT_ALT", 0, "Right Alt", "AltR"}, {EVT_RIGHTCTRLKEY, "RIGHT_CTRL", 0, "Right Ctrl", "CtrlR"}, {EVT_RIGHTSHIFTKEY, "RIGHT_SHIFT", 0, "Right Shift", "ShiftR"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {EVT_OSKEY, "OSKEY", 0, "OS Key", "Cmd"}, {EVT_APPKEY, "APP", 0, "Application", "App"}, {EVT_GRLESSKEY, "GRLESS", 0, "Grless", ""}, @@ -268,14 +286,14 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {EVT_PAGEUPKEY, "PAGE_UP", 0, "Page Up", "PgUp"}, {EVT_PAGEDOWNKEY, "PAGE_DOWN", 0, "Page Down", "PgDown"}, {EVT_ENDKEY, "END", 0, "End", ""}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {EVT_MEDIAPLAY, "MEDIA_PLAY", 0, "Media Play/Pause", ">/||"}, {EVT_MEDIASTOP, "MEDIA_STOP", 0, "Media Stop", "Stop"}, {EVT_MEDIAFIRST, "MEDIA_FIRST", 0, "Media First", "|<<"}, {EVT_MEDIALAST, "MEDIA_LAST", 0, "Media Last", ">>|"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {KM_TEXTINPUT, "TEXTINPUT", 0, "Text Input", "TxtIn"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {WINDEACTIVATE, "WINDOW_DEACTIVATE", 0, "Window Deactivate", ""}, {TIMER, "TIMER", 0, "Timer", "Tmr"}, {TIMER0, "TIMER0", 0, "Timer 0", "Tmr0"}, @@ -285,7 +303,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {TIMERAUTOSAVE, "TIMER_AUTOSAVE", 0, "Timer Autosave", "TmrSave"}, {TIMERREPORT, "TIMER_REPORT", 0, "Timer Report", "TmrReport"}, {TIMERREGION, "TIMERREGION", 0, "Timer Region", "TmrReg"}, - {0, "", 0, NULL, NULL}, + RNA_ENUM_ITEM_SEPR, {NDOF_MOTION, "NDOF_MOTION", 0, "NDOF Motion", "NdofMov"}, /* buttons on all 3dconnexion devices */ {NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "NDOF Menu", "NdofMenu"}, @@ -898,7 +916,7 @@ static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value) /** * Assumes value to be an enum from rna_enum_event_type_items. - * Function makes sure keymodifiers are only valid keys, ESC keeps it unaltered. + * Function makes sure key-modifiers are only valid keys, ESC keeps it unaltered. */ static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value) { diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 5da65510399..b9f36d35ee8 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -23,6 +23,7 @@ #include "wm_cursors.h" #include "wm_event_types.h" +#include "WM_api.h" #include "WM_types.h" #include "rna_internal.h" /* own include */ diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 4d0f58b0a55..07c2e9e0f10 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -328,7 +328,7 @@ static void mesh_merge_transform(Mesh *result, ml->e += cap_edges_index; } - /* set origindex */ + /* Set #CD_ORIGINDEX. */ index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX); if (index_orig) { copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE); @@ -464,7 +464,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, copy_m4_m4(offset, result_mat); } - /* Check if there is some scaling. If scaling, then we will not translate mapping */ + /* Check if there is some scaling. If scaling, then we will not translate mapping */ mat4_to_size(scale, offset); offset_has_scale = !is_one_v3(scale); diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index d47f2a130e3..deafe795061 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -146,7 +146,7 @@ static Mesh *get_quick_mesh( mul_m4_v3(omat, mv->co); } - BKE_mesh_normals_tag_dirty(result); + BKE_mesh_tag_coords_changed(result); } break; @@ -223,7 +223,7 @@ static BMesh *BMD_mesh_bm_create( Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip) { #ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); #endif *r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat)); @@ -270,7 +270,7 @@ static void BMD_mesh_intersection(BMesh *bm, bool is_flip) { #ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); #endif BooleanModifierData *bmd = (BooleanModifierData *)md; @@ -399,7 +399,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, Vector<Array<short>> material_remaps; # ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); # endif if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == nullptr) { @@ -447,7 +447,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, material_remaps, use_self, hole_tolerant, - bmd->operation); + bmd->operation, + nullptr); } #endif @@ -470,7 +471,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * #endif #ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); #endif if (bmd->flag & eBooleanModifierFlag_Object) { @@ -518,24 +519,29 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob, false); - if (mesh_operand_ob) { - /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh! - * But for 2.90 better not try to be smart here. */ - BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob); + if (mesh_operand_ob == nullptr) { + continue; + } - bool is_flip; - BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip); + /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh! + * But for 2.90 better not try to be smart here. */ + BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob); - BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip); + bool is_flip; + BMesh *bm = BMD_mesh_bm_create(result, object, mesh_operand_ob, operand_ob, &is_flip); - /* Needed for multiple objects to work. */ - BMeshToMeshParams bmesh_to_mesh_params{}; - bmesh_to_mesh_params.calc_object_remap = false; - BM_mesh_bm_to_me(nullptr, bm, mesh, &bmesh_to_mesh_params); + BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip); + /* Needed for multiple objects to work. */ + if (result == mesh) { result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); - BM_mesh_free(bm); } + else { + BMeshToMeshParams bmesh_to_mesh_params{}; + bmesh_to_mesh_params.calc_object_remap = false; + BM_mesh_bm_to_me(nullptr, bm, result, &bmesh_to_mesh_params); + } + BM_mesh_free(bm); } } FOREACH_COLLECTION_OBJECT_RECURSIVE_END; diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 8b6c306dae8..3698f4403a1 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -801,8 +801,9 @@ static void panelRegister(ARegionType *region_type) static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md) { CorrectiveSmoothModifierData csmd = *(const CorrectiveSmoothModifierData *)md; + const bool is_undo = BLO_write_is_undo(writer); - if (ID_IS_OVERRIDE_LIBRARY(id_owner)) { + if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) { BLI_assert(!ID_IS_LINKED(id_owner)); const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0; if (!is_local) { diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 149cf0c0cbb..1e2224e3a65 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -197,7 +197,6 @@ static void displaceModifier_do_task(void *__restrict userdata, } if (data->tex_target) { - texres.nor = NULL; BKE_texture_get_value_ex( data->scene, data->tex_target, tex_co[iter], &texres, data->pool, false); delta = texres.tin - dmd->midlevel; diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 1891ac5df7c..6b0578c77f1 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -83,17 +83,17 @@ static void requiredDataMask(Object *UNUSED(ob), if (pmd->canvas) { DynamicPaintSurface *surface = pmd->canvas->surfaces.first; for (; surface; surface = surface->next) { - /* tface */ + /* UV's: #CD_MLOOPUV. */ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ || surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) { r_cddata_masks->lmask |= CD_MASK_MLOOPUV; } - /* mcol */ + /* Vertex Colors: #CD_PROP_BYTE_COLOR. */ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT || surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) { r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR; } - /* CD_MDEFORMVERT */ + /* Vertex Weights: #CD_MDEFORMVERT. */ if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; } diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index d76a750f7e8..8e85cb1bfb3 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -897,7 +897,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, { Mesh *explode, *mesh = to_explode; MFace *mf = NULL, *mface; - /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ + // ParticleSettings *part=psmd->psys->part; /* UNUSED */ ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL, *pars = psmd->psys->particles; ParticleKey state, birth; @@ -906,7 +906,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, float *vertco = NULL, imat[4][4]; float rot[4]; float ctime; - /* float timestep; */ + // float timestep; const int *facepa = emd->facepa; int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; int i, v, u; @@ -923,7 +923,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, sim.psys = psmd->psys; sim.psmd = psmd; - /* timestep = psys_get_timestep(&sim); */ + // timestep = psys_get_timestep(&sim); ctime = BKE_scene_ctime_get(scene); diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index 06ded1c4488..a22f4b35e0d 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -846,8 +846,9 @@ static void panelRegister(ARegionType *region_type) static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md) { LaplacianDeformModifierData lmd = *(const LaplacianDeformModifierData *)md; + const bool is_undo = BLO_write_is_undo(writer); - if (ID_IS_OVERRIDE_LIBRARY(id_owner)) { + if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) { BLI_assert(!ID_IS_LINKED(id_owner)); const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0; if (!is_local) { diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index 0cff85d30ec..5dac31ac1df 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -584,8 +584,9 @@ static void panelRegister(ARegionType *region_type) static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md) { MeshDeformModifierData mmd = *(const MeshDeformModifierData *)md; + const bool is_undo = BLO_write_is_undo(writer); - if (ID_IS_OVERRIDE_LIBRARY(id_owner)) { + if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) { BLI_assert(!ID_IS_LINKED(id_owner)); const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0; if (!is_local) { diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index e0105e4962d..73db56186de 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -119,8 +119,8 @@ using blender::nodes::InputSocketFieldType; using blender::threading::EnumerableThreadSpecific; using namespace blender::fn::multi_function_types; using namespace blender::nodes::derived_node_tree_types; +using geo_log::eNamedAttrUsage; using geo_log::GeometryAttributeInfo; -using geo_log::NamedAttributeUsage; static void initData(ModifierData *md) { @@ -755,6 +755,7 @@ static void initialize_group_input(NodesModifierData &nmd, { const bNodeSocketType &socket_type = *socket.typeinfo(); const bNodeSocket &bsocket = *socket.bsocket(); + const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(bsocket.type); if (nmd.settings.properties == nullptr) { socket_type.get_geometry_nodes_cpp_value(bsocket, r_value); return; @@ -771,8 +772,7 @@ static void initialize_group_input(NodesModifierData &nmd, } if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) { - init_socket_cpp_value_from_property( - *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value); + init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; } @@ -781,14 +781,17 @@ static void initialize_group_input(NodesModifierData &nmd, const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup( nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str()); if (property_use_attribute == nullptr || property_attribute_name == nullptr) { - init_socket_cpp_value_from_property( - *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value); + init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; } const bool use_attribute = IDP_Int(property_use_attribute) != 0; if (use_attribute) { const StringRef attribute_name{IDP_String(property_attribute_name)}; + if (!blender::bke::allow_procedural_attribute_access(attribute_name)) { + init_socket_cpp_value_from_property(*property, socket_data_type, r_value); + return; + } auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>( attribute_name, *socket_type.base_cpp_type); GField attribute_field{std::move(attribute_input), 0}; @@ -799,8 +802,7 @@ static void initialize_group_input(NodesModifierData &nmd, cpp_type->construct_from_field(r_value, std::move(attribute_field)); } else { - init_socket_cpp_value_from_property( - *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value); + init_socket_cpp_value_from_property(*property, socket_data_type, r_value); } } @@ -919,7 +921,7 @@ struct OutputAttributeInfo { struct OutputAttributeToStore { GeometryComponentType component_type; - AttributeDomain domain; + eAttrDomain domain; StringRefNull name; GMutableSpan data; }; @@ -928,10 +930,10 @@ struct OutputAttributeToStore { * The output attributes are organized based on their domain, because attributes on the same domain * can be evaluated together. */ -static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attributes_to_store( +static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store( const NodesModifierData &nmd, const NodeRef &output_node, Span<GMutablePointer> output_values) { - MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain; + MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain; for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) { if (!socket_type_has_attribute_toggle(*socket->bsocket())) { continue; @@ -946,6 +948,9 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute if (attribute_name.is_empty()) { continue; } + if (!blender::bke::allow_procedural_attribute_access(attribute_name)) { + continue; + } const int index = socket->index(); const GPointer value = output_values[index]; @@ -955,7 +960,7 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink( &nmd.node_group->outputs, socket->index()); - const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain; + const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain; OutputAttributeInfo output_info; output_info.field = std::move(field); output_info.name = attribute_name; @@ -970,7 +975,7 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute */ static Vector<OutputAttributeToStore> compute_attributes_to_store( const GeometrySet &geometry, - const MultiValueMap<AttributeDomain, OutputAttributeInfo> &outputs_by_domain) + const MultiValueMap<eAttrDomain, OutputAttributeInfo> &outputs_by_domain) { Vector<OutputAttributeToStore> attributes_to_store; for (const GeometryComponentType component_type : {GEO_COMPONENT_TYPE_MESH, @@ -982,7 +987,7 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store( } const GeometryComponent &component = *geometry.get_component_for_read(component_type); for (const auto item : outputs_by_domain.items()) { - const AttributeDomain domain = item.key; + const eAttrDomain domain = item.key; const Span<OutputAttributeInfo> outputs_info = item.value; if (!component.attribute_domain_supported(domain)) { continue; @@ -1011,7 +1016,8 @@ static void store_computed_output_attributes( { for (const OutputAttributeToStore &store : attributes_to_store) { GeometryComponent &component = geometry.get_component_for_write(store.component_type); - const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(store.data.type()); + const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type( + store.data.type()); const std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data( store.name); @@ -1052,7 +1058,7 @@ static void store_output_attributes(GeometrySet &geometry, { /* All new attribute values have to be computed before the geometry is actually changed. This is * necessary because some fields might depend on attributes that are overwritten. */ - MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain = + MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain = find_output_attributes_to_store(nmd, output_node, output_values); Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store( geometry, outputs_by_domain); @@ -1431,6 +1437,14 @@ static void add_attribute_search_button(const bContext &C, nullptr, attribute_search_exec_fn, nullptr); + + char *attribute_name = RNA_string_get_alloc( + md_ptr, rna_path_attribute_name.c_str(), nullptr, 0, nullptr); + const bool access_allowed = blender::bke::allow_procedural_attribute_access(attribute_name); + MEM_freeN(attribute_name); + if (!access_allowed) { + UI_but_flag_enable(but, UI_BUT_REDALERT); + } } static void add_attribute_search_or_value_buttons(const bContext &C, @@ -1651,7 +1665,7 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p return; } const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log); - Map<std::string, NamedAttributeUsage> usage_by_attribute; + Map<std::string, eNamedAttrUsage> usage_by_attribute; log.foreach_node_log([&](const geo_log::NodeLog &node_log) { for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) { usage_by_attribute.lookup_or_add_as(used_attribute.name, @@ -1666,7 +1680,7 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p struct NameWithUsage { StringRefNull name; - NamedAttributeUsage usage; + eNamedAttrUsage usage; }; Vector<NameWithUsage> sorted_used_attribute; @@ -1681,20 +1695,20 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p for (const NameWithUsage &attribute : sorted_used_attribute) { const StringRefNull attribute_name = attribute.name; - const NamedAttributeUsage usage = attribute.usage; + const eNamedAttrUsage usage = attribute.usage; /* #uiLayoutRowWithHeading doesn't seem to work in this case. */ uiLayout *split = uiLayoutSplit(layout, 0.4f, false); std::stringstream ss; Vector<std::string> usages; - if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) { usages.append(TIP_("Read")); } - if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) { usages.append(TIP_("Write")); } - if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) { usages.append(TIP_("Remove")); } for (const int i : usages.index_range()) { diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index b5411eee883..75708851030 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -469,7 +469,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes } } - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(mesh); if (allocated_ocean) { BKE_ocean_free(omd->ocean); diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc index c6a606360e3..f410915cad8 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.cc +++ b/source/blender/modifiers/intern/MOD_particlesystem.cc @@ -306,9 +306,10 @@ ModifierTypeInfo modifierType_ParticleSystem = { /* srna */ &RNA_ParticleSystemModifier, /* type */ eModifierTypeType_OnlyDeform, /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_UsesPointCache /* | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode */ + eModifierTypeFlag_UsesPointCache +#if 0 + | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode +#endif , /* icon */ ICON_MOD_PARTICLES, diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 4201bab0326..23f447f2469 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -196,16 +196,21 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd, /* Cache settings for lazy CPU evaluation. */ -static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx, - Mesh *me, - SubsurfModifierData *smd) +static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx, + Mesh *mesh, + SubsurfModifierData *smd, + SubsurfRuntimeData *runtime_data) { SubdivToMeshSettings mesh_settings; subdiv_mesh_settings_init(&mesh_settings, smd, ctx); - me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0; - me->runtime.subsurf_resolution = mesh_settings.resolution; - me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display; - me->runtime.subsurf_session_uuid = smd->modifier.session_uuid; + + runtime_data->has_gpu_subdiv = true; + runtime_data->resolution = mesh_settings.resolution; + runtime_data->use_optimal_display = mesh_settings.use_optimal_display; + runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */ + runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals); + + mesh->runtime.subsurf_runtime_data = runtime_data; } /* Modifier itself. */ @@ -218,13 +223,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * return result; #endif SubsurfModifierData *smd = (SubsurfModifierData *)md; - SubdivSettings subdiv_settings; - BKE_subsurf_modifier_subdiv_settings_init( - &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0); - if (subdiv_settings.level == 0) { + if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) { return result; } - SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd); + + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; /* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier. */ @@ -237,13 +240,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * const bool is_editmode = (mesh->edit_mesh != NULL); const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode); if (BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ctx->object, mesh, smd, required_mode)) { - subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd); + subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data); return result; } } - Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure( - smd, &subdiv_settings, mesh, false); + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false); if (subdiv == NULL) { /* Happens on bad topology, but also on empty input mesh. */ return result; @@ -294,15 +296,11 @@ static void deformMatrices(ModifierData *md, (void)deform_matrices; SubsurfModifierData *smd = (SubsurfModifierData *)md; - SubdivSettings subdiv_settings; - BKE_subsurf_modifier_subdiv_settings_init( - &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0); - if (subdiv_settings.level == 0) { + if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) { return; } - SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd); - Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure( - smd, &subdiv_settings, mesh, false); + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false); if (subdiv == NULL) { /* Happens on bad topology, but also on empty input mesh. */ return; diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 9b0012e3890..20cc9b2392f 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1672,8 +1672,9 @@ static void panelRegister(ARegionType *region_type) static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md) { SurfaceDeformModifierData smd = *(const SurfaceDeformModifierData *)md; + const bool is_undo = BLO_write_is_undo(writer); - if (ID_IS_OVERRIDE_LIBRARY(id_owner)) { + if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) { BLI_assert(!ID_IS_LINKED(id_owner)); const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0; if (!is_local) { diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 402d7b2c99e..9693cf0c0f2 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -302,7 +302,6 @@ static void warpModifier_do(WarpModifierData *wmd, if (tex_co) { struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); TexResult texres; - texres.nor = NULL; BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false); fac *= texres.tin; } diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index 73b26dc29cd..4073f028db5 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -262,7 +262,6 @@ static void waveModifier_do(WaveModifierData *md, if (tex_co) { Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); TexResult texres; - texres.nor = NULL; BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false); amplit *= texres.tin; } diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index 65393370268..3302384568b 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -162,7 +162,6 @@ void weightvg_do_mask(const ModifierEvalContext *ctx, do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT; - texres.nor = NULL; BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage); /* Get the good channel value... */ switch (tex_use_channel) { diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 064112b7efd..e4e4295fd3a 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -62,6 +62,8 @@ void register_node_type_geo_input_curve_handles(void); void register_node_type_geo_input_curve_tilt(void); void register_node_type_geo_input_id(void); void register_node_type_geo_input_index(void); +void register_node_type_geo_input_instance_rotation(void); +void register_node_type_geo_input_instance_scale(void); void register_node_type_geo_input_material_index(void); void register_node_type_geo_input_material(void); void register_node_type_geo_input_mesh_edge_angle(void); @@ -133,6 +135,7 @@ void register_node_type_geo_transform(void); void register_node_type_geo_translate_instances(void); void register_node_type_geo_triangulate(void); void register_node_type_geo_viewer(void); +void register_node_type_geo_volume_cube(void); void register_node_type_geo_volume_to_mesh(void); #ifdef __cplusplus diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index bac4d0165e9..b82c05f33be 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -40,7 +40,7 @@ using fn::FieldInput; using fn::FieldOperation; using fn::GField; using fn::ValueOrField; -using geometry_nodes_eval_log::NamedAttributeUsage; +using geometry_nodes_eval_log::eNamedAttrUsage; using geometry_nodes_eval_log::NodeWarningType; /** @@ -298,52 +298,11 @@ class GeoNodeExecParams { */ void error_message_add(const NodeWarningType type, std::string message) const; - /** - * Creates a read-only attribute based on node inputs. The method automatically detects which - * input socket with the given name is available. - * - * \note This will add an error message if the string socket is active and - * the input attribute does not exist. - */ - GVArray get_input_attribute(const StringRef name, - const GeometryComponent &component, - AttributeDomain domain, - const CustomDataType type, - const void *default_value) const; - - template<typename T> - VArray<T> get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const T &default_value) const - { - const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>()); - GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value); - return varray.typed<T>(); - } - - /** - * Get the type of an input property or the associated constant socket types with the - * same names. Fall back to the default value if no attribute exists with the name. - */ - CustomDataType get_input_attribute_data_type(const StringRef name, - const GeometryComponent &component, - const CustomDataType default_type) const; - - /** - * If any of the corresponding input sockets are attributes instead of single values, - * use the highest priority attribute domain from among them. - * Otherwise return the default domain. - */ - AttributeDomain get_highest_priority_input_domain(Span<std::string> names, - const GeometryComponent &component, - AttributeDomain default_domain) const; - std::string attribute_producer_name() const; void set_default_remaining_outputs(); - void used_named_attribute(std::string attribute_name, NamedAttributeUsage usage); + void used_named_attribute(std::string attribute_name, eNamedAttrUsage usage); private: /* Utilities for detecting common errors at when using this class. */ diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh index 2917861f084..05c97c3903d 100644 --- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh @@ -90,8 +90,8 @@ class GFieldValueLog : public ValueLog { struct GeometryAttributeInfo { std::string name; /** Can be empty when #name does not actually exist on a geometry yet. */ - std::optional<AttributeDomain> domain; - std::optional<CustomDataType> data_type; + std::optional<eAttrDomain> domain; + std::optional<eCustomDataType> data_type; }; /** Contains information about a geometry set. In most cases this does not store the entire @@ -171,17 +171,17 @@ struct ValueOfSockets { destruct_ptr<ValueLog> value; }; -enum class NamedAttributeUsage { +enum class eNamedAttrUsage { None = 0, Read = 1 << 0, Write = 1 << 1, Remove = 1 << 2, }; -ENUM_OPERATORS(NamedAttributeUsage, NamedAttributeUsage::Remove); +ENUM_OPERATORS(eNamedAttrUsage, eNamedAttrUsage::Remove); struct UsedNamedAttribute { std::string name; - NamedAttributeUsage usage; + eNamedAttrUsage usage; }; struct NodeWithUsedNamedAttribute { @@ -219,7 +219,7 @@ class LocalGeoLogger { void log_multi_value_socket(DSocket socket, Span<GPointer> values); void log_node_warning(DNode node, NodeWarningType type, std::string message); void log_execution_time(DNode node, std::chrono::microseconds exec_time); - void log_used_named_attribute(DNode node, std::string attribute_name, NamedAttributeUsage usage); + void log_used_named_attribute(DNode node, std::string attribute_name, eNamedAttrUsage usage); /** * Log a message that will be displayed in the node editor next to the node. * This should only be used for debugging purposes and not to display information to users. diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index e0a4d241b3b..9793f133dd6 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -318,6 +318,8 @@ DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", In DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "") DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "") DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "") +DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_ROTATION, 0, "INPUT_INSTANCE_ROTATION", InputInstanceRotation, "Instance Rotation", "") +DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_SCALE, 0, "INPUT_INSTANCE_SCALE", InputInstanceScale, "Instance Scale", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", InputMeshEdgeAngle, "Edge Angle", "") @@ -395,6 +397,7 @@ DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES", Tr DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "") DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "") DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "") +DefNode(GeometryNode, GEO_NODE_VOLUME_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "") DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "") /* undefine macros */ diff --git a/source/blender/nodes/composite/nodes/node_composite_output_file.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc index 1fd6e62b4c5..f1621f83ac3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_output_file.cc +++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc @@ -130,7 +130,8 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); if (im_format) { - sockdata->format = *im_format; + BKE_image_format_copy(&sockdata->format, im_format); + sockdata->format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE; if (BKE_imtype_is_movie(sockdata->format.imtype)) { sockdata->format.imtype = R_IMF_IMTYPE_OPENEXR; } @@ -198,7 +199,8 @@ static void init_output_file(const bContext *C, PointerRNA *ptr) RenderData *rd = &scene->r; BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path)); - nimf->format = rd->im_format; + BKE_image_format_copy(&nimf->format, &rd->im_format); + nimf->format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE; if (BKE_imtype_is_movie(nimf->format.imtype)) { nimf->format.imtype = R_IMF_IMTYPE_OPENEXR; } diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc index a0942ced1be..360695299cb 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_value.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc @@ -57,7 +57,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node) static void fn_node_random_value_update(bNodeTree *ntree, bNode *node) { const NodeRandomValue &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first; bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -86,7 +86,7 @@ static void fn_node_random_value_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL); } -static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket) { switch (socket.type) { case SOCK_FLOAT: @@ -106,7 +106,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams ¶ms) { const NodeDeclaration &declaration = *params.node_type().fixed_declaration; - const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket()); if (!type) { return; } @@ -137,7 +137,7 @@ static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams &pa static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder) { const NodeRandomValue &storage = node_storage(builder.node()); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); switch (data_type) { case CD_PROP_FLOAT3: { diff --git a/source/blender/nodes/function/nodes/node_fn_separate_color.cc b/source/blender/nodes/function/nodes/node_fn_separate_color.cc index 1701dfdc6fa..19613427835 100644 --- a/source/blender/nodes/function/nodes/node_fn_separate_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_separate_color.cc @@ -60,22 +60,41 @@ class SeparateRGBAFunction : public fn::MultiFunction { { const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0, "Color"); - MutableSpan<float> red = params.uninitialized_single_output<float>(1, "Red"); - MutableSpan<float> green = params.uninitialized_single_output<float>(2, "Green"); - MutableSpan<float> blue = params.uninitialized_single_output<float>(3, "Blue"); + + MutableSpan<float> red = params.uninitialized_single_output_if_required<float>(1, "Red"); + MutableSpan<float> green = params.uninitialized_single_output_if_required<float>(2, "Green"); + MutableSpan<float> blue = params.uninitialized_single_output_if_required<float>(3, "Blue"); MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha"); - for (int64_t i : mask) { - red[i] = colors[i].r; - green[i] = colors[i].g; - blue[i] = colors[i].b; + std::array<MutableSpan<float>, 4> outputs = {red, green, blue, alpha}; + Vector<int> used_outputs; + if (!red.is_empty()) { + used_outputs.append(0); + } + if (!green.is_empty()) { + used_outputs.append(1); + } + if (!blue.is_empty()) { + used_outputs.append(2); } - if (!alpha.is_empty()) { - for (int64_t i : mask) { - alpha[i] = colors[i].a; - } + used_outputs.append(3); } + + devirtualize_varray(colors, [&](auto colors) { + mask.to_best_mask_type([&](auto mask) { + const int used_outputs_num = used_outputs.size(); + const int *used_outputs_data = used_outputs.data(); + + for (const int64_t i : mask) { + const ColorGeometry4f &color = colors[i]; + for (const int out_i : IndexRange(used_outputs_num)) { + const int channel = used_outputs_data[out_i]; + outputs[channel][i] = color[channel]; + } + } + }); + }); } }; diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 84280c0889a..015edf2d26c 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -71,6 +71,8 @@ set(SRC nodes/node_geo_input_curve_tilt.cc nodes/node_geo_input_id.cc nodes/node_geo_input_index.cc + nodes/node_geo_input_instance_rotation.cc + nodes/node_geo_input_instance_scale.cc nodes/node_geo_input_material.cc nodes/node_geo_input_material_index.cc nodes/node_geo_input_mesh_edge_angle.cc @@ -142,6 +144,7 @@ set(SRC nodes/node_geo_translate_instances.cc nodes/node_geo_triangulate.cc nodes/node_geo_viewer.cc + nodes/node_geo_volume_cube.cc nodes/node_geo_volume_to_mesh.cc node_geometry_exec.cc diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 7f9ec329efd..8f673d2264e 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -14,7 +14,7 @@ namespace blender::nodes { -std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type) +std::optional<eCustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type) { switch (type) { case SOCK_FLOAT: @@ -34,7 +34,7 @@ std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSock } } -std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket) +std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket) { return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type)); } diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 8f20da66c3b..efb7efaf1cc 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -70,13 +70,12 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, * component. If no component can work with the domain, then `error_message` is set to true. */ void separate_geometry(GeometrySet &geometry_set, - AttributeDomain domain, + eAttrDomain domain, GeometryNodeDeleteGeometryMode mode, const Field<bool> &selection_field, - bool invert, bool &r_is_error); -std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type); -std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket); +std::optional<eCustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type); +std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket); } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc index b29831ceeb6..a7404af8564 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc @@ -87,7 +87,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) static void node_update(bNodeTree *ntree, bNode *node) { const NodeAccumulateField &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first; bNodeSocket *sock_in_float = sock_in_vector->next; @@ -123,7 +123,7 @@ static void node_update(bNodeTree *ntree, bNode *node) enum class AccumulationMode { Leading = 0, Trailing = 1 }; -static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket) { switch (socket.type) { case SOCK_FLOAT: @@ -141,7 +141,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) { - const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket()); if (!type) { return; } @@ -196,11 +196,11 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu private: Field<T> input_; Field<int> group_index_; - AttributeDomain source_domain_; + eAttrDomain source_domain_; AccumulationMode accumulation_mode_; public: - AccumulateFieldInput(const AttributeDomain source_domain, + AccumulateFieldInput(const eAttrDomain source_domain, Field<T> input, Field<int> group_index, AccumulationMode accumulation_mode) @@ -213,7 +213,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { const GeometryComponentFieldContext field_context{component, source_domain_}; @@ -287,10 +287,10 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput { private: Field<T> input_; Field<int> group_index_; - AttributeDomain source_domain_; + eAttrDomain source_domain_; public: - TotalFieldInput(const AttributeDomain source_domain, Field<T> input, Field<int> group_index) + TotalFieldInput(const eAttrDomain source_domain, Field<T> input, Field<int> group_index) : GeometryFieldInput(CPPType::get<T>(), "Total Value"), input_(input), group_index_(group_index), @@ -299,7 +299,7 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { const GeometryComponentFieldContext field_context{component, source_domain_}; @@ -365,8 +365,8 @@ template<typename T> std::string identifier_suffix() static void node_geo_exec(GeoNodeExecParams params) { const NodeAccumulateField &storage = node_storage(params.node()); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - const AttributeDomain source_domain = static_cast<AttributeDomain>(storage.domain); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); + const eAttrDomain source_domain = static_cast<eAttrDomain>(storage.domain); Field<int> group_index_field = params.extract_input<Field<int>>("Group Index"); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 16967d32673..496fb081d6b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -50,7 +50,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryAttributeCapture &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first; bNodeSocket *socket_value_vector = socket_value_geometry->next; @@ -86,7 +86,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) search_link_ops_for_declarations(params, declaration.outputs().take_front(1)); const bNodeType &node_type = params.node_type(); - const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type( (eNodeSocketDatatype)params.other_socket().type); if (type && *type != CD_PROP_STRING) { if (params.in_out() == SOCK_OUT) { @@ -108,14 +108,14 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) static void try_capture_field_on_geometry(GeometryComponent &component, const AttributeIDRef &attribute_id, - const AttributeDomain domain, + const eAttrDomain domain, const GField &field) { GeometryComponentFieldContext field_context{component, domain}; const int domain_num = component.attribute_domain_num(domain); const IndexMask mask{IndexMask(domain_num)}; - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type()); + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type()); OutputAttribute output_attribute = component.attribute_try_get_for_output_only( attribute_id, domain, data_type); @@ -126,7 +126,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component, output_attribute.save(); } -static StringRefNull identifier_suffix(CustomDataType data_type) +static StringRefNull identifier_suffix(eCustomDataType data_type) { switch (data_type) { case CD_PROP_FLOAT: @@ -158,8 +158,8 @@ static void node_geo_exec(GeoNodeExecParams params) } const NodeGeometryAttributeCapture &storage = node_storage(params.node()); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); + const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain); const std::string output_identifier = "Attribute" + identifier_suffix(data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc index c7f65a68d60..35404725998 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc @@ -77,7 +77,7 @@ static void node_update(bNodeTree *ntree, bNode *node) bNodeSocket *socket_vector_std = socket_vector_range->next; bNodeSocket *socket_vector_variance = socket_vector_std->next; - const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); + const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom1); nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT); nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT); @@ -100,7 +100,7 @@ static void node_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3); } -static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket) { switch (socket.type) { case SOCK_FLOAT: @@ -121,7 +121,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) const NodeDeclaration &declaration = *params.node_type().fixed_declaration; search_link_ops_for_declarations(params, declaration.inputs().take_front(2)); - const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket()); if (!type) { return; } @@ -184,8 +184,8 @@ static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry"); const bNode &node = params.node(); - const CustomDataType data_type = static_cast<CustomDataType>(node.custom1); - const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2); + const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom1); + const eAttrDomain domain = static_cast<eAttrDomain>(node.custom2); Vector<const GeometryComponent *> components = geometry_set.get_components_for_read(); const Field<bool> selection_field = params.get_input<Field<bool>>("Selection"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index e485172d3e1..daeca311e08 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -20,6 +20,7 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Self Intersection")); b.add_input<decl::Bool>(N_("Hole Tolerant")); b.add_output<decl::Geometry>(N_("Mesh")); + b.add_output<decl::Bool>(N_("Intersecting Edges")).field_source(); } static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -27,6 +28,10 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } +struct AttributeOutputs { + StrongAnonymousAttributeID intersecting_edges_id; +}; + static void node_update(bNodeTree *ntree, bNode *node) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1; @@ -121,13 +126,21 @@ static void node_geo_exec(GeoNodeExecParams params) } } - Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes, - transforms, - float4x4::identity(), - material_remaps, - use_self, - hole_tolerant, - operation); + AttributeOutputs attribute_outputs; + if (params.output_is_required("Intersecting Edges")) { + attribute_outputs.intersecting_edges_id = StrongAnonymousAttributeID("Intersecting Edges"); + } + + Vector<int> intersecting_edges; + Mesh *result = blender::meshintersect::direct_mesh_boolean( + meshes, + transforms, + float4x4::identity(), + material_remaps, + use_self, + hole_tolerant, + operation, + attribute_outputs.intersecting_edges_id ? &intersecting_edges : nullptr); if (!result) { params.set_default_remaining_outputs(); return; @@ -138,6 +151,26 @@ static void node_geo_exec(GeoNodeExecParams params) result->totcol = materials.size(); MutableSpan(result->mat, result->totcol).copy_from(materials); + /* Store intersecting edges in attribute. */ + if (attribute_outputs.intersecting_edges_id) { + MeshComponent mesh_component; + mesh_component.replace(result, GeometryOwnershipType::Editable); + OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>( + attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE); + MutableSpan<bool> selection = attribute.as_span(); + selection.fill(false); + for (const int i : intersecting_edges) { + selection[i] = true; + } + + attribute.save(); + + params.set_output( + "Intersecting Edges", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.intersecting_edges_id), params.attribute_producer_name())); + } + params.set_output("Mesh", GeometrySet::create_with_mesh(result)); #else params.error_message_add(NodeWarningType::Error, diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index bbc8758952d..b52bf2571b5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -41,7 +41,7 @@ class EndpointFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc index dc2b9d40894..5ef20f03f28 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc @@ -84,7 +84,7 @@ class HandleTypeFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const final { if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) { 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 ae36248b573..ae2b4fd779d 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 @@ -75,7 +75,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves) case CURVE_TYPE_CATMULL_ROM: { const int resolution = resolutions[i_curve]; for (const int i : IndexRange(points.size()).drop_back(1)) { - lengths[i + 1] = evaluated_lengths[resolution * i]; + lengths[i + 1] = evaluated_lengths[resolution * (i + 1) - 1]; } break; } @@ -107,7 +107,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves) static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry &curves, const IndexMask UNUSED(mask), - const AttributeDomain domain) + const eAttrDomain domain) { VArray<bool> cyclic = curves.cyclic(); @@ -146,7 +146,7 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves, const IndexMask UNUSED(mask), - const AttributeDomain domain) + const eAttrDomain domain) { curves.ensure_evaluated_lengths(); @@ -165,7 +165,7 @@ static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGe static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &curves, const IndexMask UNUSED(mask), - const AttributeDomain domain) + const eAttrDomain domain) { if (domain == ATTR_DOMAIN_POINT) { Array<int> result(curves.points_num()); @@ -191,7 +191,7 @@ class CurveParameterFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const final { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { @@ -225,7 +225,7 @@ class CurveLengthParameterFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const final { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { @@ -259,7 +259,7 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const final { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc index 500804e41f0..8479d61a890 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_spline.hh" +#include <numeric> + +#include "BKE_attribute_math.hh" +#include "BKE_curves.hh" +#include "BKE_curves_utils.hh" #include "BLI_task.hh" @@ -29,10 +33,39 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__); - data->spline_type = GEO_NODE_SPLINE_TYPE_POLY; + data->spline_type = CURVE_TYPE_POLY; node->storage = data; } +/** + * This function answers the question about possible conversion method for NURBS-to-Bezier. In + * general for 3rd degree NURBS curves there is one-to-one relation with 3rd degree Bezier curves + * that can be exploit for conversion - Bezier handles sit on NURBS hull segments and in the middle + * between those handles are Bezier anchor points. + */ +static bool is_nurbs_to_bezier_one_to_one(const KnotsMode knots_mode) +{ + if (ELEM(knots_mode, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_ENDPOINT)) { + return true; + } + return false; +} + +/** + * As an optimization, just change the types on a mutable curves data-block when the conversion is + * simple. This could be expanded to more cases where the number of points doesn't change in the + * future, though that might require properly initializing some attributes, or removing others. + */ +static bool conversion_can_change_point_num(const CurveType dst_type) +{ + if (ELEM(dst_type, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_POLY)) { + /* The conversion to Catmull Rom or Poly should never change the number of points, no matter + * the source type (Bezier to Catmull Rom conversion cannot maintain the same shape anyway). */ + return false; + } + return true; +} + template<typename T> static void scale_input_assign(const Span<T> src, const int scale, @@ -44,32 +77,97 @@ static void scale_input_assign(const Span<T> src, } } -template<typename T> -static void scale_output_assign(const Span<T> src, - const int scale, - const int offset, - MutableSpan<T> dst) +/** + * The Bezier control point and its handles become three control points on the NURBS curve, + * so each attribute value is duplicated three times. + */ +template<typename T> static void bezier_generic_to_nurbs(const Span<T> src, MutableSpan<T> dst) { for (const int i : src.index_range()) { - dst[i * scale + offset] = src[i]; + dst[i * 3] = src[i]; + dst[i * 3 + 1] = src[i]; + dst[i * 3 + 2] = src[i]; + } +} + +static void bezier_generic_to_nurbs(const GSpan src, GMutableSpan dst) +{ + attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { + using T = decltype(dummy); + bezier_generic_to_nurbs(src.typed<T>(), dst.typed<T>()); + }); +} + +static void bezier_positions_to_nurbs(const Span<float3> src_positions, + const Span<float3> src_handles_l, + const Span<float3> src_handles_r, + MutableSpan<float3> dst_positions) +{ + for (const int i : src_positions.index_range()) { + dst_positions[i * 3] = src_handles_l[i]; + dst_positions[i * 3 + 1] = src_positions[i]; + dst_positions[i * 3 + 2] = src_handles_r[i]; + } +} + +static void catmull_rom_to_bezier_handles(const Span<float3> src_positions, + const bool cyclic, + MutableSpan<float3> dst_handles_l, + MutableSpan<float3> dst_handles_r) +{ + /* Catmull Rom curves are the same as Bezier curves with automatically defined handle positions. + * This constant defines the portion of the distance between the next/previous points to use for + * the length of the handles. */ + constexpr float handle_scale = 1.0f / 6.0f; + + if (src_positions.size() == 1) { + dst_handles_l.first() = src_positions.first(); + dst_handles_r.first() = src_positions.first(); + return; + } + + const float3 first_offset = cyclic ? src_positions[1] - src_positions.last() : + src_positions[1] - src_positions[0]; + dst_handles_r.first() = src_positions.first() + first_offset * handle_scale; + dst_handles_l.first() = src_positions.first() - first_offset * handle_scale; + + const float3 last_offset = cyclic ? src_positions.first() - src_positions.last(1) : + src_positions.last() - src_positions.last(1); + dst_handles_l.last() = src_positions.last() - last_offset * handle_scale; + dst_handles_r.last() = src_positions.last() + last_offset * handle_scale; + + for (const int i : src_positions.index_range().drop_front(1).drop_back(1)) { + const float3 left_offset = src_positions[i - 1] - src_positions[i + 1]; + dst_handles_l[i] = src_positions[i] + left_offset * handle_scale; + + const float3 right_offset = src_positions[i + 1] - src_positions[i - 1]; + dst_handles_r[i] = src_positions[i] + right_offset * handle_scale; } } +static void catmull_rom_to_nurbs_positions(const Span<float3> src_positions, + const bool cyclic, + MutableSpan<float3> dst_positions) +{ + /* Convert the Catmull Rom position data to Bezier handles in order to reuse the Bezier to + * NURBS positions assignment. If this becomes a bottleneck, this step could be avoided. */ + Array<float3, 32> bezier_handles_l(src_positions.size()); + Array<float3, 32> bezier_handles_r(src_positions.size()); + catmull_rom_to_bezier_handles(src_positions, cyclic, bezier_handles_l, bezier_handles_r); + bezier_positions_to_nurbs(src_positions, bezier_handles_l, bezier_handles_r, dst_positions); +} + template<typename T> static void nurbs_to_bezier_assign(const Span<T> src, const MutableSpan<T> dst, const KnotsMode knots_mode) { switch (knots_mode) { - case NURBS_KNOT_MODE_BEZIER: - scale_input_assign<T>(src, 3, 1, dst); - break; case NURBS_KNOT_MODE_NORMAL: for (const int i : dst.index_range()) { dst[i] = src[(i + 1) % src.size()]; } break; - case NURBS_KNOT_MODE_ENDPOINT_BEZIER: case NURBS_KNOT_MODE_ENDPOINT: for (const int i : dst.index_range().drop_back(1).drop_front(1)) { dst[i] = src[i + 1]; @@ -77,31 +175,19 @@ static void nurbs_to_bezier_assign(const Span<T> src, dst.first() = src.first(); dst.last() = src.last(); break; + default: + /* Every 3rd NURBS position (starting from index 1) should have its attributes transferred. + */ + scale_input_assign<T>(src, 3, 1, dst); } } -template<typename CopyFn> -static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn) +static void nurbs_to_bezier_assign(const GSpan src, const KnotsMode knots_mode, GMutableSpan dst) { - input_spline.attributes.foreach_attribute( - [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { - std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id); - BLI_assert(src); - if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) { - BLI_assert_unreachable(); - return false; - } - std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id); - if (!dst) { - BLI_assert_unreachable(); - return false; - } - - copy_fn(*src, *dst); - - return true; - }, - ATTR_DOMAIN_POINT); + attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { + using T = decltype(dummy); + nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode); + }); } static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_positions, @@ -109,22 +195,8 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po { const int nurbs_positions_num = nurbs_positions.size(); Vector<float3> handle_positions; - if (knots_mode == NURBS_KNOT_MODE_BEZIER) { - for (const int i : IndexRange(nurbs_positions_num)) { - if (i % 3 == 1) { - continue; - } - handle_positions.append(nurbs_positions[i]); - } - if (nurbs_positions_num % 3 == 1) { - handle_positions.pop_last(); - } - else if (nurbs_positions_num % 3 == 2) { - const int last_index = nurbs_positions_num - 1; - handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]); - } - } - else { + + if (is_nurbs_to_bezier_one_to_one(knots_mode)) { const bool is_periodic = knots_mode == NURBS_KNOT_MODE_NORMAL; if (is_periodic) { handle_positions.append(nurbs_positions[1] + @@ -134,11 +206,15 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po handle_positions.append(2 * nurbs_positions[0] - nurbs_positions[1]); handle_positions.append(nurbs_positions[1]); } + + /* Place Bezier handles on interior NURBS hull segments. Those handles can be either placed on + * endpoints, midpoints or 1/3 of the distance of a hull segment. */ const int segments_num = nurbs_positions_num - 1; const bool ignore_interior_segment = segments_num == 3 && is_periodic == false; if (ignore_interior_segment == false) { const float mid_offset = (float)(segments_num - 1) / 2.0f; for (const int i : IndexRange(1, segments_num - 2)) { + /* Divisor can have values: 1, 2 or 3. */ const int divisor = is_periodic ? 3 : std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f)); @@ -151,6 +227,7 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po } } } + const int last_index = nurbs_positions_num - 1; if (is_periodic) { handle_positions.append( @@ -162,199 +239,433 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]); } } + else { + for (const int i : IndexRange(nurbs_positions_num)) { + if (i % 3 == 1) { + continue; + } + handle_positions.append(nurbs_positions[i]); + } + if (nurbs_positions_num % 3 == 1) { + handle_positions.pop_last(); + } + else if (nurbs_positions_num % 3 == 2) { + const int last_index = nurbs_positions_num - 1; + handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]); + } + } + return handle_positions; } -static Array<float3> create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions, - const Span<float3> handle_positions, - const KnotsMode knots_mode) +static void create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions, + const Span<float3> handle_positions, + const KnotsMode knots_mode, + MutableSpan<float3> bezier_positions) { - if (knots_mode == NURBS_KNOT_MODE_BEZIER) { - /* Every third NURBS position (starting from index 1) should be converted to Bezier position */ - const int scale = 3; - const int offset = 1; - Array<float3> bezier_positions((nurbs_positions.size() + offset) / scale); - scale_input_assign(nurbs_positions, scale, offset, bezier_positions.as_mutable_span()); - return bezier_positions; + if (is_nurbs_to_bezier_one_to_one(knots_mode)) { + for (const int i : bezier_positions.index_range()) { + bezier_positions[i] = math::interpolate( + handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f); + } } - - Array<float3> bezier_positions(handle_positions.size() / 2); - for (const int i : IndexRange(bezier_positions.size())) { - bezier_positions[i] = math::interpolate( - handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f); + else { + /* Every 3rd NURBS position (starting from index 1) should be converted to Bezier position. */ + scale_input_assign(nurbs_positions, 3, 1, bezier_positions); } - return bezier_positions; } -static SplinePtr convert_to_poly_spline(const Spline &input) +static int to_bezier_size(const CurveType src_type, + const bool cyclic, + const KnotsMode knots_mode, + const int src_size) { - std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>(); - output->resize(input.positions().size()); - output->positions().copy_from(input.positions()); - output->radii().copy_from(input.radii()); - output->tilts().copy_from(input.tilts()); - Spline::copy_base_settings(input, *output); - output->attributes = input.attributes; - return output; + switch (src_type) { + case CURVE_TYPE_NURBS: { + if (is_nurbs_to_bezier_one_to_one(knots_mode)) { + return cyclic ? src_size : src_size - 2; + } + return (src_size + 1) / 3; + } + default: + return src_size; + } } -static SplinePtr poly_to_nurbs(const Spline &input) +static int to_nurbs_size(const CurveType src_type, const int src_size) { - std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>(); - output->resize(input.positions().size()); - output->positions().copy_from(input.positions()); - output->radii().copy_from(input.radii()); - output->tilts().copy_from(input.tilts()); - output->weights().fill(1.0f); - output->set_resolution(12); - output->set_order(4); - Spline::copy_base_settings(input, *output); - output->knots_mode = NURBS_KNOT_MODE_BEZIER; - output->attributes = input.attributes; - return output; + switch (src_type) { + case CURVE_TYPE_BEZIER: + case CURVE_TYPE_CATMULL_ROM: + return src_size * 3; + default: + return src_size; + } } -static SplinePtr bezier_to_nurbs(const Spline &input) +static void retrieve_curve_sizes(const bke::CurvesGeometry &curves, MutableSpan<int> sizes) { - const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input); - std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>(); - output->resize(input.size() * 3); - - scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions()); - scale_output_assign(input.radii(), 3, 0, output->radii()); - scale_output_assign(input.tilts(), 3, 0, output->tilts()); - - scale_output_assign(bezier_spline.positions(), 3, 1, output->positions()); - scale_output_assign(input.radii(), 3, 1, output->radii()); - scale_output_assign(input.tilts(), 3, 1, output->tilts()); - - scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions()); - scale_output_assign(input.radii(), 3, 2, output->radii()); - scale_output_assign(input.tilts(), 3, 2, output->tilts()); - - Spline::copy_base_settings(input, *output); - output->weights().fill(1.0f); - output->set_resolution(12); - output->set_order(4); - output->set_cyclic(input.is_cyclic()); - output->knots_mode = NURBS_KNOT_MODE_BEZIER; - output->attributes.reallocate(output->size()); - copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) { - attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { - using T = decltype(dummy); - scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>()); - scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>()); - scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>()); - }); + threading::parallel_for(curves.curves_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + sizes[i] = curves.points_for_curve(i).size(); + } }); - return output; } -static SplinePtr poly_to_bezier(const Spline &input) +struct GenericAttributes : NonCopyable, NonMovable { + Vector<GSpan> src; + Vector<GMutableSpan> dst; + + Vector<OutputAttribute> attributes; +}; + +static void retrieve_generic_point_attributes(const CurveComponent &src_component, + CurveComponent &dst_component, + GenericAttributes &attributes) { - std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>(); - output->resize(input.size()); - output->positions().copy_from(input.positions()); - output->radii().copy_from(input.radii()); - output->tilts().copy_from(input.tilts()); - output->handle_types_left().fill(BEZIER_HANDLE_VECTOR); - output->handle_types_right().fill(BEZIER_HANDLE_VECTOR); - output->set_resolution(12); - Spline::copy_base_settings(input, *output); - output->attributes = input.attributes; - return output; + src_component.attribute_foreach( + [&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.domain != ATTR_DOMAIN_POINT) { + /* Curve domain attributes are all copied directly to the result in one step. */ + return true; + } + if (src_component.attribute_is_builtin(id)) { + if (!(id.is_named() && ELEM(id, "tilt", "radius"))) { + return true; + } + } + + GVArray src_attribute = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT); + BLI_assert(src_attribute); + attributes.src.append(src_attribute.get_internal_span()); + + OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( + id, ATTR_DOMAIN_POINT, meta_data.data_type); + attributes.dst.append(dst_attribute.as_span()); + attributes.attributes.append(std::move(dst_attribute)); + + return true; + }); } -static SplinePtr nurbs_to_bezier(const Spline &input) +static void convert_to_bezier(const CurveComponent &src_component, + const bke::CurvesGeometry &src_curves, + const IndexMask selection, + CurveComponent &dst_component, + bke::CurvesGeometry &dst_curves) { - const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input); - Span<float3> nurbs_positions; - Vector<float3> nurbs_positions_vector; - KnotsMode knots_mode; - if (nurbs_spline.is_cyclic()) { - nurbs_positions_vector = nurbs_spline.positions(); - nurbs_positions_vector.append(nurbs_spline.positions()[0]); - nurbs_positions_vector.append(nurbs_spline.positions()[1]); - nurbs_positions = nurbs_positions_vector; - knots_mode = NURBS_KNOT_MODE_NORMAL; + const VArray<int8_t> src_knot_modes = src_curves.nurbs_knots_modes(); + const VArray<int8_t> src_types = src_curves.curve_types(); + const VArray<bool> src_cyclic = src_curves.cyclic(); + const Span<float3> src_positions = src_curves.positions(); + + MutableSpan<int> dst_offsets = dst_curves.offsets_for_write(); + retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write()); + threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + dst_offsets[i] = to_bezier_size( + CurveType(src_types[i]), src_cyclic[i], KnotsMode(src_knot_modes[i]), dst_offsets[i]); + } + }); + bke::curves::accumulate_counts_to_offsets(dst_offsets); + dst_curves.resize(dst_offsets.last(), dst_curves.curves_num()); + + GenericAttributes attributes; + retrieve_generic_point_attributes(src_component, dst_component, attributes); + + MutableSpan<float3> dst_positions = dst_curves.positions_for_write(); + MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write(); + MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write(); + MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write(); + MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write(); + MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write(); + + auto catmull_rom_to_bezier = [&](IndexMask selection) { + bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l); + bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r); + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions); + + threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + catmull_rom_to_bezier_handles(src_positions.slice(src_points), + src_cyclic[i], + dst_handles_l.slice(dst_points), + dst_handles_r.slice(dst_points)); + } + }); + + for (const int i : attributes.src.index_range()) { + bke::curves::copy_point_data( + src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]); + } + }; + + auto poly_to_bezier = [&](IndexMask selection) { + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions); + bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_l); + bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_r); + dst_curves.calculate_bezier_auto_handles(); + for (const int i : attributes.src.index_range()) { + bke::curves::copy_point_data( + src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]); + } + }; + + auto bezier_to_bezier = [&](IndexMask selection) { + const VArray_Span<int8_t> src_types_l = src_curves.handle_types_left(); + const VArray_Span<int8_t> src_types_r = src_curves.handle_types_right(); + const Span<float3> src_handles_l = src_curves.handle_positions_left(); + const Span<float3> src_handles_r = src_curves.handle_positions_right(); + + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions); + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_l, dst_handles_l); + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_r, dst_handles_r); + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_l, dst_types_l); + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_r, dst_types_r); + + dst_curves.calculate_bezier_auto_handles(); + + for (const int i : attributes.src.index_range()) { + bke::curves::copy_point_data( + src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]); + } + }; + + auto nurbs_to_bezier = [&](IndexMask selection) { + bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l); + bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r); + bke::curves::fill_points<float>(dst_curves, selection, 0.0f, dst_weights); + + threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + const Span<float3> src_curve_positions = src_positions.slice(src_points); + + KnotsMode knots_mode = KnotsMode(src_knot_modes[i]); + Span<float3> nurbs_positions = src_curve_positions; + Vector<float3> nurbs_positions_vector; + if (src_cyclic[i] && is_nurbs_to_bezier_one_to_one(knots_mode)) { + /* For conversion treat this as periodic closed curve. Extend NURBS hull to first and + * second point which will act as a skeleton for placing Bezier handles. */ + nurbs_positions_vector.extend(src_curve_positions); + nurbs_positions_vector.append(src_curve_positions[0]); + nurbs_positions_vector.append(src_curve_positions[1]); + nurbs_positions = nurbs_positions_vector; + knots_mode = NURBS_KNOT_MODE_NORMAL; + } + + const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions, + knots_mode); + + scale_input_assign(handle_positions.as_span(), 2, 0, dst_handles_l.slice(dst_points)); + scale_input_assign(handle_positions.as_span(), 2, 1, dst_handles_r.slice(dst_points)); + + create_nurbs_to_bezier_positions( + nurbs_positions, handle_positions, knots_mode, dst_positions.slice(dst_points)); + } + }); + + for (const int i_attribute : attributes.src.index_range()) { + threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + nurbs_to_bezier_assign(attributes.src[i_attribute].slice(src_points), + KnotsMode(src_knot_modes[i]), + attributes.dst[i_attribute].slice(dst_points)); + } + }); + } + }; + + bke::curves::foreach_curve_by_type(src_curves.curve_types(), + src_curves.curve_type_counts(), + selection, + catmull_rom_to_bezier, + poly_to_bezier, + bezier_to_bezier, + nurbs_to_bezier); + + const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert( + src_curves.curves_range()); + + for (const int i : attributes.src.index_range()) { + bke::curves::copy_point_data( + src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } - else { - nurbs_positions = nurbs_spline.positions(); - knots_mode = nurbs_spline.knots_mode; + + for (OutputAttribute &attribute : attributes.attributes) { + attribute.save(); } - const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions, - knots_mode); - BLI_assert(handle_positions.size() % 2 == 0); - const Array<float3> bezier_positions = create_nurbs_to_bezier_positions( - nurbs_positions, handle_positions.as_span(), knots_mode); - BLI_assert(handle_positions.size() == bezier_positions.size() * 2); - - std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>(); - output->resize(bezier_positions.size()); - output->positions().copy_from(bezier_positions); - nurbs_to_bezier_assign(nurbs_spline.radii(), output->radii(), knots_mode); - nurbs_to_bezier_assign(nurbs_spline.tilts(), output->tilts(), knots_mode); - scale_input_assign(handle_positions.as_span(), 2, 0, output->handle_positions_left()); - scale_input_assign(handle_positions.as_span(), 2, 1, output->handle_positions_right()); - output->handle_types_left().fill(BEZIER_HANDLE_ALIGN); - output->handle_types_right().fill(BEZIER_HANDLE_ALIGN); - output->set_resolution(nurbs_spline.resolution()); - Spline::copy_base_settings(nurbs_spline, *output); - output->attributes.reallocate(output->size()); - copy_attributes(nurbs_spline, *output, [knots_mode](GSpan src, GMutableSpan dst) { - attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { - using T = decltype(dummy); - nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode); - }); - }); - return output; } -static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params) +static void convert_to_nurbs(const CurveComponent &src_component, + const bke::CurvesGeometry &src_curves, + const IndexMask selection, + CurveComponent &dst_component, + bke::CurvesGeometry &dst_curves) { - switch (input.type()) { - case CURVE_TYPE_BEZIER: - return input.copy(); - case CURVE_TYPE_POLY: - return poly_to_bezier(input); - case CURVE_TYPE_NURBS: - if (input.size() < 4) { - params.error_message_add( - NodeWarningType::Info, - TIP_("NURBS must have minimum of 4 points for Bezier Conversion")); - return input.copy(); + const VArray<int8_t> src_types = src_curves.curve_types(); + const VArray<bool> src_cyclic = src_curves.cyclic(); + const Span<float3> src_positions = src_curves.positions(); + + MutableSpan<int> dst_offsets = dst_curves.offsets_for_write(); + retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write()); + threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), dst_offsets[i]); + } + }); + bke::curves::accumulate_counts_to_offsets(dst_offsets); + dst_curves.resize(dst_offsets.last(), dst_curves.curves_num()); + + GenericAttributes attributes; + retrieve_generic_point_attributes(src_component, dst_component, attributes); + + MutableSpan<float3> dst_positions = dst_curves.positions_for_write(); + + auto fill_weights_if_necessary = [&](const IndexMask selection) { + if (!src_curves.nurbs_weights().is_empty()) { + bke::curves::fill_points(dst_curves, selection, 1.0f, dst_curves.nurbs_weights_for_write()); + } + }; + + auto catmull_rom_to_nurbs = [&](IndexMask selection) { + dst_curves.nurbs_orders_for_write().fill_indices(selection, 4); + dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER); + fill_weights_if_necessary(selection); + + threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + catmull_rom_to_nurbs_positions( + src_positions.slice(src_points), src_cyclic[i], dst_positions.slice(dst_points)); + } + }); + + for (const int i_attribute : attributes.src.index_range()) { + threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points), + attributes.dst[i_attribute].slice(dst_points)); + } + }); + } + }; + + auto poly_to_nurbs = [&](IndexMask selection) { + dst_curves.nurbs_orders_for_write().fill_indices(selection, 4); + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions); + fill_weights_if_necessary(selection); + + /* Avoid using "Endpoint" knots modes for cyclic curves, since it adds a sharp point at the + * start/end. */ + if (src_cyclic.is_single()) { + dst_curves.nurbs_knots_modes_for_write().fill_indices( + selection, + src_cyclic.get_internal_single() ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT); + } + else { + VArray_Span<bool> cyclic{src_cyclic}; + MutableSpan<int8_t> knots_modes = dst_curves.nurbs_knots_modes_for_write(); + threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + knots_modes[i] = cyclic[i] ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT; + } + }); + } + + for (const int i_attribute : attributes.src.index_range()) { + bke::curves::copy_point_data(src_curves, + dst_curves, + selection, + attributes.src[i_attribute], + attributes.dst[i_attribute]); + } + }; + + auto bezier_to_nurbs = [&](IndexMask selection) { + const Span<float3> src_handles_l = src_curves.handle_positions_left(); + const Span<float3> src_handles_r = src_curves.handle_positions_right(); + + dst_curves.nurbs_orders_for_write().fill_indices(selection, 4); + dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER); + fill_weights_if_necessary(selection); + + threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + bezier_positions_to_nurbs(src_positions.slice(src_points), + src_handles_l.slice(src_points), + src_handles_r.slice(src_points), + dst_positions.slice(dst_points)); } - return nurbs_to_bezier(input); - case CURVE_TYPE_CATMULL_ROM: { - BLI_assert_unreachable(); - return {}; + }); + + for (const int i_attribute : attributes.src.index_range()) { + threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { + for (const int i : selection.slice(range)) { + const IndexRange src_points = src_curves.points_for_curve(i); + const IndexRange dst_points = dst_curves.points_for_curve(i); + bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points), + attributes.dst[i_attribute].slice(dst_points)); + } + }); + } + }; + + auto nurbs_to_nurbs = [&](IndexMask selection) { + bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions); + + if (!src_curves.nurbs_weights().is_empty()) { + bke::curves::copy_point_data(src_curves, + dst_curves, + selection, + src_curves.nurbs_weights(), + dst_curves.nurbs_weights_for_write()); } + + for (const int i_attribute : attributes.src.index_range()) { + bke::curves::copy_point_data(src_curves, + dst_curves, + selection, + attributes.src[i_attribute], + attributes.dst[i_attribute]); + } + }; + + bke::curves::foreach_curve_by_type(src_curves.curve_types(), + src_curves.curve_type_counts(), + selection, + catmull_rom_to_nurbs, + poly_to_nurbs, + bezier_to_nurbs, + nurbs_to_nurbs); + + const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert( + src_curves.curves_range()); + + for (const int i : attributes.src.index_range()) { + bke::curves::copy_point_data( + src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } - BLI_assert_unreachable(); - return {}; -} -static SplinePtr convert_to_nurbs(const Spline &input) -{ - switch (input.type()) { - case CURVE_TYPE_NURBS: - return input.copy(); - case CURVE_TYPE_BEZIER: - return bezier_to_nurbs(input); - case CURVE_TYPE_POLY: - return poly_to_nurbs(input); - case CURVE_TYPE_CATMULL_ROM: - BLI_assert_unreachable(); - return {}; + for (OutputAttribute &attribute : attributes.attributes) { + attribute.save(); } - BLI_assert_unreachable(); - return {}; } static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSplineType &storage = node_storage(params.node()); - const GeometryNodeSplineType dst_type = (const GeometryNodeSplineType)storage.spline_type; + const CurveType dst_type = CurveType(storage.spline_type); GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -363,45 +674,58 @@ static void node_geo_exec(GeoNodeExecParams params) if (!geometry_set.has_curves()) { return; } + const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>(); + const Curves &src_curves_id = *src_component.get_for_read(); + const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry); + if (src_curves.is_single_type(dst_type)) { + return; + } - const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); - const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( - *curve_component->get_for_read()); - GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE}; - const int domain_num = curve_component->attribute_domain_num(ATTR_DOMAIN_CURVE); - - Span<SplinePtr> src_splines = curve->splines(); - - fn::FieldEvaluator selection_evaluator{field_context, domain_num}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0); - - std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); - new_curve->resize(src_splines.size()); - - threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - if (selection[i]) { - switch (dst_type) { - case GEO_NODE_SPLINE_TYPE_POLY: - new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]); - break; - case GEO_NODE_SPLINE_TYPE_BEZIER: - new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params); - break; - case GEO_NODE_SPLINE_TYPE_NURBS: - new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]); - break; - } - } - else { - new_curve->splines()[i] = src_splines[i]->copy(); - } - } - }); - new_curve->attributes = curve->attributes; - geometry_set.replace_curves(curve_eval_to_curves(*new_curve)); + GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE}; + const int domain_size = src_component.attribute_domain_num(ATTR_DOMAIN_CURVE); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + if (!conversion_can_change_point_num(dst_type)) { + CurveComponent &dst_component = geometry_set.get_component_for_write<CurveComponent>(); + Curves &curves_id = *dst_component.get_for_write(); + bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + curves.fill_curve_types(selection, dst_type); + curves.remove_attributes_based_on_types(); + return; + } + + Curves *dst_curves_id = bke::curves_new_nomain(0, src_curves.curves_num()); + bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry); + CurveComponent dst_component; + dst_component.replace(dst_curves_id, GeometryOwnershipType::Editable); + /* Directly copy curve attributes, since they stay the same (except for curve types). */ + CustomData_copy(&src_curves.curve_data, + &dst_curves.curve_data, + CD_MASK_ALL, + CD_DUPLICATE, + src_curves.curves_num()); + + dst_curves.fill_curve_types(selection, dst_type); + + switch (dst_type) { + case CURVE_TYPE_CATMULL_ROM: + case CURVE_TYPE_POLY: + /* Converting to Catmull Rom curves or poly curves should be handled + * above by the optimization to avoid changing the point count. */ + BLI_assert_unreachable(); + break; + case CURVE_TYPE_BEZIER: + convert_to_bezier(src_component, src_curves, selection, dst_component, dst_curves); + break; + case CURVE_TYPE_NURBS: + convert_to_nurbs(src_component, src_curves, selection, dst_component, dst_curves); + break; + } + + geometry_set.replace_curves(dst_curves_id); }); params.set_output("Curve", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 73b2c400e90..7d83b4b3ecb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -124,7 +124,7 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, */ static GMutableSpan ensure_point_attribute(PointCloudComponent &points, const AttributeIDRef &attribute_id, - const CustomDataType data_type) + const eCustomDataType data_type) { points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index 99edc4d298c..352411dd8f5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -8,10 +8,11 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BKE_attribute_math.hh" +#include "BKE_curves.hh" #include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_pointcloud.h" -#include "BKE_spline.hh" #include "node_geometry_util.hh" @@ -38,26 +39,13 @@ static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> in } } -/** Utility function for making an IndexMask from a boolean selection. The indices vector should - * live at least as long as the returned IndexMask. - */ -static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<int64_t> &indices) -{ - for (const int i : mask.index_range()) { - if (mask[i] != invert) { - indices.append(i); - } - } - return IndexMask(indices); -} - /** * Copies the attributes with a domain in `domains` to `result_component`. */ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes, const GeometryComponent &in_component, GeometryComponent &result_component, - const Span<AttributeDomain> domains) + const Span<eAttrDomain> domains) { for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; @@ -70,7 +58,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!domains.contains(attribute.domain)) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -96,7 +84,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKind> &attributes, const GeometryComponent &in_component, GeometryComponent &result_component, - const AttributeDomain domain, + const eAttrDomain domain, const IndexMask mask) { for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { @@ -110,7 +98,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (domain != attribute.domain) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -132,7 +120,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes, const GeometryComponent &in_component, GeometryComponent &result_component, - const AttributeDomain domain, + const eAttrDomain domain, const Span<int> index_map) { for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { @@ -146,7 +134,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind if (domain != attribute.domain) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -324,190 +312,56 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, } } -static void spline_copy_builtin_attributes(const Spline &spline, - Spline &r_spline, - const IndexMask mask) -{ - copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask); - copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask); - copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask); - switch (spline.type()) { - case CURVE_TYPE_POLY: - break; - case CURVE_TYPE_BEZIER: { - const BezierSpline &src = static_cast<const BezierSpline &>(spline); - BezierSpline &dst = static_cast<BezierSpline &>(r_spline); - copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask); - copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask); - copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask); - copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask); - break; - } - case CURVE_TYPE_NURBS: { - const NURBSpline &src = static_cast<const NURBSpline &>(spline); - NURBSpline &dst = static_cast<NURBSpline &>(r_spline); - copy_data_based_on_mask(src.weights(), dst.weights(), mask); - break; - } - case CURVE_TYPE_CATMULL_ROM: { - BLI_assert_unreachable(); - break; - } - } -} - -static void copy_dynamic_attributes(const CustomDataAttributes &src, - CustomDataAttributes &dst, - const IndexMask mask) -{ - src.foreach_attribute( - [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { - std::optional<GSpan> src_attribute = src.get_for_read(attribute_id); - BLI_assert(src_attribute); - - if (!dst.create(attribute_id, meta_data.data_type)) { - /* Since the source spline of the same type had the attribute, adding it should work. - */ - BLI_assert_unreachable(); - } - - std::optional<GMutableSpan> new_attribute = dst.get_for_write(attribute_id); - BLI_assert(new_attribute); - - attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) { - using T = decltype(dummy); - copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask); - }); - return true; - }, - ATTR_DOMAIN_POINT); -} - -/** - * Deletes points in the spline. Those not in the mask are deleted. The spline is not split into - * multiple newer splines. - */ -static SplinePtr spline_delete(const Spline &spline, const IndexMask mask) -{ - SplinePtr new_spline = spline.copy_only_settings(); - new_spline->resize(mask.size()); - - spline_copy_builtin_attributes(spline, *new_spline, mask); - copy_dynamic_attributes(spline.attributes, new_spline->attributes, mask); - - return new_spline; -} - -static std::unique_ptr<CurveEval> curve_separate(const CurveEval &input_curve, - const Span<bool> selection, - const AttributeDomain selection_domain, - const bool invert) +static void delete_curves_selection(GeometrySet &geometry_set, + const Field<bool> &selection_field, + const eAttrDomain selection_domain) { - Span<SplinePtr> input_splines = input_curve.splines(); - std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>(); - - /* Keep track of which splines were copied to the result to copy spline domain attributes. */ - Vector<int64_t> copied_splines; - - if (selection_domain == ATTR_DOMAIN_CURVE) { - /* Operates on each of the splines as a whole, i.e. not on the points in the splines - * themselves. */ - for (const int i : selection.index_range()) { - if (selection[i] != invert) { - output_curve->add_spline(input_splines[i]->copy()); - copied_splines.append(i); - } - } - } - else { - /* Operates on the points in the splines themselves. */ - - /* Reuse index vector for each spline. */ - Vector<int64_t> indices_to_copy; - - int selection_index = 0; - for (const int i : input_splines.index_range()) { - const Spline &spline = *input_splines[i]; - - indices_to_copy.clear(); - for (const int i_point : IndexRange(spline.size())) { - if (selection[selection_index] != invert) { - /* Append i_point instead of selection_index because we need indices local to the spline - * for copying. */ - indices_to_copy.append(i_point); - } - selection_index++; - } - - /* Avoid creating an empty spline. */ - if (indices_to_copy.is_empty()) { - continue; - } + const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>(); + GeometryComponentFieldContext field_context{src_component, selection_domain}; - SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy)); - output_curve->add_spline(std::move(new_spline)); - copied_splines.append(i); - } + const int domain_num = src_component.attribute_domain_num(selection_domain); + fn::FieldEvaluator evaluator{field_context, domain_num}; + evaluator.set_selection(selection_field); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + if (selection.is_empty()) { + return; } - - if (copied_splines.is_empty()) { - return {}; + if (selection.size() == domain_num) { + geometry_set.remove<CurveComponent>(); + return; } - output_curve->attributes.reallocate(output_curve->splines().size()); - copy_dynamic_attributes( - input_curve.attributes, output_curve->attributes, IndexMask(copied_splines)); - - return output_curve; -} - -static void separate_curve_selection(GeometrySet &geometry_set, - const Field<bool> &selection_field, - const AttributeDomain selection_domain, - const bool invert) -{ - const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>(); - GeometryComponentFieldContext field_context{src_component, selection_domain}; + CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>(); + Curves &curves_id = *component.get_for_write(); + bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); - fn::FieldEvaluator selection_evaluator{field_context, - src_component.attribute_domain_num(selection_domain)}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0); - std::unique_ptr<CurveEval> r_curve = curve_separate( - *curves_to_curve_eval(*src_component.get_for_read()), selection, selection_domain, invert); - if (r_curve) { - geometry_set.replace_curves(curve_eval_to_curves(*r_curve)); + if (selection_domain == ATTR_DOMAIN_POINT) { + curves.remove_points(selection); } - else { - geometry_set.replace_curves(nullptr); + else if (selection_domain == ATTR_DOMAIN_CURVE) { + curves.remove_curves(selection); } } static void separate_point_cloud_selection(GeometrySet &geometry_set, - const Field<bool> &selection_field, - const bool invert) + const Field<bool> &selection_field) { const PointCloudComponent &src_points = *geometry_set.get_component_for_read<PointCloudComponent>(); GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT}; - fn::FieldEvaluator selection_evaluator{field_context, - src_points.attribute_domain_num(ATTR_DOMAIN_POINT)}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0); - - Vector<int64_t> indices; - const IndexMask mask = index_mask_indices(selection, invert, indices); - const int total = mask.size(); - PointCloud *pointcloud = BKE_pointcloud_new_nomain(total); - - if (total == 0) { - geometry_set.replace_pointcloud(pointcloud); + fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_num(ATTR_DOMAIN_POINT)}; + evaluator.set_selection(selection_field); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + if (selection.is_empty()) { + geometry_set.replace_pointcloud(nullptr); return; } + PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size()); + PointCloudComponent dst_points; dst_points.replace(pointcloud, GeometryOwnershipType::Editable); @@ -515,36 +369,30 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set, geometry_set.gather_attributes_for_propagation( {GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes); - copy_attributes_based_on_mask(attributes, src_points, dst_points, ATTR_DOMAIN_POINT, mask); + copy_attributes_based_on_mask(attributes, src_points, dst_points, ATTR_DOMAIN_POINT, selection); geometry_set.replace_pointcloud(pointcloud); } -static void separate_instance_selection(GeometrySet &geometry_set, - const Field<bool> &selection_field, - const bool invert) +static void delete_selected_instances(GeometrySet &geometry_set, + const Field<bool> &selection_field) { InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; - const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE); - fn::FieldEvaluator evaluator{field_context, domain_num}; - evaluator.add(selection_field); + fn::FieldEvaluator evaluator{field_context, + instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE)}; + evaluator.set_selection(selection_field); evaluator.evaluate(); - const VArray_Span<bool> &selection = evaluator.get_evaluated<bool>(0); - - Vector<int64_t> indices; - const IndexMask mask = index_mask_indices(selection, invert, indices); - - if (mask.is_empty()) { + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + if (selection.is_empty()) { geometry_set.remove<InstancesComponent>(); return; } - instances.remove_instances(mask); + instances.remove_instances(selection); } static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection, - const bool invert, MutableSpan<int> r_vertex_map, int *r_selected_vertices_num) { @@ -552,7 +400,7 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver int selected_verts_num = 0; for (const int i : r_vertex_map.index_range()) { - if (vertex_selection[i] != invert) { + if (vertex_selection[i]) { r_vertex_map[i] = selected_verts_num; selected_verts_num++; } @@ -566,7 +414,6 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver static void compute_selected_edges_from_vertex_selection(const Mesh &mesh, const Span<bool> vertex_selection, - const bool invert, MutableSpan<int> r_edge_map, int *r_selected_edges_num) { @@ -577,7 +424,7 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh, const MEdge &edge = mesh.medge[i]; /* Only add the edge if both vertices will be in the new mesh. */ - if (vertex_selection[edge.v1] != invert && vertex_selection[edge.v2] != invert) { + if (vertex_selection[edge.v1] && vertex_selection[edge.v2]) { r_edge_map[i] = selected_edges_num; selected_edges_num++; } @@ -591,7 +438,6 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh, static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh, const Span<bool> vertex_selection, - const bool invert, Vector<int> &r_selected_poly_indices, Vector<int> &r_loop_starts, int *r_selected_polys_num, @@ -609,7 +455,7 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh, bool all_verts_in_selection = true; Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop); for (const MLoop &loop : loops_src) { - if (vertex_selection[loop.v] == invert) { + if (!vertex_selection[loop.v]) { all_verts_in_selection = false; break; } @@ -633,7 +479,6 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh, static void compute_selected_vertices_and_edges_from_edge_selection( const Mesh &mesh, const Span<bool> edge_selection, - const bool invert, MutableSpan<int> r_vertex_map, MutableSpan<int> r_edge_map, int *r_selected_vertices_num, @@ -645,7 +490,7 @@ static void compute_selected_vertices_and_edges_from_edge_selection( int selected_verts_num = 0; for (const int i : IndexRange(mesh.totedge)) { const MEdge &edge = mesh.medge[i]; - if (edge_selection[i] != invert) { + if (edge_selection[i]) { r_edge_map[i] = selected_edges_num; selected_edges_num++; if (r_vertex_map[edge.v1] == -1) { @@ -671,7 +516,6 @@ static void compute_selected_vertices_and_edges_from_edge_selection( */ static void compute_selected_edges_from_edge_selection(const Mesh &mesh, const Span<bool> edge_selection, - const bool invert, MutableSpan<int> r_edge_map, int *r_selected_edges_num) { @@ -679,7 +523,7 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh, int selected_edges_num = 0; for (const int i : IndexRange(mesh.totedge)) { - if (edge_selection[i] != invert) { + if (edge_selection[i]) { r_edge_map[i] = selected_edges_num; selected_edges_num++; } @@ -697,7 +541,6 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh, */ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh, const Span<bool> edge_selection, - const bool invert, Vector<int> &r_selected_poly_indices, Vector<int> &r_loop_starts, int *r_selected_polys_num, @@ -713,7 +556,7 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh, bool all_edges_in_selection = true; Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop); for (const MLoop &loop : loops_src) { - if (edge_selection[loop.e] == invert) { + if (!edge_selection[loop.e]) { all_edges_in_selection = false; break; } @@ -736,7 +579,6 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh, static void compute_selected_mesh_data_from_vertex_selection_edge_face( const Mesh &mesh, const Span<bool> vertex_selection, - const bool invert, MutableSpan<int> r_edge_map, Vector<int> &r_selected_poly_indices, Vector<int> &r_loop_starts, @@ -746,11 +588,10 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face( { compute_selected_edges_from_vertex_selection( - mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num); + mesh, vertex_selection, r_edge_map, r_selected_edges_num); compute_selected_polygons_from_vertex_selection(mesh, vertex_selection, - invert, r_selected_poly_indices, r_loop_starts, r_selected_polys_num, @@ -763,7 +604,6 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face( */ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh, const Span<bool> vertex_selection, - const bool invert, MutableSpan<int> r_vertex_map, MutableSpan<int> r_edge_map, Vector<int> &r_selected_poly_indices, @@ -774,14 +614,13 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh, int *r_selected_loops_num) { compute_selected_vertices_from_vertex_selection( - vertex_selection, invert, r_vertex_map, r_selected_vertices_num); + vertex_selection, r_vertex_map, r_selected_vertices_num); compute_selected_edges_from_vertex_selection( - mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num); + mesh, vertex_selection, r_edge_map, r_selected_edges_num); compute_selected_polygons_from_vertex_selection(mesh, vertex_selection, - invert, r_selected_poly_indices, r_loop_starts, r_selected_polys_num, @@ -795,7 +634,6 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh, static void compute_selected_mesh_data_from_edge_selection_edge_face( const Mesh &mesh, const Span<bool> edge_selection, - const bool invert, MutableSpan<int> r_edge_map, Vector<int> &r_selected_poly_indices, Vector<int> &r_loop_starts, @@ -804,10 +642,9 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face( int *r_selected_loops_num) { compute_selected_edges_from_edge_selection( - mesh, edge_selection, invert, r_edge_map, r_selected_edges_num); + mesh, edge_selection, r_edge_map, r_selected_edges_num); compute_selected_polygons_from_edge_selection(mesh, edge_selection, - invert, r_selected_poly_indices, r_loop_starts, r_selected_polys_num, @@ -820,7 +657,6 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face( */ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh, const Span<bool> edge_selection, - const bool invert, MutableSpan<int> r_vertex_map, MutableSpan<int> r_edge_map, Vector<int> &r_selected_poly_indices, @@ -833,14 +669,12 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh, r_vertex_map.fill(-1); compute_selected_vertices_and_edges_from_edge_selection(mesh, edge_selection, - invert, r_vertex_map, r_edge_map, r_selected_vertices_num, r_selected_edges_num); compute_selected_polygons_from_edge_selection(mesh, edge_selection, - invert, r_selected_poly_indices, r_loop_starts, r_selected_polys_num, @@ -852,7 +686,6 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh, */ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh, const Span<bool> poly_selection, - const bool invert, Vector<int> &r_selected_poly_indices, Vector<int> &r_loop_starts, int *r_selected_polys_num, @@ -867,7 +700,7 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh, for (const int i : IndexRange(mesh.totpoly)) { const MPoly &poly_src = mesh.mpoly[i]; /* We keep this one. */ - if (poly_selection[i] != invert) { + if (poly_selection[i]) { r_selected_poly_indices.append_unchecked(i); r_loop_starts.append_unchecked(selected_loops_num); selected_loops_num += poly_src.totloop; @@ -883,7 +716,6 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh, static void compute_selected_mesh_data_from_poly_selection_edge_face( const Mesh &mesh, const Span<bool> poly_selection, - const bool invert, MutableSpan<int> r_edge_map, Vector<int> &r_selected_poly_indices, Vector<int> &r_loop_starts, @@ -903,7 +735,7 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face( for (const int i : IndexRange(mesh.totpoly)) { const MPoly &poly_src = mesh.mpoly[i]; /* We keep this one. */ - if (poly_selection[i] != invert) { + if (poly_selection[i]) { r_selected_poly_indices.append_unchecked(i); r_loop_starts.append_unchecked(selected_loops_num); selected_loops_num += poly_src.totloop; @@ -930,7 +762,6 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face( */ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh, const Span<bool> poly_selection, - const bool invert, MutableSpan<int> r_vertex_map, MutableSpan<int> r_edge_map, Vector<int> &r_selected_poly_indices, @@ -954,7 +785,7 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh, for (const int i : IndexRange(mesh.totpoly)) { const MPoly &poly_src = mesh.mpoly[i]; /* We keep this one. */ - if (poly_selection[i] != invert) { + if (poly_selection[i]) { r_selected_poly_indices.append_unchecked(i); r_loop_starts.append_unchecked(selected_loops_num); selected_loops_num += poly_src.totloop; @@ -985,9 +816,8 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh, */ static void do_mesh_separation(GeometrySet &geometry_set, const MeshComponent &in_component, - const VArray_Span<bool> &selection, - const bool invert, - const AttributeDomain domain, + const Span<bool> selection, + const eAttrDomain domain, const GeometryNodeDeleteGeometryMode mode) { /* Needed in all cases. */ @@ -1017,7 +847,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_POINT: compute_selected_mesh_data_from_vertex_selection(mesh_in, selection, - invert, vertex_map, edge_map, selected_poly_indices, @@ -1030,7 +859,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_EDGE: compute_selected_mesh_data_from_edge_selection(mesh_in, selection, - invert, vertex_map, edge_map, selected_poly_indices, @@ -1043,7 +871,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_FACE: compute_selected_mesh_data_from_poly_selection(mesh_in, selection, - invert, vertex_map, edge_map, selected_poly_indices, @@ -1098,7 +925,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_POINT: compute_selected_mesh_data_from_vertex_selection_edge_face(mesh_in, selection, - invert, edge_map, selected_poly_indices, new_loop_starts, @@ -1109,7 +935,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_EDGE: compute_selected_mesh_data_from_edge_selection_edge_face(mesh_in, selection, - invert, edge_map, selected_poly_indices, new_loop_starts, @@ -1120,7 +945,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_FACE: compute_selected_mesh_data_from_poly_selection_edge_face(mesh_in, selection, - invert, edge_map, selected_poly_indices, new_loop_starts, @@ -1169,7 +993,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_POINT: compute_selected_polygons_from_vertex_selection(mesh_in, selection, - invert, selected_poly_indices, new_loop_starts, &selected_polys_num, @@ -1178,7 +1001,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_EDGE: compute_selected_polygons_from_edge_selection(mesh_in, selection, - invert, selected_poly_indices, new_loop_starts, &selected_polys_num, @@ -1187,7 +1009,6 @@ static void do_mesh_separation(GeometrySet &geometry_set, case ATTR_DOMAIN_FACE: compute_selected_polygons_from_poly_selection(mesh_in, selection, - invert, selected_poly_indices, new_loop_starts, &selected_polys_num, @@ -1230,32 +1051,25 @@ static void do_mesh_separation(GeometrySet &geometry_set, static void separate_mesh_selection(GeometrySet &geometry_set, const Field<bool> &selection_field, - const AttributeDomain selection_domain, - const GeometryNodeDeleteGeometryMode mode, - const bool invert) + const eAttrDomain selection_domain, + const GeometryNodeDeleteGeometryMode mode) { const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>(); GeometryComponentFieldContext field_context{src_component, selection_domain}; - fn::FieldEvaluator selection_evaluator{field_context, - src_component.attribute_domain_num(selection_domain)}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0); - + fn::FieldEvaluator evaluator{field_context, + src_component.attribute_domain_num(selection_domain)}; + evaluator.add(selection_field); + evaluator.evaluate(); + const VArray<bool> selection = evaluator.get_evaluated<bool>(0); /* Check if there is anything to delete. */ - bool delete_nothing = true; - for (const int i : selection.index_range()) { - if (selection[i] == invert) { - delete_nothing = false; - break; - } - } - if (delete_nothing) { + if (selection.is_single() && selection.get_internal_single()) { return; } - do_mesh_separation(geometry_set, src_component, selection, invert, selection_domain, mode); + const VArray_Span<bool> selection_span{selection}; + + do_mesh_separation(geometry_set, src_component, selection_span, selection_domain, mode); } } // namespace blender::nodes::node_geo_delete_geometry_cc @@ -1263,10 +1077,9 @@ static void separate_mesh_selection(GeometrySet &geometry_set, namespace blender::nodes { void separate_geometry(GeometrySet &geometry_set, - const AttributeDomain domain, + const eAttrDomain domain, const GeometryNodeDeleteGeometryMode mode, const Field<bool> &selection_field, - const bool invert, bool &r_is_error) { namespace file_ns = blender::nodes::node_geo_delete_geometry_cc; @@ -1274,25 +1087,26 @@ void separate_geometry(GeometrySet &geometry_set, bool some_valid_domain = false; if (geometry_set.has_pointcloud()) { if (domain == ATTR_DOMAIN_POINT) { - file_ns::separate_point_cloud_selection(geometry_set, selection_field, invert); + file_ns::separate_point_cloud_selection(geometry_set, selection_field); some_valid_domain = true; } } if (geometry_set.has_mesh()) { if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) { - file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode, invert); + file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode); some_valid_domain = true; } } if (geometry_set.has_curves()) { if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) { - file_ns::separate_curve_selection(geometry_set, selection_field, domain, invert); + file_ns::delete_curves_selection( + geometry_set, fn::invert_boolean_field(selection_field), domain); some_valid_domain = true; } } if (geometry_set.has_instances()) { if (domain == ATTR_DOMAIN_INSTANCE) { - file_ns::separate_instance_selection(geometry_set, selection_field, invert); + file_ns::delete_selected_instances(geometry_set, selection_field); some_valid_domain = true; } } @@ -1320,7 +1134,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { const bNode *node = static_cast<bNode *>(ptr->data); const NodeGeometryDeleteGeometry &storage = node_storage(*node); - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain); uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); /* Only show the mode when it is relevant. */ @@ -1342,21 +1156,25 @@ static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); + /* The node's input is a selection of elements that should be deleted, but the code is + * implemented as a separation operation that copies the selected elements to a new geometry. + * Invert the selection to avoid the need to keep track of both cases in the code. */ + const Field<bool> selection = fn::invert_boolean_field( + params.extract_input<Field<bool>>("Selection")); const NodeGeometryDeleteGeometry &storage = node_storage(params.node()); - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain); const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode; if (domain == ATTR_DOMAIN_INSTANCE) { bool is_error; - separate_geometry(geometry_set, domain, mode, selection_field, true, is_error); + separate_geometry(geometry_set, domain, mode, selection, is_error); } else { geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { bool is_error; /* Invert here because we want to keep the things not in the selection. */ - separate_geometry(geometry_set, domain, mode, selection_field, true, is_error); + separate_geometry(geometry_set, domain, mode, selection, is_error); }); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index c242cfd5cf3..f95601813a3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -247,7 +247,7 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(const Span<bool> elimina BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh, const Span<float3> bary_coords, const Span<int> looptri_indices, - const AttributeDomain source_domain, + const eAttrDomain source_domain, const GVArray &source_data, GMutableSpan output_data) { @@ -293,7 +293,7 @@ BLI_NOINLINE static void propagate_existing_attributes( for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - const CustomDataType output_data_type = entry.value.data_type; + const eCustomDataType output_data_type = entry.value.data_type; ReadAttributeLookup source_attribute = mesh_component.attribute_try_get_for_read(attribute_id); if (!source_attribute) { @@ -396,7 +396,7 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent const Field<float> &density_field, const Field<bool> &selection_field) { - const AttributeDomain attribute_domain = ATTR_DOMAIN_CORNER; + const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER; GeometryComponentFieldContext field_context{component, attribute_domain}; const int domain_num = component.attribute_domain_num(attribute_domain); diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index dcd9bcfb034..52156b59c51 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -153,7 +153,7 @@ static void transfer_attributes( continue; } - AttributeDomain out_domain; + eAttrDomain out_domain; if (src_attribute.domain == ATTR_DOMAIN_FACE) { out_domain = ATTR_DOMAIN_POINT; } @@ -164,7 +164,7 @@ static void transfer_attributes( /* Edges and Face Corners. */ out_domain = src_attribute.domain; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type( + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, out_domain, data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index ac057ad078b..691f341b518 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -92,12 +92,16 @@ static Array<int> accumulate_counts_to_offsets(const IndexMask selection, /* Utility functions for threaded copying of attribute data where possible. */ template<typename T> -static void threaded_slice_fill(Span<int> offsets, Span<T> src, MutableSpan<T> dst) +static void threaded_slice_fill(Span<int> offsets, + const IndexMask selection, + Span<T> src, + MutableSpan<T> dst) { BLI_assert(offsets.last() == dst.size()); + BLI_assert(selection.size() == offsets.size() - 1); threading::parallel_for(IndexRange(offsets.size() - 1), 512, [&](IndexRange range) { for (const int i : range) { - dst.slice(range_for_offsets_index(offsets, i)).fill(src[i]); + dst.slice(range_for_offsets_index(offsets, i)).fill(src[selection[i]]); } }); } @@ -140,7 +144,7 @@ static void threaded_id_offset_copy(const Span<int> offsets, /** Create the copy indices for the duplication domain. */ static void create_duplicate_index_attribute(GeometryComponent &component, - const AttributeDomain output_domain, + const eAttrDomain output_domain, const IndexMask selection, const IndexAttributes &attribute_outputs, const Span<int> offsets) @@ -191,6 +195,7 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set, const GeometryComponentType component_type, const bool include_instances, const Span<int> offsets, + const IndexMask selection, const GeometryComponent &src_component, GeometryComponent &dst_component) { @@ -203,8 +208,8 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set, if (!src_attribute || src_attribute.domain != ATTR_DOMAIN_POINT) { continue; } - AttributeDomain out_domain = src_attribute.domain; - const CustomDataType data_type = bke::cpp_type_to_custom_data_type( + eAttrDomain out_domain = src_attribute.domain; + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, out_domain, data_type); @@ -215,7 +220,7 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set, using T = decltype(dummy); VArray_Span<T> src = src_attribute.varray.typed<T>(); MutableSpan<T> dst = dst_attribute.as_span<T>(); - threaded_slice_fill<T>(offsets, src, dst); + threaded_slice_fill<T>(offsets, selection, src, dst); }); dst_attribute.save(); } @@ -249,8 +254,8 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set, continue; } - AttributeDomain out_domain = src_attribute.domain; - const CustomDataType data_type = bke::cpp_type_to_custom_data_type( + eAttrDomain out_domain = src_attribute.domain; + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, out_domain, data_type); @@ -265,7 +270,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set, switch (out_domain) { case ATTR_DOMAIN_CURVE: - threaded_slice_fill<T>(curve_offsets, src, dst); + threaded_slice_fill<T>(curve_offsets, selection, src, dst); break; case ATTR_DOMAIN_POINT: threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { @@ -416,6 +421,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, const Span<int> vert_mapping, const Span<int> loop_mapping, const Span<int> offsets, + const IndexMask selection, const GeometryComponent &src_component, GeometryComponent &dst_component) { @@ -429,8 +435,8 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, continue; } - AttributeDomain out_domain = src_attribute.domain; - const CustomDataType data_type = bke::cpp_type_to_custom_data_type( + eAttrDomain out_domain = src_attribute.domain; + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, out_domain, data_type); @@ -445,7 +451,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, switch (out_domain) { case ATTR_DOMAIN_FACE: - threaded_slice_fill<T>(offsets, src, dst); + threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_EDGE: threaded_mapped_copy<T>(edge_mapping, src, dst); @@ -601,6 +607,7 @@ static void duplicate_faces(GeometrySet &geometry_set, vert_mapping, loop_mapping, offsets, + selection, src_component, dst_component); @@ -627,6 +634,7 @@ static void duplicate_faces(GeometrySet &geometry_set, static void copy_edge_attributes_without_id(GeometrySet &geometry_set, const Span<int> point_mapping, const Span<int> offsets, + const IndexMask selection, const GeometryComponent &src_component, GeometryComponent &dst_component) { @@ -640,8 +648,8 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, continue; } - const AttributeDomain out_domain = src_attribute.domain; - const CustomDataType data_type = bke::cpp_type_to_custom_data_type( + const eAttrDomain out_domain = src_attribute.domain; + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, out_domain, data_type); @@ -655,7 +663,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, switch (out_domain) { case ATTR_DOMAIN_EDGE: - threaded_slice_fill<T>(offsets, src, dst); + threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_POINT: threaded_mapped_copy<T>(point_mapping, src, dst); @@ -693,12 +701,12 @@ static void copy_stable_id_edges(const Mesh &mesh, VArray_Span<int> src{src_attribute.varray.typed<int>()}; MutableSpan<int> dst = dst_attribute.as_span<int>(); threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) { - for (const int i_edge : range) { - const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge); + for (const int i_selection : range) { + const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection); if (edge_range.size() == 0) { continue; } - const MEdge &edge = edges[i_edge]; + const MEdge &edge = edges[selection[i_selection]]; const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2}; dst[vert_range[0]] = src[edge.v1]; @@ -742,9 +750,9 @@ static void duplicate_edges(GeometrySet &geometry_set, Array<int> vert_orig_indices(edge_offsets.last() * 2); threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { - for (const int i_edge : range) { - const MEdge &edge = edges[i_edge]; - const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge); + for (const int i_selection : range) { + const MEdge &edge = edges[selection[i_selection]]; + const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection); const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2); for (const int i_duplicate : IndexRange(edge_range.size())) { @@ -755,8 +763,8 @@ static void duplicate_edges(GeometrySet &geometry_set, }); threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { - for (const int i_edge : range) { - const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge); + for (const int i_selection : range) { + const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection); const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2); for (const int i_duplicate : IndexRange(edge_range.size())) { MEdge &new_edge = new_edges[edge_range[i_duplicate]]; @@ -771,7 +779,7 @@ static void duplicate_edges(GeometrySet &geometry_set, dst_component.replace(new_mesh, GeometryOwnershipType::Editable); copy_edge_attributes_without_id( - geometry_set, vert_orig_indices, edge_offsets, src_component, dst_component); + geometry_set, vert_orig_indices, edge_offsets, selection, src_component, dst_component); copy_stable_id_edges(mesh, selection, edge_offsets, src_component, dst_component); @@ -841,8 +849,8 @@ static void duplicate_points_curve(GeometrySet &geometry_set, continue; } - AttributeDomain domain = src_attribute.domain; - const CustomDataType data_type = bke::cpp_type_to_custom_data_type( + eAttrDomain domain = src_attribute.domain; + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( attribute_id, domain, data_type); @@ -866,7 +874,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set, }); break; case ATTR_DOMAIN_POINT: - threaded_slice_fill(offsets, src, dst); + threaded_slice_fill(offsets, selection, src, dst); break; default: break; @@ -913,12 +921,17 @@ static void duplicate_points_mesh(GeometrySet &geometry_set, Mesh *new_mesh = BKE_mesh_new_nomain(offsets.last(), 0, 0, 0, 0); MutableSpan<MVert> dst_verts(new_mesh->mvert, new_mesh->totvert); - threaded_slice_fill(offsets.as_span(), src_verts, dst_verts); + threaded_slice_fill(offsets.as_span(), selection, src_verts, dst_verts); MeshComponent dst_component; dst_component.replace(new_mesh, GeometryOwnershipType::Editable); - copy_point_attributes_without_id( - geometry_set, GEO_COMPONENT_TYPE_MESH, false, offsets, src_component, dst_component); + copy_point_attributes_without_id(geometry_set, + GEO_COMPONENT_TYPE_MESH, + false, + offsets, + selection, + src_component, + dst_component); copy_stable_id_point(offsets, src_component, dst_component); @@ -959,8 +972,13 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set, PointCloudComponent dst_component; dst_component.replace(pointcloud, GeometryOwnershipType::Editable); - copy_point_attributes_without_id( - geometry_set, GEO_COMPONENT_TYPE_POINT_CLOUD, false, offsets, src_points, dst_component); + copy_point_attributes_without_id(geometry_set, + GEO_COMPONENT_TYPE_POINT_CLOUD, + false, + offsets, + selection, + src_points, + dst_component); copy_stable_id_point(offsets, src_points, dst_component); @@ -1058,8 +1076,13 @@ static void duplicate_instances(GeometrySet &geometry_set, dst_instances.instance_reference_handles().slice(range).fill(new_handle); } - copy_point_attributes_without_id( - geometry_set, GEO_COMPONENT_TYPE_INSTANCES, true, offsets, src_instances, dst_instances); + copy_point_attributes_without_id(geometry_set, + GEO_COMPONENT_TYPE_INSTANCES, + true, + offsets, + selection, + src_instances, + dst_instances); if (attribute_outputs.duplicate_index) { create_duplicate_index_attribute( @@ -1080,7 +1103,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const NodeGeometryDuplicateElements &storage = node_storage(params.node()); - const AttributeDomain duplicate_domain = AttributeDomain(storage.domain); + const eAttrDomain duplicate_domain = eAttrDomain(storage.domain); Field<int> count_field = params.extract_input<Field<int>>("Amount"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 1f16e8d55bd..3eca92e37a3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -63,7 +63,7 @@ struct AttributeOutputs { static void save_selection_as_attribute(MeshComponent &component, const AnonymousAttributeID *id, - const AttributeDomain domain, + const eAttrDomain domain, const IndexMask selection) { BLI_assert(!component.attribute_exists(id)); @@ -145,6 +145,34 @@ static void expand_mesh(Mesh &mesh, BKE_mesh_update_customdata_pointers(&mesh, false); } +static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: + return mesh.vdata; + case ATTR_DOMAIN_EDGE: + return mesh.edata; + case ATTR_DOMAIN_FACE: + return mesh.pdata; + case ATTR_DOMAIN_CORNER: + return mesh.ldata; + default: + BLI_assert_unreachable(); + return mesh.vdata; + } +} + +static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domain) +{ + MeshComponent component; + component.replace(&mesh, GeometryOwnershipType::ReadOnly); + CustomData &custom_data = get_customdata(mesh, domain); + if (int *orig_indices = static_cast<int *>(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) { + return {orig_indices, component.attribute_domain_num(domain)}; + } + return {}; +} + static MEdge new_edge(const int v1, const int v2) { MEdge edge; @@ -292,6 +320,9 @@ static void extrude_mesh_vertices(MeshComponent &component, }); }); + MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); + vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); + if (attribute_outputs.top_id) { save_selection_as_attribute( component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range); @@ -615,6 +646,13 @@ static void extrude_mesh_edges(MeshComponent &component, }); } + MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); + vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); + + MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE); + edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE); + edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE); + if (attribute_outputs.top_id) { save_selection_as_attribute( component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range); @@ -983,6 +1021,17 @@ static void extrude_mesh_face_regions(MeshComponent &component, }); } + MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); + vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); + + MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE); + edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE); + edge_orig_indices.slice(new_inner_edge_range).fill(ORIGINDEX_NONE); + edge_orig_indices.slice(boundary_edge_range).fill(ORIGINDEX_NONE); + + MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE); + poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE); + if (attribute_outputs.top_id) { save_selection_as_attribute( component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection); @@ -1232,6 +1281,16 @@ static void extrude_individual_mesh_faces(MeshComponent &component, } }); + MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); + vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); + + MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE); + edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE); + edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE); + + MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE); + poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE); + /* Finally update each extruded polygon's loops to point to the new edges and vertices. * This must be done last, because they were used to find original indices for attribute * interpolation before. Alternatively an original index array could be built for each domain. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc index bf956f3b83d..58281df43d3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc @@ -42,7 +42,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) static void node_update(bNodeTree *ntree, bNode *node) { - const CustomDataType data_type = static_cast<CustomDataType>(node->custom2); + const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom2); bNodeSocket *sock_index = static_cast<bNodeSocket *>(node->inputs.first); bNodeSocket *sock_in_float = sock_index->next; @@ -74,10 +74,10 @@ class FieldAtIndex final : public GeometryFieldInput { private: Field<int> index_field_; GField value_field_; - AttributeDomain value_field_domain_; + eAttrDomain value_field_domain_; public: - FieldAtIndex(Field<int> index_field, GField value_field, AttributeDomain value_field_domain) + FieldAtIndex(Field<int> index_field, GField value_field, eAttrDomain value_field_domain) : GeometryFieldInput(value_field.cpp_type(), "Field at Index"), index_field_(std::move(index_field)), value_field_(std::move(value_field)), @@ -86,7 +86,7 @@ class FieldAtIndex final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const final { const GeometryComponentFieldContext value_field_context{component, value_field_domain_}; @@ -125,7 +125,7 @@ class FieldAtIndex final : public GeometryFieldInput { } }; -static StringRefNull identifier_suffix(CustomDataType data_type) +static StringRefNull identifier_suffix(eCustomDataType data_type) { switch (data_type) { case CD_PROP_BOOL: @@ -147,8 +147,8 @@ static StringRefNull identifier_suffix(CustomDataType data_type) static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); - const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1); - const CustomDataType data_type = static_cast<CustomDataType>(node.custom2); + const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1); + const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom2); Field<int> index_field = params.extract_input<Field<int>>("Index"); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc index 3ba1378abe1..da249278867 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc @@ -26,7 +26,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const final { if (component.type() != GEO_COMPONENT_TYPE_CURVE) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc new file mode 100644 index 00000000000..4c7a148a797 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_instance_rotation_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Vector>(N_("Rotation")).field_source(); +} + +class VectorFieldInput final : public GeometryFieldInput { + public: + VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Rotation") + { + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const eAttrDomain UNUSED(domain), + IndexMask UNUSED(mask)) const final + { + if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) { + return {}; + } + + const InstancesComponent &instance_component = static_cast<const InstancesComponent &>( + component); + + auto rotation_fn = [&](const int i) -> float3 { + return instance_component.instance_transforms()[i].to_euler(); + }; + + return VArray<float3>::ForFunc(instance_component.instances_num(), rotation_fn); + } + + uint64_t hash() const override + { + return 22374372; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const VectorFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<float3> rotation{std::make_shared<VectorFieldInput>()}; + params.set_output("Rotation", std::move(rotation)); +} + +} // namespace blender::nodes::node_geo_input_instance_rotation_cc + +void register_node_type_geo_input_instance_rotation() +{ + namespace file_ns = blender::nodes::node_geo_input_instance_rotation_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_INPUT_INSTANCE_ROTATION, "Instance Rotation", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc new file mode 100644 index 00000000000..b3a362fbf3e --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_instance_scale_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Vector>(N_("Scale")).field_source(); +} + +class VectorFieldInput final : public GeometryFieldInput { + public: + VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Scale") + { + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const eAttrDomain UNUSED(domain), + IndexMask UNUSED(mask)) const final + { + if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) { + return {}; + } + + const InstancesComponent &instance_component = static_cast<const InstancesComponent &>( + component); + + auto scale_fn = [&](const int i) -> float3 { + return instance_component.instance_transforms()[i].scale(); + }; + + return VArray<float3>::ForFunc(instance_component.instances_num(), scale_fn); + } + + uint64_t hash() const override + { + return 8346343; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const VectorFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<float3> scale{std::make_shared<VectorFieldInput>()}; + params.set_output("Scale", std::move(scale)); +} + +} // namespace blender::nodes::node_geo_input_instance_scale_cc + +void register_node_type_geo_input_instance_scale() +{ + namespace file_ns = blender::nodes::node_geo_input_instance_scale_cc; + + static bNodeType ntype; + geo_node_type_base(&ntype, GEO_NODE_INPUT_INSTANCE_SCALE, "Instance Scale", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc index 60640bcb112..f27e0305c7d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc @@ -61,7 +61,7 @@ class AngleFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() != GEO_COMPONENT_TYPE_MESH) { @@ -115,7 +115,7 @@ class SignedAngleFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() != GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc index 92172ce7ebd..cbc2ebc3e68 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc @@ -25,7 +25,7 @@ class EdgeNeighborCountFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc index 213a692d80f..6201ad26bfb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc @@ -29,7 +29,7 @@ enum VertexNumber { VERTEX_ONE, VERTEX_TWO }; static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component, const VertexNumber vertex, - const AttributeDomain domain) + const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { @@ -58,7 +58,7 @@ class EdgeVerticesFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { @@ -85,7 +85,7 @@ class EdgeVerticesFieldInput final : public GeometryFieldInput { static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component, const VertexNumber vertex, - const AttributeDomain domain) + const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { @@ -120,7 +120,7 @@ class EdgePositionFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc index 6f58d28100a..7a0e3e37a65 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc @@ -17,7 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b) } static VArray<float> construct_face_area_gvarray(const MeshComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { @@ -41,7 +41,7 @@ class FaceAreaFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc index 62af0476057..532c3dc81e5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc @@ -34,7 +34,7 @@ class PlanarFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, [[maybe_unused]] IndexMask mask) const final { if (component.type() != GEO_COMPONENT_TYPE_MESH) { @@ -65,7 +65,7 @@ class PlanarFieldInput final : public GeometryFieldInput { float3 reference_normal = poly_normals[i_poly]; float min = FLT_MAX; - float max = FLT_MIN; + float max = -FLT_MAX; for (const int i_loop : poly_loops.index_range()) { const float3 vert = mesh->mvert[poly_loops[i_loop].v].co; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc index 9968c53f649..67a21cb06f0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc @@ -20,7 +20,7 @@ static void node_declare(NodeDeclarationBuilder &b) } static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { @@ -53,7 +53,7 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { @@ -76,7 +76,7 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput { }; static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { @@ -98,7 +98,7 @@ class FaceVertexCountFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc index 8e3a9b6769d..bd57924d685 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc @@ -30,7 +30,7 @@ class IslandFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() != GEO_COMPONENT_TYPE_MESH) { @@ -78,7 +78,7 @@ class IslandCountFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() != GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc index b81016eda18..62b3f9d0e92 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc @@ -21,7 +21,7 @@ static void node_declare(NodeDeclarationBuilder &b) } static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { @@ -47,7 +47,7 @@ class VertexCountFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { @@ -70,7 +70,7 @@ class VertexCountFieldInput final : public GeometryFieldInput { }; static VArray<int> construct_face_count_gvarray(const MeshComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { @@ -96,7 +96,7 @@ class VertexFaceCountFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc index 72dfff7cb39..122c7b352c7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc @@ -37,7 +37,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryInputNamedAttribute &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); bNodeSocket *socket_vector = (bNodeSocket *)node->outputs.first; bNodeSocket *socket_float = socket_vector->next; @@ -58,7 +58,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) search_link_ops_for_declarations(params, declaration.inputs()); if (params.in_out() == SOCK_OUT) { - const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type( static_cast<eNodeSocketDatatype>(params.other_socket().type)); if (type && *type != CD_PROP_STRING) { /* The input and output sockets have the same name. */ @@ -74,7 +74,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryInputNamedAttribute &storage = node_storage(params.node()); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); const std::string name = params.extract_input<std::string>("Name"); @@ -82,8 +82,13 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_default_remaining_outputs(); return; } + if (!bke::allow_procedural_attribute_access(name)) { + params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message)); + params.set_default_remaining_outputs(); + return; + } - params.used_named_attribute(name, NamedAttributeUsage::Read); + params.used_named_attribute(name, eNamedAttrUsage::Read); switch (data_type) { case CD_PROP_FLOAT: diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index 84d773ff8eb..def82eefca5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -17,7 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b) */ static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { if (!component.has_curves()) { return {}; @@ -47,7 +47,7 @@ class SplineCountFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 039d6b69585..f5831941094 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -64,7 +64,7 @@ static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curve } static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component, - const AttributeDomain domain) + const eAttrDomain domain) { if (!component.has_curves()) { return {}; @@ -101,7 +101,7 @@ class TangentFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index 12582f9e9c6..21ef8765e43 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -49,7 +49,7 @@ static void add_instances_from_component( const GeoNodeExecParams ¶ms, const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate) { - const AttributeDomain domain = ATTR_DOMAIN_POINT; + const eAttrDomain domain = ATTR_DOMAIN_POINT; const int domain_num = src_component.attribute_domain_num(domain); VArray<bool> pick_instance; diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 2067086c298..0c56b0e9804 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -47,8 +47,8 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info( static void fill_new_attribute(Span<const GeometryComponent *> src_components, const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const AttributeDomain domain, + const eCustomDataType data_type, + const eAttrDomain domain, GMutableSpan dst_span) { const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index c245260f259..5875606da97 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -51,7 +51,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput { } GVArray get_varray_for_context(const GeometryComponent &component, - const AttributeDomain domain, + const eAttrDomain domain, IndexMask mask) const final { if (component.type() != GEO_COMPONENT_TYPE_MESH) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index 6b23b685549..7463eb01471 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -58,7 +58,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, Field<float3> &position_field, Field<float> &radius_field, Field<bool> &selection_field, - const AttributeDomain domain) + const eAttrDomain domain) { const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>(); if (mesh_component == nullptr) { @@ -105,7 +105,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - const CustomDataType data_type = entry.value.data_type; + const eCustomDataType data_type = entry.value.data_type; GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); OutputAttribute dst = point_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 577b001fd06..00b3d167755 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -59,7 +59,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - const CustomDataType data_type = entry.value.data_type; + const eCustomDataType data_type = entry.value.data_type; GVArray src = point_component->attribute_get_for_read( attribute_id, ATTR_DOMAIN_POINT, data_type); OutputAttribute dst = mesh_component.attribute_try_get_for_output_only( diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index 0c30d50076f..a92cee2d066 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -70,7 +70,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryRaycast &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *socket_float = socket_vector->next; @@ -104,7 +104,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) search_link_ops_for_declarations(params, declaration.inputs().take_back(3)); search_link_ops_for_declarations(params, declaration.outputs().take_front(4)); - const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type( (eNodeSocketDatatype)params.other_socket().type); if (type && *type != CD_PROP_STRING) { /* The input and output sockets have the same name. */ @@ -215,7 +215,7 @@ class RaycastFunction : public fn::MultiFunction { /* Always evaluate the target domain data on the face corner domain because it contains the most * information. Eventually this could be exposed as an option or determined automatically from * the field inputs for better performance. */ - const AttributeDomain domain_ = ATTR_DOMAIN_CORNER; + const eAttrDomain domain_ = ATTR_DOMAIN_CORNER; fn::MFSignature signature_; @@ -320,7 +320,7 @@ class RaycastFunction : public fn::MultiFunction { } }; -static GField get_input_attribute_field(GeoNodeExecParams ¶ms, const CustomDataType data_type) +static GField get_input_attribute_field(GeoNodeExecParams ¶ms, const eCustomDataType data_type) { switch (data_type) { case CD_PROP_FLOAT: @@ -387,7 +387,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet target = params.extract_input<GeometrySet>("Target Geometry"); const NodeGeometryRaycast &storage = node_storage(params.node()); const GeometryNodeRaycastMapMode mapping = (GeometryNodeRaycastMapMode)storage.mapping; - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); if (target.is_empty()) { params.set_default_remaining_outputs(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc index effeac5a37f..da42b8c5ee0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc @@ -21,6 +21,11 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); return; } + if (!bke::allow_procedural_attribute_access(name)) { + params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message)); + params.set_output("Geometry", std::move(geometry_set)); + return; + } std::atomic<bool> attribute_exists = false; std::atomic<bool> cannot_delete = false; @@ -50,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params) }); if (attribute_exists && !cannot_delete) { - params.used_named_attribute(name, NamedAttributeUsage::Remove); + params.used_named_attribute(name, eNamedAttrUsage::Remove); } if (!attribute_exists) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc index 7923ad6264d..d674f611c9f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc @@ -183,8 +183,7 @@ static void scale_vertex_islands_uniformly(Mesh &mesh, } }); - /* Positions have changed, so the normals will have to be recomputed. */ - BKE_mesh_normals_tag_dirty(&mesh); + BKE_mesh_tag_coords_changed(&mesh); } static void scale_vertex_islands_on_axis(Mesh &mesh, @@ -228,8 +227,7 @@ static void scale_vertex_islands_on_axis(Mesh &mesh, } }); - /* Positions have changed, so the normals will have to be recomputed. */ - BKE_mesh_normals_tag_dirty(&mesh); + BKE_mesh_tag_coords_changed(&mesh); } static Vector<ElementIsland> prepare_face_islands(const Mesh &mesh, const IndexMask face_selection) @@ -397,7 +395,7 @@ static void scale_edges_on_axis(MeshComponent &mesh_component, const AxisScaleFi static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); - const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1); + const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1); const GeometryNodeScaleElementsMode scale_mode = static_cast<GeometryNodeScaleElementsMode>( node.custom2); diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc index a48d422e4c0..d785694f253 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc @@ -43,38 +43,31 @@ static void node_geo_exec(GeoNodeExecParams params) const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); const NodeGeometrySeparateGeometry &storage = node_storage(params.node()); - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain); - auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set, bool invert) { + auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set, + const Field<bool> &selection) { bool is_error; if (domain == ATTR_DOMAIN_INSTANCE) { /* Only delete top level instances. */ - separate_geometry(geometry_set, - domain, - GEO_NODE_DELETE_GEOMETRY_MODE_ALL, - selection_field, - invert, - is_error); + separate_geometry( + geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, is_error); } else { geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - separate_geometry(geometry_set, - domain, - GEO_NODE_DELETE_GEOMETRY_MODE_ALL, - selection_field, - invert, - is_error); + separate_geometry( + geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, is_error); }); } }; GeometrySet second_set(geometry_set); if (params.output_is_required("Selection")) { - separate_geometry_maybe_recursively(geometry_set, false); + separate_geometry_maybe_recursively(geometry_set, selection_field); params.set_output("Selection", std::move(geometry_set)); } if (params.output_is_required("Inverted")) { - separate_geometry_maybe_recursively(second_set, true); + separate_geometry_maybe_recursively(second_set, fn::invert_boolean_field(selection_field)); params.set_output("Inverted", std::move(second_set)); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc index ec95f9a89f5..87d48daddea 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc @@ -16,9 +16,9 @@ static void set_id_in_component(GeometryComponent &component, const Field<bool> &selection_field, const Field<int> &id_field) { - const AttributeDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ? - ATTR_DOMAIN_INSTANCE : - ATTR_DOMAIN_POINT; + const eAttrDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ? + ATTR_DOMAIN_INSTANCE : + ATTR_DOMAIN_POINT; GeometryComponentFieldContext field_context{component, domain}; const int domain_num = component.attribute_domain_num(domain); if (domain_num == 0) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index caf33108716..e9ed87e552f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -25,7 +25,7 @@ static void node_declare(NodeDeclarationBuilder &b) static void set_computed_position_and_offset(GeometryComponent &component, const VArray<float3> &in_positions, const VArray<float3> &in_offsets, - const AttributeDomain domain, + const eAttrDomain domain, const IndexMask selection) { @@ -139,9 +139,8 @@ static void set_position_in_component(GeometryComponent &component, const Field<float3> &position_field, const Field<float3> &offset_field) { - AttributeDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? - ATTR_DOMAIN_INSTANCE : - ATTR_DOMAIN_POINT; + eAttrDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? ATTR_DOMAIN_INSTANCE : + ATTR_DOMAIN_POINT; GeometryComponentFieldContext field_context{component, domain}; const int domain_num = component.attribute_domain_num(domain); if (domain_num == 0) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc index 3b348dd0136..abac6d8d6b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc @@ -45,7 +45,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryStoreNamedAttribute &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first; bNodeSocket *socket_name = socket_geometry->next; @@ -69,7 +69,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) search_link_ops_for_declarations(params, declaration.inputs().take_front(2)); if (params.in_out() == SOCK_OUT) { - const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type( static_cast<eNodeSocketDatatype>(params.other_socket().type)); if (type && *type != CD_PROP_STRING) { /* The input and output sockets have the same name. */ @@ -84,7 +84,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) static void try_capture_field_on_geometry(GeometryComponent &component, const StringRef name, - const AttributeDomain domain, + const eAttrDomain domain, const GField &field) { GeometryComponentFieldContext field_context{component, domain}; @@ -92,7 +92,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component, const IndexMask mask{IndexMask(domain_num)}; const CPPType &type = field.cpp_type(); - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(type); + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type); /* Could avoid allocating a new buffer if: * - We are writing to an attribute that exists already. @@ -118,7 +118,9 @@ static void try_capture_field_on_geometry(GeometryComponent &component, MEM_freeN(buffer); } else { - component.attribute_try_create(name, domain, data_type, AttributeInitMove{buffer}); + if (!component.attribute_try_create(name, domain, data_type, AttributeInitMove{buffer})) { + MEM_freeN(buffer); + } } } @@ -131,12 +133,17 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); return; } + if (!bke::allow_procedural_attribute_access(name)) { + params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message)); + params.set_output("Geometry", std::move(geometry_set)); + return; + } - params.used_named_attribute(name, NamedAttributeUsage::Write); + params.used_named_attribute(name, eNamedAttrUsage::Write); const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node()); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); + const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain); GField field; switch (data_type) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc index dca214660c8..0af6c76feaf 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc @@ -81,7 +81,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryTransferAttribute &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode) storage.mode; @@ -123,7 +123,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) search_link_ops_for_declarations(params, declaration.inputs().take_back(2)); search_link_ops_for_declarations(params, declaration.inputs().take_front(1)); - const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type( (eNodeSocketDatatype)params.other_socket().type); if (type && *type != CD_PROP_STRING) { /* The input and output sockets have the same name. */ @@ -356,7 +356,7 @@ void copy_with_indices_and_comparison(const VArray<T> &src_1, static bool component_is_available(const GeometrySet &geometry, const GeometryComponentType type, - const AttributeDomain domain) + const eAttrDomain domain) { if (!geometry.has(type)) { return false; @@ -383,7 +383,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction { * future, it should be possible to use the most complex domain required by the field inputs, to * simplify sampling and avoid domain conversions. */ - AttributeDomain domain_ = ATTR_DOMAIN_CORNER; + eAttrDomain domain_ = ATTR_DOMAIN_CORNER; fn::MFSignature signature_; @@ -449,7 +449,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction { class NearestTransferFunction : public fn::MultiFunction { GeometrySet source_; GField src_field_; - AttributeDomain domain_; + eAttrDomain domain_; fn::MFSignature signature_; @@ -466,7 +466,7 @@ class NearestTransferFunction : public fn::MultiFunction { const GVArray *point_data_; public: - NearestTransferFunction(GeometrySet geometry, GField src_field, AttributeDomain domain) + NearestTransferFunction(GeometrySet geometry, GField src_field, eAttrDomain domain) : source_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain) { source_.ensure_owns_direct_data(); @@ -599,7 +599,7 @@ class NearestTransferFunction : public fn::MultiFunction { }; static const GeometryComponent *find_source_component(const GeometrySet &geometry, - const AttributeDomain domain) + const eAttrDomain domain) { /* Choose the other component based on a consistent order, rather than some more complicated * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */ @@ -624,7 +624,7 @@ static const GeometryComponent *find_source_component(const GeometrySet &geometr class IndexTransferFunction : public fn::MultiFunction { GeometrySet src_geometry_; GField src_field_; - AttributeDomain domain_; + eAttrDomain domain_; fn::MFSignature signature_; @@ -633,7 +633,7 @@ class IndexTransferFunction : public fn::MultiFunction { const GVArray *src_data_ = nullptr; public: - IndexTransferFunction(GeometrySet geometry, GField src_field, const AttributeDomain domain) + IndexTransferFunction(GeometrySet geometry, GField src_field, const eAttrDomain domain) : src_geometry_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain) { src_geometry_.ensure_owns_direct_data(); @@ -684,7 +684,7 @@ class IndexTransferFunction : public fn::MultiFunction { } }; -static GField get_input_attribute_field(GeoNodeExecParams ¶ms, const CustomDataType data_type) +static GField get_input_attribute_field(GeoNodeExecParams ¶ms, const eCustomDataType data_type) { switch (data_type) { case CD_PROP_FLOAT: @@ -737,8 +737,8 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeGeometryTransferAttribute &storage = node_storage(params.node()); const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode) storage.mode; - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); + const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain); GField field = get_input_attribute_field(params, data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index 8e9d7b0e46d..6979693e215 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -39,7 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } -static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType type) +static eNodeSocketDatatype custom_data_type_to_socket_type(const eCustomDataType type) { switch (type) { case CD_PROP_FLOAT: @@ -61,7 +61,7 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryViewer &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type); LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { @@ -82,7 +82,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node); }; - const std::optional<CustomDataType> type = node_socket_to_custom_data_type( + const std::optional<eCustomDataType> type = node_socket_to_custom_data_type( params.other_socket()); if (params.in_out() == SOCK_OUT) { /* The viewer node only has inputs. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc new file mode 100644 index 00000000000..d7e9e38ea0d --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifdef WITH_OPENVDB +# include <openvdb/openvdb.h> +# include <openvdb/tools/Dense.h> +# include <openvdb/tools/LevelSetUtil.h> +# include <openvdb/tools/ParticlesToLevelSet.h> +#endif + +#include "node_geometry_util.hh" + +#include "DNA_mesh_types.h" + +#include "BLI_task.hh" + +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" +#include "BKE_volume.h" + +namespace blender::nodes::node_geo_volume_cube_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Density")) + .description(N_("Volume density per voxel")) + .supports_field() + .default_value(1.0f); + b.add_input<decl::Float>(N_("Background")) + .description(N_("Value for voxels outside of the cube")); + + b.add_input<decl::Vector>(N_("Min")) + .description(N_("Minimum boundary of volume")) + .default_value(float3(-1.0f)); + b.add_input<decl::Vector>(N_("Max")) + .description(N_("Maximum boundary of volume")) + .default_value(float3(1.0f)); + + b.add_input<decl::Int>(N_("Resolution X")) + .description(N_("Number of voxels in the X axis")) + .default_value(32) + .min(2); + b.add_input<decl::Int>(N_("Resolution Y")) + .description(N_("Number of voxels in the Y axis")) + .default_value(32) + .min(2); + b.add_input<decl::Int>(N_("Resolution Z")) + .description(N_("Number of voxels in the Z axis")) + .default_value(32) + .min(2); + + b.add_output<decl::Geometry>(N_("Volume")); +} + +static float map(const float x, + const float in_min, + const float in_max, + const float out_min, + const float out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +class Grid3DFieldContext : public FieldContext { + private: + int3 resolution_; + float3 bounds_min_; + float3 bounds_max_; + + public: + Grid3DFieldContext(const int3 resolution, const float3 bounds_min, const float3 bounds_max) + : resolution_(resolution), bounds_min_(bounds_min), bounds_max_(bounds_max) + { + } + + int64_t points_num() const + { + return static_cast<int64_t>(resolution_.x) * static_cast<int64_t>(resolution_.y) * + static_cast<int64_t>(resolution_.z); + } + + GVArray get_varray_for_input(const FieldInput &field_input, + const IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const + { + const bke::AttributeFieldInput *attribute_field_input = + dynamic_cast<const bke::AttributeFieldInput *>(&field_input); + if (attribute_field_input == nullptr) { + return {}; + } + if (attribute_field_input->attribute_name() != "position") { + return {}; + } + + Array<float3> positions(this->points_num()); + + threading::parallel_for(IndexRange(resolution_.x), 1, [&](const IndexRange x_range) { + /* Start indexing at current X slice. */ + int64_t index = x_range.start() * resolution_.y * resolution_.z; + for (const int64_t x_i : x_range) { + const float x = map(x_i, 0.0f, resolution_.x - 1, bounds_min_.x, bounds_max_.x); + for (const int64_t y_i : IndexRange(resolution_.y)) { + const float y = map(y_i, 0.0f, resolution_.y - 1, bounds_min_.y, bounds_max_.y); + for (const int64_t z_i : IndexRange(resolution_.z)) { + const float z = map(z_i, 0.0f, resolution_.z - 1, bounds_min_.z, bounds_max_.z); + positions[index] = float3(x, y, z); + index++; + } + } + } + }); + return VArray<float3>::ForContainer(std::move(positions)); + } +}; + +#ifdef WITH_OPENVDB +static void node_geo_exec(GeoNodeExecParams params) +{ + const float3 bounds_min = params.extract_input<float3>("Min"); + const float3 bounds_max = params.extract_input<float3>("Max"); + + const int3 resolution = int3(params.extract_input<int>("Resolution X"), + params.extract_input<int>("Resolution Y"), + params.extract_input<int>("Resolution Z")); + + if (resolution.x < 2 || resolution.y < 2 || resolution.z < 2) { + params.error_message_add(NodeWarningType::Error, TIP_("Resolution must be greater than 1")); + params.set_default_remaining_outputs(); + return; + } + + if (bounds_min.x == bounds_max.x || bounds_min.y == bounds_max.y || + bounds_min.z == bounds_max.z) { + params.error_message_add(NodeWarningType::Error, + TIP_("Bounding box volume must be greater than 0")); + params.set_default_remaining_outputs(); + return; + } + + Field<float> input_field = params.extract_input<Field<float>>("Density"); + + /* Evaluate input field on a 3D grid. */ + Grid3DFieldContext context(resolution, bounds_min, bounds_max); + FieldEvaluator evaluator(context, context.points_num()); + Array<float> densities(context.points_num()); + evaluator.add_with_destination(std::move(input_field), densities.as_mutable_span()); + evaluator.evaluate(); + + /* Store resulting values in openvdb grid. */ + const float background = params.extract_input<float>("Background"); + openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(background); + grid->setGridClass(openvdb::GRID_FOG_VOLUME); + + openvdb::tools::Dense<float, openvdb::tools::LayoutZYX> dense_grid{ + openvdb::math::CoordBBox({0, 0, 0}, {resolution.x - 1, resolution.y - 1, resolution.z - 1}), + densities.data()}; + openvdb::tools::copyFromDense(dense_grid, *grid, 0.0f); + + grid->transform().preTranslate(openvdb::math::Vec3<float>(-0.5f)); + const float3 scale_fac = (bounds_max - bounds_min) / float3(resolution - 1); + grid->transform().postScale(openvdb::math::Vec3<float>(scale_fac.x, scale_fac.y, scale_fac.z)); + grid->transform().postTranslate( + openvdb::math::Vec3<float>(bounds_min.x, bounds_min.y, bounds_min.z)); + + Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr); + BKE_volume_init_grids(volume); + + BKE_volume_grid_add_vdb(*volume, "density", std::move(grid)); + + GeometrySet r_geometry_set; + r_geometry_set.replace_volume(volume); + params.set_output("Volume", r_geometry_set); +} + +#else +static void node_geo_exec(GeoNodeExecParams params) +{ + params.error_message_add(NodeWarningType::Error, + TIP_("Disabled, Blender was compiled without OpenVDB")); + params.set_default_remaining_outputs(); +} +#endif /* WITH_OPENVDB */ + +} // namespace blender::nodes::node_geo_volume_cube_cc + +void register_node_type_geo_volume_cube() +{ + namespace file_ns = blender::nodes::node_geo_volume_cube_cc; + + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_VOLUME_CUBE, "Volume Cube", NODE_CLASS_GEOMETRY); + + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index e5827c24320..e1d1c67b8c8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -41,7 +41,9 @@ static void node_declare(NodeDeclarationBuilder &b) .make_available([](bNode &node) { node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT; }); - b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f); + b.add_input<decl::Float>(N_("Threshold")) + .default_value(0.1f) + .description(N_("Values larger than the threshold are inside the generated mesh")); b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR); b.add_output<decl::Geometry>(N_("Mesh")); } @@ -151,6 +153,16 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam } const bke::VolumeToMeshResolution resolution = get_resolution_param(params); + + if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE && + resolution.settings.voxel_size <= 0.0f) { + return nullptr; + } + if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT && + resolution.settings.voxel_amount <= 0) { + return nullptr; + } + const Main *bmain = DEG_get_bmain(params.depsgraph()); BKE_volume_load(volume, bmain); diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 9a316190720..85dfdf03b82 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -495,7 +495,7 @@ void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds ex void LocalGeoLogger::log_used_named_attribute(DNode node, std::string attribute_name, - NamedAttributeUsage usage) + eNamedAttrUsage usage) { used_named_attributes_.append({node, {std::move(attribute_name), usage}}); } diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index abbfe4b823d..b7c5f9570e4 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -156,7 +156,8 @@ static void group_verify_socket_list(bNodeTree &node_tree, bNode &node, const ListBase &interface_sockets, ListBase &verify_lb, - const eNodeSocketInOut in_out) + const eNodeSocketInOut in_out, + const bool ensure_extend_socket_exists) { ListBase old_sockets = verify_lb; BLI_listbase_clear(&verify_lb); @@ -177,6 +178,17 @@ static void group_verify_socket_list(bNodeTree &node_tree, } } + if (ensure_extend_socket_exists) { + bNodeSocket *last_socket = static_cast<bNodeSocket *>(old_sockets.last); + if (last_socket != nullptr && STREQ(last_socket->identifier, "__extend__")) { + BLI_remlink(&old_sockets, last_socket); + BLI_addtail(&verify_lb, last_socket); + } + else { + nodeAddSocket(&node_tree, &node, in_out, "NodeSocketVirtual", "__extend__", ""); + } + } + /* Remove leftover sockets that didn't match the node group's interface. */ LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) { nodeRemoveSocket(&node_tree, &node, unused_socket); @@ -195,8 +207,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node) } else { bNodeTree *ngroup = (bNodeTree *)node->id; - group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN); - group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT); + group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN, false); + group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT, false); } } @@ -484,15 +496,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node) } BLI_freelistN(&tmplinks); - - /* check inputs and outputs, and remove or insert them */ - { - /* value_in_out inverted for interface nodes to get correct socket value_property */ - group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT); - - /* add virtual extension socket */ - nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", ""); - } + group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT, true); } void register_node_type_group_input() @@ -582,15 +586,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node) } BLI_freelistN(&tmplinks); - - /* check inputs and outputs, and remove or insert them */ - { - /* value_in_out inverted for interface nodes to get correct socket value_property */ - group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN); - - /* add virtual extension socket */ - nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", ""); - } + group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN, true); } void register_node_type_group_output() diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 9aee3ddcce7..56e9c9f0496 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -24,7 +24,7 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin } void GeoNodeExecParams::used_named_attribute(std::string attribute_name, - const NamedAttributeUsage usage) + const eNamedAttrUsage usage) { if (provider_->logger == nullptr) { return; @@ -110,137 +110,6 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name return nullptr; } -GVArray GeoNodeExecParams::get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const -{ - const bNodeSocket *found_socket = this->find_available_socket(name); - BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ - const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type); - const int64_t domain_num = component.attribute_domain_num(domain); - - if (default_value == nullptr) { - default_value = cpp_type->default_value(); - } - - if (found_socket == nullptr) { - return GVArray::ForSingle(*cpp_type, domain_num, default_value); - } - - if (found_socket->type == SOCK_STRING) { - const std::string name = this->get_input<std::string>(found_socket->identifier); - /* Try getting the attribute without the default value. */ - GVArray attribute = component.attribute_try_get_for_read(name, domain, type); - if (attribute) { - return attribute; - } - - /* If the attribute doesn't exist, use the default value and output an error message - * (except when the field is empty, to avoid spamming error messages, and not when - * the domain is empty and we don't expect an attribute anyway). */ - if (!name.empty() && component.attribute_domain_num(domain) != 0) { - this->error_message_add(NodeWarningType::Error, - TIP_("No attribute with name \"") + name + "\""); - } - return GVArray::ForSingle(*cpp_type, domain_num, default_value); - } - const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); - if (found_socket->type == SOCK_FLOAT) { - const float value = this->get_input<float>(found_socket->identifier); - BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); - conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer); - return GVArray::ForSingle(*cpp_type, domain_num, buffer); - } - if (found_socket->type == SOCK_INT) { - const int value = this->get_input<int>(found_socket->identifier); - BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); - conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer); - return GVArray::ForSingle(*cpp_type, domain_num, buffer); - } - if (found_socket->type == SOCK_VECTOR) { - const float3 value = this->get_input<float3>(found_socket->identifier); - BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); - conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer); - return GVArray::ForSingle(*cpp_type, domain_num, buffer); - } - if (found_socket->type == SOCK_RGBA) { - const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier); - BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); - conversions.convert_to_uninitialized( - CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer); - return GVArray::ForSingle(*cpp_type, domain_num, buffer); - } - BLI_assert(false); - return GVArray::ForSingle(*cpp_type, domain_num, default_value); -} - -CustomDataType GeoNodeExecParams::get_input_attribute_data_type( - const StringRef name, - const GeometryComponent &component, - const CustomDataType default_type) const -{ - const bNodeSocket *found_socket = this->find_available_socket(name); - BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ - if (found_socket == nullptr) { - return default_type; - } - - if (found_socket->type == SOCK_STRING) { - const std::string name = this->get_input<std::string>(found_socket->identifier); - std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name); - if (info) { - return info->data_type; - } - return default_type; - } - if (found_socket->type == SOCK_FLOAT) { - return CD_PROP_FLOAT; - } - if (found_socket->type == SOCK_VECTOR) { - return CD_PROP_FLOAT3; - } - if (found_socket->type == SOCK_RGBA) { - return CD_PROP_COLOR; - } - if (found_socket->type == SOCK_BOOLEAN) { - return CD_PROP_BOOL; - } - - BLI_assert(false); - return default_type; -} - -AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain( - Span<std::string> names, - const GeometryComponent &component, - const AttributeDomain default_domain) const -{ - Vector<AttributeDomain, 8> input_domains; - for (const std::string &name : names) { - const bNodeSocket *found_socket = this->find_available_socket(name); - BLI_assert(found_socket != nullptr); /* A socket should be available socket for the name. */ - if (found_socket == nullptr) { - continue; - } - - if (found_socket->type == SOCK_STRING) { - const std::string name = this->get_input<std::string>(found_socket->identifier); - std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name); - if (info) { - input_domains.append(info->domain); - } - } - } - - if (input_domains.size() > 0) { - return bke::attribute_domain_highest_priority(input_domains); - } - - return default_domain; -} - std::string GeoNodeExecParams::attribute_producer_name() const { return provider_->dnode->label_or_name() + TIP_(" node"); diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index f107ec73c60..24558e4b32b 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -1007,6 +1007,7 @@ static void ntree_shader_pruned_unused(bNodeTree *ntree, bNode *output_node) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == SH_NODE_OUTPUT_AOV) { + node->tmp_flag = 1; nodeChainIterBackwards(ntree, node, ntree_branch_node_tag, nullptr, 0); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index a487e07bd5a..5fc69987c67 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -53,7 +53,7 @@ static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), Po static int node_shader_map_range_ui_class(const bNode *node) { const NodeMapRange &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); if (data_type == CD_PROP_FLOAT3) { return NODE_CLASS_OP_VECTOR; } @@ -63,7 +63,7 @@ static int node_shader_map_range_ui_class(const bNode *node) static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { const NodeMapRange &storage = node_storage(*node); - const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type); const int type = (data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR; Array<bool> new_input_availability(BLI_listbase_count(&node->inputs)); @@ -108,7 +108,7 @@ static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) class SocketSearchOp { public: std::string socket_name; - CustomDataType data_type; + eCustomDataType data_type; int interpolation_type = NODE_MAP_RANGE_LINEAR; void operator()(LinkSearchOpParams ¶ms) @@ -120,7 +120,7 @@ class SocketSearchOp { } }; -static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket) { switch (socket.type) { case SOCK_FLOAT: @@ -137,7 +137,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock static void node_map_range_gather_link_searches(GatherLinkSearchOpParams ¶ms) { - const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket()); if (!type) { return; } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index 94a6febe92e..d4413036555 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -48,16 +48,36 @@ class MF_SeparateXYZ : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "XYZ"); - MutableSpan<float> xs = params.uninitialized_single_output<float>(1, "X"); - MutableSpan<float> ys = params.uninitialized_single_output<float>(2, "Y"); - MutableSpan<float> zs = params.uninitialized_single_output<float>(3, "Z"); - - for (int64_t i : mask) { - float3 xyz = vectors[i]; - xs[i] = xyz.x; - ys[i] = xyz.y; - zs[i] = xyz.z; + MutableSpan<float> xs = params.uninitialized_single_output_if_required<float>(1, "X"); + MutableSpan<float> ys = params.uninitialized_single_output_if_required<float>(2, "Y"); + MutableSpan<float> zs = params.uninitialized_single_output_if_required<float>(3, "Z"); + + std::array<MutableSpan<float>, 3> outputs = {xs, ys, zs}; + Vector<int> used_outputs; + if (!xs.is_empty()) { + used_outputs.append(0); } + if (!ys.is_empty()) { + used_outputs.append(1); + } + if (!zs.is_empty()) { + used_outputs.append(2); + } + + devirtualize_varray(vectors, [&](auto vectors) { + mask.to_best_mask_type([&](auto mask) { + const int used_outputs_num = used_outputs.size(); + const int *used_outputs_data = used_outputs.data(); + + for (const int64_t i : mask) { + const float3 &vector = vectors[i]; + for (const int out_i : IndexRange(used_outputs_num)) { + const int coordinate = used_outputs_data[out_i]; + outputs[coordinate][i] = vector[coordinate]; + } + } + }); + }); } }; diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc index 91d89952da7..53228f0a314 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc +++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc @@ -46,7 +46,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat, NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node->storage); /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MTFACE as geometry nodes may overwrite data which - * will also change the CustomDataType. This will also make EEVEE and Cycles consistent. See + * will also change the eCustomDataType. This will also make EEVEE and Cycles consistent. See * T93179. */ GPUNodeLink *mtface = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->uv_map); diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc index cba944c671c..830f02d8df1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc @@ -43,7 +43,7 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat, { NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage; /* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR for named attributes - * as geometry nodes may overwrite data which will also change the CustomDataType. + * as geometry nodes may overwrite data which will also change the eCustomDataType. * This will also make EEVEE and Cycles * consistent. See T93179. */ diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 903e293a962..03dc61af9a2 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -324,7 +324,6 @@ int ntreeTexExecTree(bNodeTree *ntree, MTex *mtex) { TexCallData data; - float *nor = target->nor; int retval = TEX_INT; bNodeThreadStack *nts = NULL; bNodeTreeExec *exec = ntree->execdata; @@ -356,14 +355,7 @@ int ntreeTexExecTree(bNodeTree *ntree, ntreeExecThreadNodes(exec, nts, &data, thread); ntreeReleaseThreadStack(nts); - if (target->nor) { - retval |= TEX_NOR; - } retval |= TEX_RGB; - /* confusing stuff; the texture output node sets this to NULL to indicate no normal socket was - * set however, the texture code checks this for other reasons - * (namely, a normal is required for material). */ - target->nor = nor; return retval; } diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c index cf5e32cb486..b300ba9ef77 100644 --- a/source/blender/nodes/texture/nodes/node_texture_output.c +++ b/source/blender/nodes/texture/nodes/node_texture_output.c @@ -13,7 +13,6 @@ /* **************** COMPOSITE ******************** */ static bNodeSocketTemplate inputs[] = { {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f}, - {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_DIRECTION}, {-1, ""}, }; @@ -32,12 +31,7 @@ static void exec(void *data, TexParams params; params_from_cdata(¶ms, cdata); - if (in[1] && in[1]->hasinput && !in[0]->hasinput) { - tex_input_rgba(target->trgba, in[1], ¶ms, cdata->thread); - } - else { - tex_input_rgba(target->trgba, in[0], ¶ms, cdata->thread); - } + tex_input_rgba(target->trgba, in[0], ¶ms, cdata->thread); } else { /* 0 means don't care, so just use first */ @@ -49,15 +43,6 @@ static void exec(void *data, target->tin = (target->trgba[0] + target->trgba[1] + target->trgba[2]) / 3.0f; target->talpha = true; - - if (target->nor) { - if (in[1] && in[1]->hasinput) { - tex_input_vec(target->nor, in[1], ¶ms, cdata->thread); - } - else { - target->nor = NULL; - } - } } } } diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c index fd7e6fdfc7f..d925c9f3554 100644 --- a/source/blender/nodes/texture/nodes/node_texture_proc.c +++ b/source/blender/nodes/texture/nodes/node_texture_proc.c @@ -14,10 +14,8 @@ * In this file: wrappers to use procedural textures as nodes */ -static bNodeSocketTemplate outputs_both[] = { - {SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f}, - {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_DIRECTION}, - {-1, ""}}; +static bNodeSocketTemplate outputs_both[] = {{SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f}, + {-1, ""}}; static bNodeSocketTemplate outputs_color_only[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}}; /* Inputs common to all, #defined because nodes will need their own inputs too */ @@ -34,27 +32,15 @@ static void do_proc(float *result, TexParams *p, const float col1[4], const float col2[4], - char is_normal, Tex *tex, const short thread) { TexResult texres; int textype; - if (is_normal) { - texres.nor = result; - } - else { - texres.nor = NULL; - } - textype = multitex_nodes( tex, p->co, p->dxt, p->dyt, p->osatex, &texres, thread, 0, p->mtex, NULL); - if (is_normal) { - return; - } - if (textype & TEX_RGB) { copy_v4_v4(result, texres.trgba); } @@ -66,13 +52,8 @@ static void do_proc(float *result, typedef void (*MapFn)(Tex *tex, bNodeStack **in, TexParams *p, const short thread); -static void texfn(float *result, - TexParams *p, - bNode *node, - bNodeStack **in, - char is_normal, - MapFn map_inputs, - short thread) +static void texfn( + float *result, TexParams *p, bNode *node, bNodeStack **in, MapFn map_inputs, short thread) { Tex tex = *((Tex *)(node->storage)); float col1[4], col2[4]; @@ -81,7 +62,7 @@ static void texfn(float *result, map_inputs(&tex, in, p, thread); - do_proc(result, p, col1, col2, is_normal, &tex, thread); + do_proc(result, p, col1, col2, &tex, thread); } static int count_outputs(bNode *node) @@ -106,12 +87,7 @@ static int count_outputs(bNode *node) static void name##_colorfn( \ float *result, TexParams *p, bNode *node, bNodeStack **in, short thread) \ { \ - texfn(result, p, node, in, 0, &name##_map_inputs, thread); \ - } \ - static void name##_normalfn( \ - float *result, TexParams *p, bNode *node, bNodeStack **in, short thread) \ - { \ - texfn(result, p, node, in, 1, &name##_map_inputs, thread); \ + texfn(result, p, node, in, &name##_map_inputs, thread); \ } \ static void name##_exec(void *data, \ int UNUSED(thread), \ @@ -124,9 +100,6 @@ static int count_outputs(bNode *node) if (outs >= 1) { \ tex_output(node, execdata, in, out[0], &name##_colorfn, data); \ } \ - if (outs >= 2) { \ - tex_output(node, execdata, in, out[1], &name##_normalfn, data); \ - } \ } /* --- VORONOI -- */ diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c index 2d2b4e06665..79cd8bbb1df 100644 --- a/source/blender/nodes/texture/nodes/node_texture_texture.c +++ b/source/blender/nodes/texture/nodes/node_texture_texture.c @@ -45,13 +45,11 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor else if (nodetex) { TexResult texres; int textype; - float nor[] = {0, 0, 0}; float col1[4], col2[4]; tex_input_rgba(col1, in[0], p, thread); tex_input_rgba(col2, in[1], p, thread); - texres.nor = nor; textype = multitex_nodes(nodetex, co, dxt, dyt, p->osatex, &texres, thread, 0, p->mtex, NULL); if (textype & TEX_RGB) { diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c index d45fdc21130..a2075566f31 100644 --- a/source/blender/python/gpu/gpu_py_api.c +++ b/source/blender/python/gpu/gpu_py_api.c @@ -14,8 +14,6 @@ #include "BLI_utildefines.h" -#include "../generic/python_utildefines.h" - #include "gpu_py_capabilities.h" #include "gpu_py_matrix.h" #include "gpu_py_platform.h" @@ -23,7 +21,7 @@ #include "gpu_py_state.h" #include "gpu_py_types.h" -#include "gpu_py_api.h" /* own include */ +#include "gpu_py_api.h" /* Own include. */ /* -------------------------------------------------------------------- */ /** \name GPU Module diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c index 02bcf80aa5d..533e5154d83 100644 --- a/source/blender/python/gpu/gpu_py_batch.c +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -13,14 +13,10 @@ #include <Python.h> -#include "MEM_guardedalloc.h" - #include "BLI_utildefines.h" #include "GPU_batch.h" -#include "../mathutils/mathutils.h" - #include "../generic/py_capi_utils.h" #include "gpu_py.h" diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c index 616e7da6e9f..d52a97c0c84 100644 --- a/source/blender/python/gpu/gpu_py_element.c +++ b/source/blender/python/gpu/gpu_py_element.c @@ -16,7 +16,6 @@ #include "MEM_guardedalloc.h" #include "../generic/py_capi_utils.h" -#include "../generic/python_utildefines.h" #include "gpu_py.h" #include "gpu_py_element.h" /* own include */ diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c index 2a7857b3059..33d9ff0b041 100644 --- a/source/blender/python/gpu/gpu_py_framebuffer.c +++ b/source/blender/python/gpu/gpu_py_framebuffer.c @@ -21,11 +21,9 @@ #include "../mathutils/mathutils.h" #include "gpu_py.h" -#include "gpu_py_texture.h" - -#include "gpu_py.h" #include "gpu_py_buffer.h" #include "gpu_py_framebuffer.h" /* own include */ +#include "gpu_py_texture.h" /* -------------------------------------------------------------------- */ /** \name GPUFrameBuffer Common Utilities diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index b50f536da8a..621c6647cb9 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -13,8 +13,6 @@ #include <Python.h> -#include "MEM_guardedalloc.h" - #include "BLI_string.h" #include "BLI_utildefines.h" @@ -31,7 +29,6 @@ #include "GPU_texture.h" #include "GPU_viewport.h" -#include "ED_view3d.h" #include "ED_view3d_offscreen.h" #include "../mathutils/mathutils.h" diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index 6c5a5bdaaf8..656024ae22c 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -13,7 +13,7 @@ #include "GPU_platform.h" -#include "gpu_py_platform.h" /* own include */ +#include "gpu_py_platform.h" /* Own include. */ /* -------------------------------------------------------------------- */ /** \name Functions diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c index 8e5c172f90c..8869ea38e32 100644 --- a/source/blender/python/gpu/gpu_py_select.c +++ b/source/blender/python/gpu/gpu_py_select.c @@ -20,7 +20,7 @@ #include "GPU_select.h" -#include "gpu_py_select.h" /* own include */ +#include "gpu_py_select.h" /* Own include. */ /* -------------------------------------------------------------------- */ /** \name Methods diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index d7369731a98..101b9f8e4c6 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -16,7 +16,6 @@ #include "GPU_uniform_buffer.h" #include "../generic/py_capi_utils.h" -#include "../generic/python_utildefines.h" #include "../mathutils/mathutils.h" #include "gpu_py.h" diff --git a/source/blender/python/gpu/gpu_py_shader_create_info.cc b/source/blender/python/gpu/gpu_py_shader_create_info.cc index 3b043c605fa..e00d01174f4 100644 --- a/source/blender/python/gpu/gpu_py_shader_create_info.cc +++ b/source/blender/python/gpu/gpu_py_shader_create_info.cc @@ -15,7 +15,6 @@ #include "intern/gpu_shader_create_info.hh" #include "../generic/py_capi_utils.h" -#include "../generic/python_utildefines.h" #include "gpu_py_shader.h" /* own include */ diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c index 65201df4a9e..eccbebbd8dd 100644 --- a/source/blender/python/gpu/gpu_py_types.c +++ b/source/blender/python/gpu/gpu_py_types.c @@ -10,7 +10,6 @@ #include <Python.h> #include "../generic/py_capi_utils.h" -#include "../generic/python_utildefines.h" #include "gpu_py_types.h" /* own include */ diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c index f8f88d61cf6..dcf9ab76470 100644 --- a/source/blender/python/gpu/gpu_py_uniformbuffer.c +++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c @@ -14,13 +14,11 @@ #include "BLI_string.h" #include "GPU_context.h" -#include "GPU_texture.h" #include "GPU_uniform_buffer.h" #include "../generic/py_capi_utils.h" #include "gpu_py.h" -#include "gpu_py_buffer.h" #include "gpu_py_uniformbuffer.h" /* own include */ diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c index 3e6695419c0..40a0e5d1e9f 100644 --- a/source/blender/python/gpu/gpu_py_vertex_format.c +++ b/source/blender/python/gpu/gpu_py_vertex_format.c @@ -9,10 +9,6 @@ #include <Python.h> -#include "BLI_math.h" - -#include "MEM_guardedalloc.h" - #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 959fbc7ee98..71138134370 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -232,7 +232,7 @@ if(WITH_IMAGE_TIFF) endif() if(WITH_WEBP) - add_definitions(-DWITH_WEBP) + add_definitions(-DWITH_WEBP) endif() if(WITH_INPUT_NDOF) @@ -310,6 +310,18 @@ if(WITH_OPENCOLLADA) add_definitions(-DWITH_COLLADA) endif() +if(WITH_IO_WAVEFRONT_OBJ) + add_definitions(-DWITH_IO_WAVEFRONT_OBJ) +endif() + +if(WITH_IO_STL) + add_definitions(-DWITH_IO_STL) +endif() + +if(WITH_IO_GPENCIL) + add_definitions(-DWITH_IO_GPENCIL) +endif() + if(WITH_ALEMBIC) add_definitions(-DWITH_ALEMBIC) endif() diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 9d8602d51bd..2e97ae0fc1d 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -23,6 +23,7 @@ #include "BKE_global.h" /* XXX, G_MAIN only */ #include "RNA_access.h" +#include "RNA_enum_types.h" #include "RNA_prototypes.h" #include "RNA_types.h" @@ -456,6 +457,41 @@ static PyObject *bpy_context_members(PyObject *UNUSED(self)) return result; } +/** + * \note only exposed for generating documentation, see: `doc/python_api/sphinx_doc_gen.py`. + */ +PyDoc_STRVAR(bpy_rna_enum_items_static_doc, + ".. function:: rna_enum_items_static()\n" + "\n" + " :return: A dict where the key the name of the enum, the value is a tuple of " + ":class:`bpy.types.EnumPropertyItem`.\n" + " :rtype: dict of \n"); +static PyObject *bpy_rna_enum_items_static(PyObject *UNUSED(self)) +{ +#define DEF_ENUM(id) {STRINGIFY(id), id}, + struct { + const char *id; + const EnumPropertyItem *items; + } enum_info[] = { +#include "RNA_enum_items.h" + }; + PyObject *result = _PyDict_NewPresized(ARRAY_SIZE(enum_info)); + for (int i = 0; i < ARRAY_SIZE(enum_info); i++) { + /* Include all items (including headings & separators), can be shown in documentation. */ + const EnumPropertyItem *items = enum_info[i].items; + const int items_count = RNA_enum_items_count(items); + PyObject *value = PyTuple_New(items_count); + for (int item_index = 0; item_index < items_count; item_index++) { + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_EnumPropertyItem, (void *)&items[item_index], &ptr); + PyTuple_SET_ITEM(value, item_index, pyrna_struct_CreatePyObject(&ptr)); + } + PyDict_SetItemString(result, enum_info[i].id, value); + Py_DECREF(value); + } + return result; +} + static PyMethodDef meth_bpy_script_paths = { "script_paths", (PyCFunction)bpy_script_paths, @@ -510,6 +546,12 @@ static PyMethodDef meth_bpy_context_members = { METH_NOARGS, bpy_context_members_doc, }; +static PyMethodDef meth_bpy_rna_enum_items_static = { + "rna_enum_items_static", + (PyCFunction)bpy_rna_enum_items_static, + METH_NOARGS, + bpy_rna_enum_items_static_doc, +}; static PyObject *bpy_import_test(const char *modname) { @@ -616,6 +658,9 @@ void BPy_init_modules(struct bContext *C) PyModule_AddObject(mod, meth_bpy_context_members.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_context_members, NULL)); + PyModule_AddObject(mod, + meth_bpy_rna_enum_items_static.ml_name, + (PyObject *)PyCFunction_New(&meth_bpy_rna_enum_items_static, NULL)); /* register funcs (bpy_rna.c) */ PyModule_AddObject(mod, diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 621cc79a8db..939473ceaa0 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -36,15 +36,19 @@ #include "BKE_appdir.h" #include "BKE_blender_version.h" #include "BKE_global.h" +#include "BKE_main.h" #include "DNA_ID.h" #include "UI_interface_icons.h" +#include "RNA_enum_types.h" /* For `rna_enum_wm_job_type_items`. */ + /* for notifiers */ #include "WM_api.h" #include "WM_types.h" +#include "../generic/py_capi_rna.h" #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" @@ -450,6 +454,44 @@ static PyGetSetDef bpy_app_getsets[] = { {NULL, NULL, NULL, NULL, NULL}, }; +PyDoc_STRVAR(bpy_app_is_job_running_doc, + ".. staticmethod:: is_job_running(job_type)\n" + "\n" + " Check whether a job of the given type is running.\n" + "\n" + " :arg job_type: job type in :ref:`rna_enum_wm_job_type_items`.\n" + " :type job_type: str\n" + " :return: Whether a job of the given type is currently running.\n" + " :rtype: bool.\n"); +static PyObject *bpy_app_is_job_running(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +{ + struct BPy_EnumProperty_Parse job_type_enum = { + .items = rna_enum_wm_job_type_items, + .value = 0, + }; + static const char *_keywords[] = {"job_type", NULL}; + static _PyArg_Parser _parser = { + "O&" /* `job_type` */ + ":is_job_running", + _keywords, + 0, + }; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, pyrna_enum_value_parse_string, &job_type_enum)) { + return NULL; + } + wmWindowManager *wm = G_MAIN->wm.first; + return PyBool_FromLong(WM_jobs_has_running_type(wm, job_type_enum.value)); +} + +static struct PyMethodDef bpy_app_methods[] = { + {"is_job_running", + (PyCFunction)bpy_app_is_job_running, + METH_VARARGS | METH_KEYWORDS | METH_STATIC, + bpy_app_is_job_running_doc}, + {NULL, NULL, 0, NULL}, +}; + static void py_struct_seq_getset_init(void) { /* tricky dynamic members, not to py-spec! */ @@ -459,6 +501,17 @@ static void py_struct_seq_getset_init(void) Py_DECREF(item); } } + +static void py_struct_seq_method_init(void) +{ + for (PyMethodDef *method = bpy_app_methods; method->ml_name; method++) { + BLI_assert_msg(method->ml_flags & METH_STATIC, "Only static methods make sense for 'bpy.app'"); + PyObject *item = PyCFunction_New(method, NULL); + PyDict_SetItemString(BlenderAppType.tp_dict, method->ml_name, item); + Py_DECREF(item); + } +} + /* end dynamic bpy.app */ PyObject *BPY_app_struct(void) @@ -477,6 +530,7 @@ PyObject *BPY_app_struct(void) /* kindof a hack ontop of PyStructSequence */ py_struct_seq_getset_init(); + py_struct_seq_method_init(); return ret; } diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index beb78753406..fe5111c37f2 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -43,6 +43,9 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {"mod_oceansim", NULL}, {"mod_remesh", NULL}, {"collada", NULL}, + {"io_wavefront_obj", NULL}, + {"io_stl", NULL}, + {"io_gpencil", NULL}, {"opencolorio", NULL}, {"openmp", NULL}, {"openvdb", NULL}, @@ -251,6 +254,24 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif +#ifdef WITH_IO_WAVEFRONT_OBJ + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + +#ifdef WITH_IO_STL + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + +#ifdef WITH_IO_GPENCIL + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + #ifdef WITH_OCIO SetObjIncref(Py_True); #else diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index bf427d9639a..641727927ec 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -66,6 +66,12 @@ static PyStructSequence_Field app_cb_info_fields[] = { {"xr_session_start_pre", "on starting an xr session (before)"}, {"annotation_pre", "on drawing an annotation (before)"}, {"annotation_post", "on drawing an annotation (after)"}, + {"object_bake_pre", "before starting a bake job"}, + {"object_bake_complete", "on completing a bake job; will be called in the main thread"}, + {"object_bake_cancel", "on canceling a bake job; will be called in the main thread"}, + {"composite_pre", "on a compositing background job (before)"}, + {"composite_post", "on a compositing background job (after)"}, + {"composite_cancel", "on a compositing background job (cancel)"}, /* sets the permanent tag */ #define APP_CB_OTHER_FIELDS 1 diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 1ee778ae801..3f2154189e8 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -45,163 +45,34 @@ /** \name Shared Enums & Doc-Strings * \{ */ -static const EnumPropertyItem property_flag_items[] = { - {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, - {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""}, - {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""}, - {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""}, - {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to eachother", ""}, - {PROP_TEXTEDIT_UPDATE, - "TEXTEDIT_UPDATE", - 0, - "Update on every keystroke in textedit 'mode'", - ""}, - {0, NULL, 0, NULL, NULL}, -}; - #define BPY_PROPDEF_OPTIONS_DOC \ - " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', " \ - "'PROPORTIONAL'," \ - "'TEXTEDIT_UPDATE'].\n" \ + " :arg options: Enumerator in :ref:`rna_enum_property_flag_items`.\n" \ " :type options: set\n" -static const EnumPropertyItem property_flag_enum_items[] = { - {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, - {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""}, - {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""}, - {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""}, - {PROP_ENUM_FLAG, "ENUM_FLAG", 0, "Enum Flag", ""}, - {0, NULL, 0, NULL, NULL}, -}; - #define BPY_PROPDEF_OPTIONS_ENUM_DOC \ - " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'ENUM_FLAG', " \ - "'LIBRARY_EDITABLE'].\n" \ + " :arg options: Enumerator in :ref:`rna_enum_property_flag_enum_items`.\n" \ " :type options: set\n" -static const EnumPropertyItem property_flag_override_items[] = { - {PROPOVERRIDE_OVERRIDABLE_LIBRARY, - "LIBRARY_OVERRIDABLE", - 0, - "Library Overridable", - "Make that property editable in library overrides of linked data-blocks"}, - {0, NULL, 0, NULL, NULL}, -}; - #define BPY_PROPDEF_OPTIONS_OVERRIDE_DOC \ - " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE'].\n" \ + " :arg override: Enumerator in :ref:`rna_enum_property_override_flag_items`.\n" \ " :type override: set\n" -static const EnumPropertyItem property_flag_override_collection_items[] = { - {PROPOVERRIDE_OVERRIDABLE_LIBRARY, - "LIBRARY_OVERRIDABLE", - 0, - "Library Overridable", - "Make that property editable in library overrides of linked data-blocks"}, - {PROPOVERRIDE_NO_PROP_NAME, - "NO_PROPERTY_NAME", - 0, - "No Name", - "Do not use the names of the items, only their indices in the collection"}, - {PROPOVERRIDE_LIBRARY_INSERTION, - "USE_INSERTION", - 0, - "Use Insertion", - "Allow users to add new items in that collection in library overrides"}, - {0, NULL, 0, NULL, NULL}, -}; - #define BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC \ - " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE', 'NO_PROPERTY_NAME', " \ - "'USE_INSERTION'].\n" \ + " :arg override: Enumerator in :ref:`rna_enum_property_override_flag_collection_items`.\n" \ " :type override: set\n" -/* subtypes */ -/* Keep in sync with RNA_types.h PropertySubType and rna_rna.c's rna_enum_property_subtype_items */ -static const EnumPropertyItem property_subtype_string_items[] = { - {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""}, - {PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""}, - {PROP_FILENAME, "FILE_NAME", 0, "Filename", ""}, - {PROP_BYTESTRING, "BYTE_STRING", 0, "Byte String", ""}, - {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"}, - - {PROP_NONE, "NONE", 0, "None", ""}, - {0, NULL, 0, NULL, NULL}, -}; - #define BPY_PROPDEF_SUBTYPE_STRING_DOC \ - " :arg subtype: Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILE_NAME', 'BYTE_STRING', " \ - "'PASSWORD', 'NONE'].\n" \ + " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_string_items`.\n" \ " :type subtype: string\n" -static const EnumPropertyItem property_subtype_number_items[] = { - {PROP_PIXEL, "PIXEL", 0, "Pixel", ""}, - {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""}, - {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, - {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, - {PROP_ANGLE, "ANGLE", 0, "Angle", ""}, - {PROP_TIME, - "TIME", - 0, - "Time (Scene Relative)", - "Time specified in frames, converted to seconds based on scene frame rate"}, - {PROP_TIME_ABSOLUTE, - "TIME_ABSOLUTE", - 0, - "Time (Absolute)", - "Time specified in seconds, independent of the scene"}, - {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""}, - {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""}, - {PROP_POWER, "POWER", 0, "Power", ""}, - {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""}, - - {PROP_NONE, "NONE", 0, "None", ""}, - {0, NULL, 0, NULL, NULL}, -}; - #define BPY_PROPDEF_SUBTYPE_NUMBER_DOC \ - " :arg subtype: Enumerator in ['PIXEL', 'UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', " \ - "'TIME', 'DISTANCE', 'DISTANCE_CAMERA', 'POWER', 'TEMPERATURE', 'NONE'].\n" \ + " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_number_items`.\n" \ " :type subtype: string\n" -static const EnumPropertyItem property_subtype_array_items[] = { - {PROP_COLOR, "COLOR", 0, "Color", ""}, - {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""}, - {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""}, - {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""}, - {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""}, - {PROP_MATRIX, "MATRIX", 0, "Matrix", ""}, - {PROP_EULER, "EULER", 0, "Euler", ""}, - {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""}, - {PROP_AXISANGLE, "AXISANGLE", 0, "Axis Angle", ""}, - {PROP_XYZ, "XYZ", 0, "XYZ", ""}, - {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""}, - {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color Gamma", ""}, - {PROP_COORDS, "COORDINATES", 0, "Vector Coordinates", ""}, - {PROP_LAYER, "LAYER", 0, "Layer", ""}, - {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""}, - - {PROP_NONE, "NONE", 0, "None", ""}, - {0, NULL, 0, NULL, NULL}, -}; - -#define BPY_PROPDEF_SUBTYPE_ARRAY_DOC \ - " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', " \ - "'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', " \ - "'XYZ', 'XYZ_LENGTH', 'COLOR_GAMMA', 'COORDINATES', 'LAYER', 'LAYER_MEMBER', 'NONE'].\n" \ +#define BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC \ + " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_number_array_items`.\n" \ " :type subtype: string\n" -static const EnumPropertyItem property_string_search_options_items[] = { - {PROP_STRING_SEARCH_SORT, "SORT", 0, "Sort Search Results", ""}, - {PROP_STRING_SEARCH_SUGGESTION, - "SUGGESTION", - 0, - "Suggestion", - "Search results are suggestions (other values may be entered)"}, - - {0, NULL, 0, NULL, NULL}, -}; - /** \} */ /* -------------------------------------------------------------------- */ @@ -2750,8 +2621,7 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p) " :type description: string\n" #define BPY_PROPDEF_UNIT_DOC \ - " :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', " \ - "'VELOCITY', 'ACCELERATION', 'MASS', 'CAMERA', 'POWER'].\n" \ + " :arg unit: Enumerator in :ref:`rna_enum_property_unit_items`.\n" \ " :type unit: string\n" #define BPY_PROPDEF_NUM_MIN_DOC \ @@ -2900,18 +2770,18 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) bool default_value = false; PropertyRNA *prop; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { .srna = srna, }; struct BPy_EnumProperty_Parse subtype_enum = { - .items = property_subtype_number_items, + .items = rna_enum_property_subtype_number_items, .value = PROP_NONE, }; @@ -3025,7 +2895,7 @@ PyDoc_STRVAR( "\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC " :arg default: sequence of booleans the length of *size*.\n" " :type default: sequence\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC - BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC + BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC); static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { @@ -3048,18 +2918,18 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject PropertyRNA *prop; PyObject *default_py = NULL; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { .srna = srna, }; struct BPy_EnumProperty_Parse subtype_enum = { - .items = property_subtype_array_items, + .items = rna_enum_property_subtype_number_array_items, .value = PROP_NONE, }; PyObject *update_fn = NULL; @@ -3224,18 +3094,18 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) PropertyRNA *prop; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { .srna = srna, }; struct BPy_EnumProperty_Parse subtype_enum = { - .items = property_subtype_number_items, + .items = rna_enum_property_subtype_number_items, .value = PROP_NONE, }; PyObject *update_fn = NULL; @@ -3371,8 +3241,8 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc, " :type soft_min: int\n" BPY_PROPDEF_NUM_SOFTMAX_DOC " :type soft_max: int\n" BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC - BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC - BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC); + BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC + BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC); static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -3397,18 +3267,18 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject PyObject *default_py = NULL; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { .srna = srna, }; struct BPy_EnumProperty_Parse subtype_enum = { - .items = property_subtype_array_items, + .items = rna_enum_property_subtype_number_array_items, .value = PROP_NONE, }; PyObject *update_fn = NULL; @@ -3594,18 +3464,18 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) PropertyRNA *prop; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { .srna = srna, }; struct BPy_EnumProperty_Parse subtype_enum = { - .items = property_subtype_number_items, + .items = rna_enum_property_subtype_number_items, .value = PROP_NONE, }; struct BPy_EnumProperty_Parse unit_enum = { @@ -3739,8 +3609,9 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc, " :type soft_min: float\n" BPY_PROPDEF_NUM_SOFTMAX_DOC " :type soft_max: float\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC - BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_VECSIZE_DOC - BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC); + BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_UNIT_DOC + BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC + BPY_PROPDEF_SET_DOC); static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -3766,18 +3637,18 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec PyObject *default_py = NULL; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { .srna = srna, }; struct BPy_EnumProperty_Parse subtype_enum = { - .items = property_subtype_array_items, + .items = rna_enum_property_subtype_number_array_items, .value = PROP_NONE, }; struct BPy_EnumProperty_Parse unit_enum = { @@ -3955,18 +3826,18 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw PropertyRNA *prop; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { .srna = srna, }; struct BPy_EnumProperty_Parse subtype_enum = { - .items = property_subtype_string_items, + .items = rna_enum_property_subtype_string_items, .value = PROP_NONE, }; PyObject *update_fn = NULL; @@ -3974,7 +3845,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw PyObject *set_fn = NULL; PyObject *search_fn = NULL; static struct BPy_EnumProperty_Parse search_options_enum = { - .items = property_string_search_options_items, + .items = rna_enum_property_string_search_flag_items, .value = PROP_STRING_SEARCH_SUGGESTION, }; @@ -4161,11 +4032,11 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) PropertyRNA *prop; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_enum_items, + .items = rna_enum_property_flag_enum_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { @@ -4384,11 +4255,11 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *type = Py_None; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_items, + .items = rna_enum_property_override_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { @@ -4521,11 +4392,11 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *type = Py_None; struct BPy_EnumProperty_Parse options_enum = { - .items = property_flag_items, + .items = rna_enum_property_flag_items, .value = 0, }; struct BPy_EnumProperty_Parse override_enum = { - .items = property_flag_override_collection_items, + .items = rna_enum_property_override_flag_collection_items, .value = 0, }; struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { diff --git a/source/blender/python/intern/bpy_traceback.c b/source/blender/python/intern/bpy_traceback.c index 45977ba400c..cb93843a6de 100644 --- a/source/blender/python/intern/bpy_traceback.c +++ b/source/blender/python/intern/bpy_traceback.c @@ -165,7 +165,7 @@ finally: bool python_script_error_jump( const char *filepath, int *r_lineno, int *r_offset, int *r_lineno_end, int *r_offset_end) { - /* WARNING(@campbellbarton): The normalized exception is restored (loosing line number info). + /* WARNING(@campbellbarton): The normalized exception is restored (losing line number info). * Ideally this would leave the exception state as it found it, but that needs to be done * carefully with regards to reference counting, see: T97731. */ diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt index 747d6c0e8f8..f355d03cadc 100644 --- a/source/blender/python/mathutils/CMakeLists.txt +++ b/source/blender/python/mathutils/CMakeLists.txt @@ -4,9 +4,9 @@ set(INC . ../../blenkernel ../../blenlib - ../../imbuf ../../bmesh ../../depsgraph + ../../imbuf ../../makesdna ../../../../intern/guardedalloc ) diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py index 61df784336c..b4e23547c62 100644 --- a/source/blender/python/rna_dump.py +++ b/source/blender/python/rna_dump.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# <pep8 compliant> - if 1: # Print once every 1000 GEN_PATH = True diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index 0a8668221ad..548e38d3ef3 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -74,10 +74,12 @@ typedef struct RenderPass { int pad; } RenderPass; -/* a renderlayer is a full image, but with all passes and samples */ -/* size of the rects is defined in RenderResult */ -/* after render, the Combined pass is in combined, - * for renderlayers read from files it is a real pass */ +/** + * - A render-layer is a full image, but with all passes and samples. + * - The size of the rects is defined in #RenderResult. + * - After render, the Combined pass is in combined, + * for render-layers read from files it is a real pass. + */ typedef struct RenderLayer { struct RenderLayer *next, *prev; @@ -247,15 +249,15 @@ void RE_render_result_full_channel_name(char *fullname, const char *passname, const char *viewname, const char *chan_id, - const int channel); + int channel); struct ImBuf *RE_render_result_rect_to_ibuf(struct RenderResult *rr, const struct ImageFormatData *imf, const float dither, - const int view_id); + int view_id); void RE_render_result_rect_from_ibuf(struct RenderResult *rr, const struct ImBuf *ibuf, - const int view_id); + int view_id); struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname); diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h index be50eacd7bf..a4e30c917d5 100644 --- a/source/blender/render/RE_texture.h +++ b/source/blender/render/RE_texture.h @@ -44,8 +44,6 @@ bool RE_texture_evaluate(const struct MTex *mtex, * \param fact: Texture strength. * \param facg: Button strength value. */ -void texture_rgb_blend( - float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype); float texture_value_blend(float tex, float out, float fact, float facg, int blendtype); void RE_texture_rng_init(void); @@ -89,7 +87,6 @@ typedef struct TexResult { float trgba[4]; /* Is actually a boolean: When true -> use alpha, false -> set alpha to 1.0. */ int talpha; - float *nor; } TexResult; /* This one uses nodes. */ diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h index 0c91abeaddd..023615cea87 100644 --- a/source/blender/render/RE_texture_margin.h +++ b/source/blender/render/RE_texture_margin.h @@ -27,16 +27,13 @@ struct Mesh; */ void RE_generate_texturemargin_adjacentfaces(struct ImBuf *ibuf, char *mask, - const int margin, + int margin, struct Mesh const *me, char const *uv_layer, const float uv_offset[2]); -void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf, - char *mask, - const int margin, - struct DerivedMesh *dm, - const float uv_offset[2]); +void RE_generate_texturemargin_adjacentfaces_dm( + struct ImBuf *ibuf, char *mask, int margin, struct DerivedMesh *dm, const float uv_offset[2]); #ifdef __cplusplus } diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 43497fb8318..075f1ece647 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -981,7 +981,7 @@ static void render_result_uncrop(Render *re) render_result_free(re->result); re->result = rres; - /* weak... the display callback wants an active renderlayer pointer... */ + /* Weak, the display callback wants an active render-layer pointer. */ re->result->renlay = render_get_active_layer(re, re->result); BLI_rw_mutex_unlock(&re->resultmutex); @@ -1313,8 +1313,8 @@ static void do_render_sequencer(Render *re) true, &context); - /* the renderresult gets destroyed during the rendering, so we first collect all ibufs - * and then we populate the final renderesult */ + /* The render-result gets destroyed during the rendering, so we first collect all ibufs + * and then we populate the final render-result. */ for (view_id = 0; view_id < tot_views; view_id++) { context.view_id = view_id; diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index 9f4aa642773..9992d1a507f 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -825,7 +825,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) if (rpass->rect == NULL || rpassp->rect == NULL) { continue; } - /* Renderresult have all passes, renderpart only the active view's passes. */ + /* Render-result have all passes, render-part only the active view's passes. */ if (!STREQ(rpassp->fullname, rpass->fullname)) { continue; } diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h index 30f49775562..c84e0a04018 100644 --- a/source/blender/render/intern/render_result.h +++ b/source/blender/render/intern/render_result.h @@ -44,7 +44,7 @@ struct RenderResult *render_result_new(struct Render *re, void render_result_passes_allocated_ensure(struct RenderResult *rr); /** - * From imbuf, if a handle was returned and + * From `imbuf`, if a handle was returned and * it's not a single-layer multi-view we convert this to render result. */ struct RenderResult *render_result_new_from_exr( diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c index 3b1eb293a3a..7da9e7c3d58 100644 --- a/source/blender/render/intern/texture_image.c +++ b/source/blender/render/intern/texture_image.c @@ -88,14 +88,13 @@ int imagewrap(Tex *tex, struct ImagePool *pool, const bool skip_load_image) { - float fx, fy, val1, val2, val3; + float fx, fy; int x, y, retval; int xi, yi; /* original values */ texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f; - /* we need to set retval OK, otherwise texture code generates normals itself... */ - retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB; + retval = TEX_RGB; /* quick tests */ if (ima == NULL) { @@ -256,47 +255,6 @@ int imagewrap(Tex *tex, ibuf_get_color(texres->trgba, ibuf, x, y); } - if (texres->nor) { - if (tex->imaflag & TEX_NORMALMAP) { - /* Normal from color: - * The invert of the red channel is to make - * the normal map compliant with the outside world. - * It needs to be done because in Blender - * the normal used in the renderer points inward. It is generated - * this way in calc_vertexnormals(). Should this ever change - * this negate must be removed. */ - texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f); - texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f); - texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f); - } - else { - /* bump: take three samples */ - val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2]; - - if (x < ibuf->x - 1) { - float col[4]; - ibuf_get_color(col, ibuf, x + 1, y); - val2 = (col[0] + col[1] + col[2]); - } - else { - val2 = val1; - } - - if (y < ibuf->y - 1) { - float col[4]; - ibuf_get_color(col, ibuf, x, y + 1); - val3 = (col[0] + col[1] + col[2]); - } - else { - val3 = val1; - } - - /* do not mix up x and y here! */ - texres->nor[0] = (val1 - val2); - texres->nor[1] = (val1 - val3); - } - } - if (texres->talpha) { texres->tin = texres->trgba[3]; } @@ -989,7 +947,7 @@ static int imagewraposa_aniso(Tex *tex, { TexResult texr; float fx, fy, minx, maxx, miny, maxy; - float maxd, val1, val2, val3; + float maxd; int curmap, retval, intpol, extflag = 0; afdata_t AFD; @@ -1008,8 +966,7 @@ static int imagewraposa_aniso(Tex *tex, texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f; - /* we need to set retval OK, otherwise texture code generates normals itself... */ - retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB; + retval = TEX_RGB; /* quick tests */ if (ibuf == NULL && ima == NULL) { @@ -1040,7 +997,7 @@ static int imagewraposa_aniso(Tex *tex, if (ima) { if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { - texres->talpha = 1; + texres->talpha = true; } } } @@ -1301,48 +1258,17 @@ static int imagewraposa_aniso(Tex *tex, } /* filter functions take care of interpolation themselves, no need to modify dxt/dyt here */ - - if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) { - /* color & normal */ - filterfunc(texres, curibuf, fx, fy, &AFD); - val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2]; - filterfunc(&texr, curibuf, fx + dxt[0], fy + dxt[1], &AFD); - val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - filterfunc(&texr, curibuf, fx + dyt[0], fy + dyt[1], &AFD); - val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - /* don't switch x or y! */ - texres->nor[0] = val1 - val2; - texres->nor[1] = val1 - val3; - if (previbuf != curibuf) { /* interpolate */ - filterfunc(&texr, previbuf, fx, fy, &AFD); - /* rgb */ - texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]); - texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]); - texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]); - texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]); - /* normal */ - val1 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val1); - filterfunc(&texr, previbuf, fx + dxt[0], fy + dxt[1], &AFD); - val2 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val2); - filterfunc(&texr, previbuf, fx + dyt[0], fy + dyt[1], &AFD); - val3 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val3); - texres->nor[0] = val1 - val2; /* vals have been interpolated above! */ - texres->nor[1] = val1 - val3; - } + filterfunc(texres, curibuf, fx, fy, &AFD); + if (previbuf != curibuf) { /* interpolate */ + filterfunc(&texr, previbuf, fx, fy, &AFD); + texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]); + texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]); + texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]); + texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]); } - else { /* color */ - filterfunc(texres, curibuf, fx, fy, &AFD); - if (previbuf != curibuf) { /* interpolate */ - filterfunc(&texr, previbuf, fx, fy, &AFD); - texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]); - texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]); - texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]); - texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]); - } - if (tex->texfilter != TXF_EWA) { - alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres); - } + if (tex->texfilter != TXF_EWA) { + alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres); } } else { /* no mipmap */ @@ -1372,23 +1298,9 @@ static int imagewraposa_aniso(Tex *tex, AFD.dusc = 1.0f / ff; AFD.dvsc = ff / (float)ibuf->y; } - if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) { - /* color & normal */ - filterfunc(texres, ibuf, fx, fy, &AFD); - val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2]; - filterfunc(&texr, ibuf, fx + dxt[0], fy + dxt[1], &AFD); - val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - filterfunc(&texr, ibuf, fx + dyt[0], fy + dyt[1], &AFD); - val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - /* don't switch x or y! */ - texres->nor[0] = val1 - val2; - texres->nor[1] = val1 - val3; - } - else { - filterfunc(texres, ibuf, fx, fy, &AFD); - if (tex->texfilter != TXF_EWA) { - alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres); - } + filterfunc(texres, ibuf, fx, fy, &AFD); + if (tex->texfilter != TXF_EWA) { + alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres); } } @@ -1403,18 +1315,6 @@ static int imagewraposa_aniso(Tex *tex, texres->trgba[3] = 1.0f - texres->trgba[3]; } - if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* normal from color */ - /* The invert of the red channel is to make - * the normal map compliant with the outside world. - * It needs to be done because in Blender - * the normal used in the renderer points inward. It is generated - * this way in calc_vertexnormals(). Should this ever change - * this negate must be removed. */ - texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f); - texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f); - texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f); - } - /* de-premul, this is being pre-multiplied in shade_input_do_shade() * TXF: this currently does not (yet?) work properly, destroys edge AA in clip/checker mode, * so for now commented out also disabled in imagewraposa() @@ -1451,7 +1351,7 @@ int imagewraposa(Tex *tex, { TexResult texr; float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2]; - float maxd, pixsize, val1, val2, val3; + float maxd, pixsize; int curmap, retval, imaprepeat, imapextend; /* TXF: since dxt/dyt might be modified here and since they might be needed after imagewraposa() @@ -1466,8 +1366,7 @@ int imagewraposa(Tex *tex, texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f; - /* we need to set retval OK, otherwise texture code generates normals itself... */ - retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB; + retval = TEX_RGB; /* quick tests */ if (ibuf == NULL && ima == NULL) { @@ -1762,118 +1661,30 @@ int imagewraposa(Tex *tex, } } - if (texres->nor && (tex->imaflag & TEX_NORMALMAP) == 0) { - /* a bit extra filter */ - // minx*= 1.35f; - // miny*= 1.35f; - - boxsample( - curibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend); - val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2]; - boxsample(curibuf, - fx - minx + dxt[0], - fy - miny + dxt[1], - fx + minx + dxt[0], - fy + miny + dxt[1], - &texr, - imaprepeat, - imapextend); - val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - boxsample(curibuf, - fx - minx + dyt[0], - fy - miny + dyt[1], - fx + minx + dyt[0], - fy + miny + dyt[1], - &texr, - imaprepeat, - imapextend); - val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - - /* don't switch x or y! */ - texres->nor[0] = (val1 - val2); - texres->nor[1] = (val1 - val3); - - if (previbuf != curibuf) { /* interpolate */ - - boxsample( - previbuf, fx - minx, fy - miny, fx + minx, fy + miny, &texr, imaprepeat, imapextend); - - /* calc rgb */ - dx = 2.0f * (pixsize - maxd) / pixsize; - if (dx >= 1.0f) { - texres->trgba[3] = texr.trgba[3]; - texres->trgba[2] = texr.trgba[2]; - texres->trgba[1] = texr.trgba[1]; - texres->trgba[0] = texr.trgba[0]; - } - else { - dy = 1.0f - dx; - texres->trgba[2] = dy * texres->trgba[2] + dx * texr.trgba[2]; - texres->trgba[1] = dy * texres->trgba[1] + dx * texr.trgba[1]; - texres->trgba[0] = dy * texres->trgba[0] + dx * texr.trgba[0]; - texres->trgba[3] = dy * texres->trgba[3] + dx * texr.trgba[3]; - } - - val1 = dy * val1 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]); - boxsample(previbuf, - fx - minx + dxt[0], - fy - miny + dxt[1], - fx + minx + dxt[0], - fy + miny + dxt[1], - &texr, - imaprepeat, - imapextend); - val2 = dy * val2 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]); - boxsample(previbuf, - fx - minx + dyt[0], - fy - miny + dyt[1], - fx + minx + dyt[0], - fy + miny + dyt[1], - &texr, - imaprepeat, - imapextend); - val3 = dy * val3 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]); - - texres->nor[0] = (val1 - val2); /* vals have been interpolated above! */ - texres->nor[1] = (val1 - val3); - - if (dx < 1.0f) { - dy = 1.0f - dx; - texres->trgba[2] = dy * texres->trgba[2] + dx * texr.trgba[2]; - texres->trgba[1] = dy * texres->trgba[1] + dx * texr.trgba[1]; - texres->trgba[0] = dy * texres->trgba[0] + dx * texr.trgba[0]; - texres->trgba[3] = dy * texres->trgba[3] + dx * texr.trgba[3]; - } - } - texres->nor[0] *= bumpscale; - texres->nor[1] *= bumpscale; - } - else { - maxx = fx + minx; - minx = fx - minx; - maxy = fy + miny; - miny = fy - miny; + maxx = fx + minx; + minx = fx - minx; + maxy = fy + miny; + miny = fy - miny; - boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend); + boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend); - if (previbuf != curibuf) { /* interpolate */ - boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend); + if (previbuf != curibuf) { /* interpolate */ + boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend); - fx = 2.0f * (pixsize - maxd) / pixsize; + fx = 2.0f * (pixsize - maxd) / pixsize; - if (fx >= 1.0f) { - texres->trgba[3] = texr.trgba[3]; - texres->trgba[2] = texr.trgba[2]; - texres->trgba[1] = texr.trgba[1]; - texres->trgba[0] = texr.trgba[0]; - } - else { - fy = 1.0f - fx; - texres->trgba[2] = fy * texres->trgba[2] + fx * texr.trgba[2]; - texres->trgba[1] = fy * texres->trgba[1] + fx * texr.trgba[1]; - texres->trgba[0] = fy * texres->trgba[0] + fx * texr.trgba[0]; - texres->trgba[3] = fy * texres->trgba[3] + fx * texr.trgba[3]; - } + if (fx >= 1.0f) { + texres->trgba[3] = texr.trgba[3]; + texres->trgba[2] = texr.trgba[2]; + texres->trgba[1] = texr.trgba[1]; + texres->trgba[0] = texr.trgba[0]; + } + else { + fy = 1.0f - fx; + texres->trgba[2] = fy * texres->trgba[2] + fx * texr.trgba[2]; + texres->trgba[1] = fy * texres->trgba[1] + fx * texr.trgba[1]; + texres->trgba[0] = fy * texres->trgba[0] + fx * texr.trgba[0]; + texres->trgba[3] = fy * texres->trgba[3] + fx * texr.trgba[3]; } } } @@ -1889,35 +1700,7 @@ int imagewraposa(Tex *tex, } } - if (texres->nor && (tex->imaflag & TEX_NORMALMAP) == 0) { - boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend); - val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2]; - boxsample(ibuf, - fx - minx + dxt[0], - fy - miny + dxt[1], - fx + minx + dxt[0], - fy + miny + dxt[1], - &texr, - imaprepeat, - imapextend); - val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - boxsample(ibuf, - fx - minx + dyt[0], - fy - miny + dyt[1], - fx + minx + dyt[0], - fy + miny + dyt[1], - &texr, - imaprepeat, - imapextend); - val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2]; - - /* don't switch x or y! */ - texres->nor[0] = (val1 - val2); - texres->nor[1] = (val1 - val3); - } - else { - boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend); - } + boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend); } if (tex->imaflag & TEX_CALCALPHA) { @@ -1932,17 +1715,6 @@ int imagewraposa(Tex *tex, texres->trgba[3] = 1.0f - texres->trgba[3]; } - if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { - /* Normal from color: - * The invert of the red channel is to make the normal map compliant with the outside world. - * It needs to be done because in Blender the normal used in the renderer points inward. - * It is generated this way in #calc_vertexnormals(). - * Should this ever change this negate must be removed. */ - texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f); - texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f); - texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f); - } - /* de-premul, this is being pre-multiplied in shade_input_do_shade() */ /* do not de-premul for generated alpha, it is already in straight */ if (texres->trgba[3] != 1.0f && texres->trgba[3] > 1e-4f && !(tex->imaflag & TEX_CALCALPHA)) { diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c index ce58993b7cf..37605236738 100644 --- a/source/blender/render/intern/texture_procedural.c +++ b/source/blender/render/intern/texture_procedural.c @@ -61,34 +61,6 @@ void RE_texture_rng_exit(void) /* ------------------------------------------------------------------------- */ -/* This allows color-banded textures to control normals as well. */ -static void tex_normal_derivate(const Tex *tex, TexResult *texres) -{ - if (tex->flag & TEX_COLORBAND) { - float col[4]; - if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) { - float fac0, fac1, fac2, fac3; - - fac0 = (col[0] + col[1] + col[2]); - BKE_colorband_evaluate(tex->coba, texres->nor[0], col); - fac1 = (col[0] + col[1] + col[2]); - BKE_colorband_evaluate(tex->coba, texres->nor[1], col); - fac2 = (col[0] + col[1] + col[2]); - BKE_colorband_evaluate(tex->coba, texres->nor[2], col); - fac3 = (col[0] + col[1] + col[2]); - - texres->nor[0] = (fac0 - fac1) / 3.0f; - texres->nor[1] = (fac0 - fac2) / 3.0f; - texres->nor[2] = (fac0 - fac3) / 3.0f; - - return; - } - } - texres->nor[0] = texres->tin - texres->nor[0]; - texres->nor[1] = texres->tin - texres->nor[1]; - texres->nor[2] = texres->tin - texres->nor[2]; -} - static int blend(const Tex *tex, const float texvec[3], TexResult *texres) { float x, y, t; @@ -165,37 +137,7 @@ static int clouds(const Tex *tex, const float texvec[3], TexResult *texres) (tex->noisetype != TEX_NOISESOFT), tex->noisebasis); - if (texres->nor != NULL) { - /* calculate bumpnormal */ - texres->nor[0] = BLI_noise_generic_turbulence(tex->noisesize, - texvec[0] + tex->nabla, - texvec[1], - texvec[2], - tex->noisedepth, - (tex->noisetype != TEX_NOISESOFT), - tex->noisebasis); - texres->nor[1] = BLI_noise_generic_turbulence(tex->noisesize, - texvec[0], - texvec[1] + tex->nabla, - texvec[2], - tex->noisedepth, - (tex->noisetype != TEX_NOISESOFT), - tex->noisebasis); - texres->nor[2] = BLI_noise_generic_turbulence(tex->noisesize, - texvec[0], - texvec[1], - texvec[2] + tex->nabla, - tex->noisedepth, - (tex->noisetype != TEX_NOISESOFT), - tex->noisebasis); - - tex_normal_derivate(tex, texres); - rv |= TEX_NOR; - } - if (tex->stype == TEX_COLOR) { - /* in this case, int. value should really be computed from color, - * and bumpnormal from that, would be too slow, looks ok as is */ texres->trgba[0] = texres->tin; texres->trgba[1] = BLI_noise_generic_turbulence(tex->noisesize, texvec[1], @@ -298,15 +240,6 @@ static int wood(const Tex *tex, const float texvec[3], TexResult *texres) int rv = TEX_INT; texres->tin = wood_int(tex, texvec[0], texvec[1], texvec[2]); - if (texres->nor != NULL) { - /* calculate bumpnormal */ - texres->nor[0] = wood_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]); - texres->nor[1] = wood_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]); - texres->nor[2] = wood_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla); - - tex_normal_derivate(tex, texres); - rv |= TEX_NOR; - } BRICONT; @@ -358,17 +291,6 @@ static int marble(const Tex *tex, const float texvec[3], TexResult *texres) texres->tin = marble_int(tex, texvec[0], texvec[1], texvec[2]); - if (texres->nor != NULL) { - /* calculate bumpnormal */ - texres->nor[0] = marble_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]); - texres->nor[1] = marble_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]); - texres->nor[2] = marble_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla); - - tex_normal_derivate(tex, texres); - - rv |= TEX_NOR; - } - BRICONT; return rv; @@ -454,7 +376,7 @@ static int magic(const Tex *tex, const float texvec[3], TexResult *texres) /* newnoise: stucci also modified to use different noisebasis */ static int stucci(const Tex *tex, const float texvec[3], TexResult *texres) { - float nor[3], b2, ofs; + float b2, ofs; int retval = TEX_INT; b2 = BLI_noise_generic_noise(tex->noisesize, @@ -469,40 +391,13 @@ static int stucci(const Tex *tex, const float texvec[3], TexResult *texres) if (tex->stype) { ofs *= (b2 * b2); } - nor[0] = BLI_noise_generic_noise(tex->noisesize, - texvec[0] + ofs, - texvec[1], - texvec[2], - (tex->noisetype != TEX_NOISESOFT), - tex->noisebasis); - nor[1] = BLI_noise_generic_noise(tex->noisesize, - texvec[0], - texvec[1] + ofs, - texvec[2], - (tex->noisetype != TEX_NOISESOFT), - tex->noisebasis); - nor[2] = BLI_noise_generic_noise(tex->noisesize, - texvec[0], - texvec[1], - texvec[2] + ofs, - (tex->noisetype != TEX_NOISESOFT), - tex->noisebasis); - - texres->tin = nor[2]; - - if (texres->nor) { - - copy_v3_v3(texres->nor, nor); - tex_normal_derivate(tex, texres); - - if (tex->stype == TEX_WALLOUT) { - texres->nor[0] = -texres->nor[0]; - texres->nor[1] = -texres->nor[1]; - texres->nor[2] = -texres->nor[2]; - } - retval |= TEX_NOR; - } + texres->tin = BLI_noise_generic_noise(tex->noisesize, + texvec[0], + texvec[1], + texvec[2] + ofs, + (tex->noisetype != TEX_NOISESOFT), + tex->noisebasis); if (tex->stype == TEX_WALLOUT) { texres->tin = 1.0f - texres->tin; @@ -538,36 +433,6 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult tex->mg_octaves, tex->noisebasis); - if (texres->nor != NULL) { - float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ - - /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs, - texvec[1], - texvec[2], - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->noisebasis); - texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1] + ofs, - texvec[2], - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->noisebasis); - texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1], - texvec[2] + ofs, - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->noisebasis); - - tex_normal_derivate(tex, texres); - rv |= TEX_NOR; - } - BRICONT; return rv; @@ -595,42 +460,6 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu tex->mg_gain, tex->noisebasis); - if (texres->nor != NULL) { - float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ - - /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs, - texvec[1], - texvec[2], - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->mg_offset, - tex->mg_gain, - tex->noisebasis); - texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1] + ofs, - texvec[2], - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->mg_offset, - tex->mg_gain, - tex->noisebasis); - texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1], - texvec[2] + ofs, - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->mg_offset, - tex->mg_gain, - tex->noisebasis); - - tex_normal_derivate(tex, texres); - rv |= TEX_NOR; - } - BRICONT; return rv; @@ -649,39 +478,6 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr tex->mg_offset, tex->noisebasis); - if (texres->nor != NULL) { - float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ - - /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + ofs, - texvec[1], - texvec[2], - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->mg_offset, - tex->noisebasis); - texres->nor[1] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0], - texvec[1] + ofs, - texvec[2], - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->mg_offset, - tex->noisebasis); - texres->nor[2] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0], - texvec[1], - texvec[2] + ofs, - tex->mg_H, - tex->mg_lacunarity, - tex->mg_octaves, - tex->mg_offset, - tex->noisebasis); - - tex_normal_derivate(tex, texres); - rv |= TEX_NOR; - } - BRICONT; return rv; @@ -694,33 +490,6 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex texres->tin = BLI_noise_mg_variable_lacunarity( texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2); - if (texres->nor != NULL) { - float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ - - /* calculate bumpnormal */ - texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + ofs, - texvec[1], - texvec[2], - tex->dist_amount, - tex->noisebasis, - tex->noisebasis2); - texres->nor[1] = BLI_noise_mg_variable_lacunarity(texvec[0], - texvec[1] + ofs, - texvec[2], - tex->dist_amount, - tex->noisebasis, - tex->noisebasis2); - texres->nor[2] = BLI_noise_mg_variable_lacunarity(texvec[0], - texvec[1], - texvec[2] + ofs, - tex->dist_amount, - tex->noisebasis, - tex->noisebasis2); - - tex_normal_derivate(tex, texres); - rv |= TEX_NOR; - } - BRICONT; return rv; @@ -788,21 +557,6 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres) } } - if (texres->nor != NULL) { - float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ - - /* calculate bumpnormal */ - BLI_noise_voronoi(texvec[0] + ofs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); - texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); - BLI_noise_voronoi(texvec[0], texvec[1] + ofs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); - texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); - BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + ofs, da, pa, tex->vn_mexp, tex->vn_distm); - texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); - - tex_normal_derivate(tex, texres); - rv |= TEX_NOR; - } - if (tex->vn_coltype) { BRICONTRGB; texres->trgba[3] = 1.0; @@ -1148,7 +902,7 @@ static int multitex(Tex *tex, const bool use_nodes) { float tmpvec[3]; - int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */ + int retval = 0; /* return value, TEX_INT or TEX_RGB. */ texres->talpha = false; /* is set when image texture returns alpha (considered premul) */ @@ -1283,14 +1037,14 @@ static int multitex_nodes_intern(Tex *tex, } if (tex->type == TEX_IMAGE) { - int rgbnor; + int retval; if (mtex) { float texvec_l[3]; copy_v3_v3(texvec_l, texvec); /* we have mtex, use it for 2d mapping images only */ do_2d_mapping(mtex, texvec_l, NULL, dxt, dyt); - rgbnor = multitex(tex, + retval = multitex(tex, texvec_l, dxt, dyt, @@ -1307,7 +1061,7 @@ static int multitex_nodes_intern(Tex *tex, ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); /* don't linearize float buffers, assumed to be linear */ - if (ibuf != NULL && ibuf->rect_float == NULL && (rgbnor & TEX_RGB) && scene_color_manage) { + if (ibuf != NULL && ibuf->rect_float == NULL && (retval & TEX_RGB) && scene_color_manage) { IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace); } @@ -1335,7 +1089,7 @@ static int multitex_nodes_intern(Tex *tex, } do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l); - rgbnor = multitex(tex, + retval = multitex(tex, texvec_l, dxt_l, dyt_l, @@ -1352,7 +1106,7 @@ static int multitex_nodes_intern(Tex *tex, ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); /* don't linearize float buffers, assumed to be linear */ - if (ibuf != NULL && ibuf->rect_float == NULL && (rgbnor & TEX_RGB) && scene_color_manage) { + if (ibuf != NULL && ibuf->rect_float == NULL && (retval & TEX_RGB) && scene_color_manage) { IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace); } @@ -1360,7 +1114,7 @@ static int multitex_nodes_intern(Tex *tex, } } - return rgbnor; + return retval; } return multitex(tex, @@ -1456,145 +1210,6 @@ int multitex_ext_safe(Tex *tex, /* ------------------------------------------------------------------------- */ -void texture_rgb_blend( - float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) -{ - float facm; - - switch (blendtype) { - case MTEX_BLEND: - fact *= facg; - facm = 1.0f - fact; - - in[0] = (fact * tex[0] + facm * out[0]); - in[1] = (fact * tex[1] + facm * out[1]); - in[2] = (fact * tex[2] + facm * out[2]); - break; - - case MTEX_MUL: - fact *= facg; - facm = 1.0f - fact; - in[0] = (facm + fact * tex[0]) * out[0]; - in[1] = (facm + fact * tex[1]) * out[1]; - in[2] = (facm + fact * tex[2]) * out[2]; - break; - - case MTEX_SCREEN: - fact *= facg; - facm = 1.0f - fact; - in[0] = 1.0f - (facm + fact * (1.0f - tex[0])) * (1.0f - out[0]); - in[1] = 1.0f - (facm + fact * (1.0f - tex[1])) * (1.0f - out[1]); - in[2] = 1.0f - (facm + fact * (1.0f - tex[2])) * (1.0f - out[2]); - break; - - case MTEX_OVERLAY: - fact *= facg; - facm = 1.0f - fact; - - if (out[0] < 0.5f) { - in[0] = out[0] * (facm + 2.0f * fact * tex[0]); - } - else { - in[0] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[0])) * (1.0f - out[0]); - } - if (out[1] < 0.5f) { - in[1] = out[1] * (facm + 2.0f * fact * tex[1]); - } - else { - in[1] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[1])) * (1.0f - out[1]); - } - if (out[2] < 0.5f) { - in[2] = out[2] * (facm + 2.0f * fact * tex[2]); - } - else { - in[2] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[2])) * (1.0f - out[2]); - } - break; - - case MTEX_SUB: - fact = -fact; - ATTR_FALLTHROUGH; - case MTEX_ADD: - fact *= facg; - in[0] = (fact * tex[0] + out[0]); - in[1] = (fact * tex[1] + out[1]); - in[2] = (fact * tex[2] + out[2]); - break; - - case MTEX_DIV: - fact *= facg; - facm = 1.0f - fact; - - if (tex[0] != 0.0f) { - in[0] = facm * out[0] + fact * out[0] / tex[0]; - } - if (tex[1] != 0.0f) { - in[1] = facm * out[1] + fact * out[1] / tex[1]; - } - if (tex[2] != 0.0f) { - in[2] = facm * out[2] + fact * out[2] / tex[2]; - } - - break; - - case MTEX_DIFF: - fact *= facg; - facm = 1.0f - fact; - in[0] = facm * out[0] + fact * fabsf(tex[0] - out[0]); - in[1] = facm * out[1] + fact * fabsf(tex[1] - out[1]); - in[2] = facm * out[2] + fact * fabsf(tex[2] - out[2]); - break; - - case MTEX_DARK: - fact *= facg; - facm = 1.0f - fact; - - in[0] = min_ff(out[0], tex[0]) * fact + out[0] * facm; - in[1] = min_ff(out[1], tex[1]) * fact + out[1] * facm; - in[2] = min_ff(out[2], tex[2]) * fact + out[2] * facm; - break; - - case MTEX_LIGHT: - fact *= facg; - - in[0] = max_ff(fact * tex[0], out[0]); - in[1] = max_ff(fact * tex[1], out[1]); - in[2] = max_ff(fact * tex[2], out[2]); - break; - - case MTEX_BLEND_HUE: - fact *= facg; - copy_v3_v3(in, out); - ramp_blend(MA_RAMP_HUE, in, fact, tex); - break; - case MTEX_BLEND_SAT: - fact *= facg; - copy_v3_v3(in, out); - ramp_blend(MA_RAMP_SAT, in, fact, tex); - break; - case MTEX_BLEND_VAL: - fact *= facg; - copy_v3_v3(in, out); - ramp_blend(MA_RAMP_VAL, in, fact, tex); - break; - case MTEX_BLEND_COLOR: - fact *= facg; - copy_v3_v3(in, out); - ramp_blend(MA_RAMP_COLOR, in, fact, tex); - break; - case MTEX_SOFT_LIGHT: - fact *= facg; - copy_v3_v3(in, out); - ramp_blend(MA_RAMP_SOFT, in, fact, tex); - break; - case MTEX_LIN_LIGHT: - fact *= facg; - copy_v3_v3(in, out); - ramp_blend(MA_RAMP_LINEAR, in, fact, tex); - break; - } -} - float texture_value_blend(float tex, float out, float fact, float facg, int blendtype) { float in = 0.0, facm, col, scf; @@ -1703,7 +1318,6 @@ bool RE_texture_evaluate(const MTex *mtex, if (tex == NULL) { return 0; } - texr.nor = NULL; /* placement */ if (mtex->projx) { diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h index c195165a792..dea5151598c 100644 --- a/source/blender/sequencer/SEQ_add.h +++ b/source/blender/sequencer/SEQ_add.h @@ -183,9 +183,6 @@ void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *fil * \param seq: image strip to be changed */ void SEQ_add_image_init_alpha_mode(struct Sequence *seq); -/** - * \note caller should run `SEQ_time_update_sequence(scene, seq)` after.. - */ void SEQ_add_reload_new_file(struct Main *bmain, struct Scene *scene, struct Sequence *seq, diff --git a/source/blender/sequencer/SEQ_channels.h b/source/blender/sequencer/SEQ_channels.h index dcfdb933940..197ad5e55de 100644 --- a/source/blender/sequencer/SEQ_channels.h +++ b/source/blender/sequencer/SEQ_channels.h @@ -24,8 +24,8 @@ void SEQ_channels_duplicate(struct ListBase *channels_dst, struct ListBase *chan void SEQ_channels_free(struct ListBase *channels); struct SeqTimelineChannel *SEQ_channel_get_by_index(const struct ListBase *channels, - const int channel_index); -char *SEQ_channel_name_get(struct ListBase *channels, const int channel_index); + int channel_index); +char *SEQ_channel_name_get(struct ListBase *channels, int channel_index); bool SEQ_channel_is_locked(const struct SeqTimelineChannel *channel); bool SEQ_channel_is_muted(const struct SeqTimelineChannel *channel); int SEQ_channel_index_get(const struct SeqTimelineChannel *channel); diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h index 8cb20d41ba2..1f94574513c 100644 --- a/source/blender/sequencer/SEQ_iterator.h +++ b/source/blender/sequencer/SEQ_iterator.h @@ -131,6 +131,9 @@ bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *collection * \param collection: collection to be freed */ void SEQ_collection_free(SeqCollection *collection); +/** Quiet compiler warning for free function. */ +#define SEQ_collection_free_void_p ((GHashValFreeFP)SEQ_collection_free) + /** * Move strips from collection_src to collection_dst. Source collection will be freed. * diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index 8ded6d99a8d..70cba58007f 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -143,7 +143,8 @@ typedef enum eSequenceLookupTag { * * \return pointer to Sequence */ -struct Sequence *SEQ_sequence_lookup_by_name(const struct Scene *scene, const char *key); +struct Sequence *SEQ_sequence_lookup_seq_by_name(const struct Scene *scene, const char *key); + /** * Free lookup hash data. * diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h index 1da6efb1d04..eab10f2e852 100644 --- a/source/blender/sequencer/SEQ_time.h +++ b/source/blender/sequencer/SEQ_time.h @@ -47,8 +47,6 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene, bool do_skip_mute, bool do_center, bool do_unselected); -void SEQ_time_update_sequence(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq); -void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq); /** * Test if strip intersects with timeline frame. * \note This checks if strip would be rendered at this frame. For rendering it is assumed, that @@ -59,14 +57,15 @@ void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq * \return true if strip intersects with timeline frame. */ bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, int timeline_frame); -void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta); bool SEQ_time_has_still_frames(const struct Sequence *seq); bool SEQ_time_has_left_still_frames(const struct Sequence *seq); bool SEQ_time_has_right_still_frames(const struct Sequence *seq); -int SEQ_time_left_handle_frame_get(struct Sequence *seq); -int SEQ_time_right_handle_frame_get(struct Sequence *seq); -void SEQ_time_left_handle_frame_set(struct Sequence *seq, int val); -void SEQ_time_right_handle_frame_set(struct Sequence *seq, int val); + +int SEQ_time_left_handle_frame_get(const struct Sequence *seq); +int SEQ_time_right_handle_frame_get(const struct Sequence *seq); +void SEQ_time_left_handle_frame_set(const struct Scene *scene, struct Sequence *seq, int val); +void SEQ_time_right_handle_frame_set(const struct Scene *scene, struct Sequence *seq, int val); +void SEQ_time_update_meta_strip_range(const struct Scene *scene, struct Sequence *seq_meta); #ifdef __cplusplus } diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h index bd4258bfdb1..31a7399f844 100644 --- a/source/blender/sequencer/SEQ_transform.h +++ b/source/blender/sequencer/SEQ_transform.h @@ -21,14 +21,17 @@ struct Sequence; * Use to impose limits when dragging/extending - so impossible situations don't happen. * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip. */ -void SEQ_transform_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag); +void SEQ_transform_handle_xlimits(const struct Scene *scene, + struct Sequence *seq, + int leftflag, + int rightflag); bool SEQ_transform_sequence_can_be_translated(struct Sequence *seq); /** * Used so we can do a quick check for single image seq * since they work a bit differently to normal image seq's (during transform). */ bool SEQ_transform_single_image_check(struct Sequence *seq); -void SEQ_transform_fix_single_image_seq_offsets(struct Sequence *seq); +void SEQ_transform_fix_single_image_seq_offsets(const struct Scene *scene, struct Sequence *seq); bool SEQ_transform_test_overlap(struct ListBase *seqbasep, struct Sequence *test); bool SEQ_transform_test_overlap_seq_seq(struct Sequence *seq1, struct Sequence *seq2); void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta); @@ -43,6 +46,7 @@ bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep, struct Sequence *test, struct Scene *evil_scene); bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle, + struct SeqCollection *time_dependent_strips, struct ListBase *seqbasep, struct Scene *evil_scene, struct ListBase *markers, @@ -51,6 +55,7 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle, void SEQ_transform_handle_overlap(struct Scene *scene, struct ListBase *seqbasep, struct SeqCollection *transformed_strips, + struct SeqCollection *time_dependent_strips, bool use_sync_markers); /** * Check if the selected seq's reference unselected seq's. diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h index ce3c81606ea..24ca7559166 100644 --- a/source/blender/sequencer/SEQ_utils.h +++ b/source/blender/sequencer/SEQ_utils.h @@ -20,14 +20,6 @@ struct SeqRenderData; struct Sequence; struct StripElem; -/** - * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by - * channel position as well. - * This is important for SEQ_time_update_sequence to work properly - * - * \param seqbase: ListBase with strips - */ -void SEQ_sort(struct ListBase *seqbase); void SEQ_sequence_base_unique_name_recursive(struct Scene *scene, struct ListBase *seqbasep, struct Sequence *seq); @@ -39,7 +31,7 @@ const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int f /** * In cases where we don't know the sequence's listbase. */ -struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq); +struct ListBase *SEQ_get_seqbase_by_seq(const struct Scene *scene, struct Sequence *seq); /** * Only use as last resort when the StripElem is available but no the Sequence. * (needed for RNA) diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c index f8e8fc32a5d..cc34066c432 100644 --- a/source/blender/sequencer/intern/disk_cache.c +++ b/source/blender/sequencer/intern/disk_cache.c @@ -37,6 +37,7 @@ #include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "disk_cache.h" #include "image_cache.h" @@ -411,8 +412,8 @@ void seq_disk_cache_invalidate(SeqDiskCache *disk_cache, BLI_mutex_lock(&disk_cache->read_write_mutex); - start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE; - end = seq_changed->enddisp; + start = SEQ_time_left_handle_frame_get(seq_changed) - DCACHE_IMAGES_PER_FILE; + end = SEQ_time_right_handle_frame_get(seq_changed); seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end); diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index d9d21ee3b05..0e5e56908b0 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -49,6 +49,7 @@ #include "SEQ_proxy.h" #include "SEQ_relations.h" #include "SEQ_render.h" +#include "SEQ_time.h" #include "SEQ_utils.h" #include "BLF_api.h" @@ -2431,7 +2432,7 @@ static ImBuf *do_multicam(const SeqRenderData *context, if (!ed) { return NULL; } - ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); + ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq); ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq); if (!seqbasep) { return NULL; @@ -2467,13 +2468,15 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl ed = context->scene->ed; - ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); + ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq); ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq); /* Clamp timeline_frame to strip range so it behaves as if it had "still frame" offset (last * frame is static after end of strip). This is how most strips behave. This way transition * effects that doesn't overlap or speed effect can't fail rendering outside of strip range. */ - timeline_frame = clamp_i(timeline_frame, seq->startdisp, seq->enddisp - 1); + timeline_frame = clamp_i(timeline_frame, + SEQ_time_left_handle_frame_get(seq), + SEQ_time_right_handle_frame_get(seq) - 1); if (seq->machine > 1) { i = seq_render_give_ibuf_seqbase( @@ -2583,7 +2586,7 @@ static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac)) static int seq_effect_speed_get_strip_content_length(const Sequence *seq) { if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) == 0) { - return seq->enddisp - seq->startdisp; + return SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq); } return seq->len; @@ -2610,13 +2613,14 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq) MEM_freeN(v->frameMap); } - const int effect_strip_length = seq->enddisp - seq->startdisp; + const int effect_strip_length = SEQ_time_right_handle_frame_get(seq) - + SEQ_time_left_handle_frame_get(seq); v->frameMap = MEM_mallocN(sizeof(float) * effect_strip_length, __func__); v->frameMap[0] = 0.0f; float target_frame = 0; for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) { - target_frame += evaluate_fcurve(fcu, seq->startdisp + frame_index); + target_frame += evaluate_fcurve(fcu, SEQ_time_left_handle_frame_get(seq) + frame_index); CLAMP(target_frame, 0, seq->seq1->len); v->frameMap[frame_index] = target_frame; } @@ -2652,7 +2656,8 @@ float seq_speed_effect_target_frame_get(Scene *scene, /* Only right handle controls effect speed! */ const float target_content_length = seq_effect_speed_get_strip_content_length(source) - source->startofs; - const float speed_effetct_length = seq_speed->enddisp - seq_speed->startdisp; + const float speed_effetct_length = SEQ_time_right_handle_frame_get(seq_speed) - + SEQ_time_left_handle_frame_get(seq_speed); const float ratio = frame_index / speed_effetct_length; target_frame = target_content_length * ratio; break; @@ -3509,7 +3514,7 @@ static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_fr static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac) { - *fac = (float)(timeline_frame - seq->startdisp); + *fac = (float)(timeline_frame - SEQ_time_left_handle_frame_get(seq)); *fac /= seq->len; } diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index e1ff0ff64b3..47306dbbc6c 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -36,6 +36,7 @@ #include "SEQ_prefetch.h" #include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "disk_cache.h" #include "image_cache.h" @@ -558,8 +559,9 @@ void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame) /* Use frame_index here to avoid freeing raw images if they are used for multiple frames. */ float frame_index = seq_cache_timeline_frame_to_frame_index( key->seq, timeline_frame, key->type); - if (frame_index != key->frame_index || timeline_frame > key->seq->enddisp || - timeline_frame < key->seq->startdisp) { + if (frame_index != key->frame_index || + timeline_frame > SEQ_time_right_handle_frame_get(key->seq) || + timeline_frame < SEQ_time_left_handle_frame_get(key->seq)) { BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree); } } @@ -634,17 +636,12 @@ void seq_cache_cleanup_sequence(Scene *scene, seq_cache_lock(scene); - int range_start = seq_changed->startdisp; - int range_end = seq_changed->enddisp; + int range_start = SEQ_time_left_handle_frame_get(seq_changed); + int range_end = SEQ_time_right_handle_frame_get(seq_changed); if (!force_seq_changed_range) { - if (seq->startdisp > range_start) { - range_start = seq->startdisp; - } - - if (seq->enddisp < range_end) { - range_end = seq->enddisp; - } + range_start = max_ii(range_start, SEQ_time_left_handle_frame_get(seq)); + range_end = min_ii(range_end, SEQ_time_right_handle_frame_get(seq)); } int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT; @@ -668,8 +665,8 @@ void seq_cache_cleanup_sequence(Scene *scene, } if (key->type & invalidate_source && key->seq == seq && - key->timeline_frame >= seq_changed->startdisp && - key->timeline_frame <= seq_changed->enddisp) { + key->timeline_frame >= SEQ_time_left_handle_frame_get(seq_changed) && + key->timeline_frame <= SEQ_time_right_handle_frame_get(seq_changed)) { if (key->link_next || key->link_prev) { seq_cache_relink_keys(key->link_next, key->link_prev); } @@ -700,11 +697,12 @@ void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area_safe) SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); BLI_ghashIterator_step(&gh_iter); - const int frame_index = key->timeline_frame - key->seq->startdisp; + const int frame_index = key->timeline_frame - SEQ_time_left_handle_frame_get(key->seq); const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(key->seq); const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step; - const int nearest_guaranted_absolute_frame = relative_base_frame + key->seq->startdisp; + const int nearest_guaranted_absolute_frame = relative_base_frame + + SEQ_time_left_handle_frame_get(key->seq); if (nearest_guaranted_absolute_frame == key->timeline_frame) { continue; diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index 59b4c6de1ef..464580f5bed 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -43,6 +43,7 @@ #include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "multiview.h" #include "proxy.h" @@ -523,7 +524,9 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context, SeqRenderState state; seq_render_state_init(&state); - for (timeline_frame = seq->startdisp; timeline_frame < seq->enddisp; timeline_frame++) { + for (timeline_frame = SEQ_time_left_handle_frame_get(seq); + timeline_frame < SEQ_time_right_handle_frame_get(seq); + timeline_frame++) { if (context->size_flags & IMB_PROXY_25) { seq_proxy_build_frame(&render_context, &state, seq, timeline_frame, 25, overwrite); } @@ -537,7 +540,8 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context, seq_proxy_build_frame(&render_context, &state, seq, timeline_frame, 100, overwrite); } - *progress = (float)(timeline_frame - seq->startdisp) / (seq->enddisp - seq->startdisp); + *progress = (float)(timeline_frame - SEQ_time_left_handle_frame_get(seq)) / + (SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq)); *do_update = true; if (*stop || G.is_break) { diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index b0898be3765..e7a1bbeb9d0 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -1994,11 +1994,12 @@ ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context, float SEQ_render_thumbnail_first_frame_get(Sequence *seq, float frame_step, rctf *view_area) { - int first_drawable_frame = max_iii(seq->startdisp, seq->start, view_area->xmin); + int first_drawable_frame = max_iii( + SEQ_time_left_handle_frame_get(seq), seq->start, view_area->xmin); /* First frame should correspond to handle position. */ - if (first_drawable_frame == seq->startdisp) { - return seq->startdisp; + if (first_drawable_frame == SEQ_time_left_handle_frame_get(seq)) { + return SEQ_time_left_handle_frame_get(seq); } float aligned_frame_offset = (int)((first_drawable_frame - seq->start) / frame_step) * @@ -2011,7 +2012,7 @@ float SEQ_render_thumbnail_next_frame_get(Sequence *seq, float last_frame, float float next_frame = last_frame + frame_step; /* If handle position was displayed, align next frame with `seq->start`. */ - if (last_frame == seq->startdisp) { + if (last_frame == SEQ_time_left_handle_frame_get(seq)) { next_frame = seq->start + ((int)((last_frame - seq->start) / frame_step) + 1) * frame_step; } @@ -2088,8 +2089,9 @@ void SEQ_render_thumbnails(const SeqRenderData *context, /* Adding the hold offset value (seq->anim_startofs) to the start frame. Position of image not * affected, but frame loaded affected. */ - float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : - seq->enddisp; + float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? + (seq->start + seq->len) : + SEQ_time_right_handle_frame_get(seq); upper_thumb_bound = (upper_thumb_bound > view_area->xmax) ? view_area->xmax + frame_step : upper_thumb_bound; @@ -2122,8 +2124,8 @@ void SEQ_render_thumbnails(const SeqRenderData *context, int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq) { - const int content_start = max_ii(seq->startdisp, seq->start); - const int content_end = min_ii(seq->enddisp, seq->start + seq->len); + const int content_start = max_ii(SEQ_time_left_handle_frame_get(seq), seq->start); + const int content_end = min_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len); const int content_len = content_end - content_start; /* Arbitrary, but due to performance reasons should be as low as possible. */ @@ -2143,10 +2145,10 @@ void SEQ_render_thumbnails_base_set(const SeqRenderData *context, SeqRenderState state; seq_render_state_init(&state); - int timeline_frame = seq->startdisp; + int timeline_frame = SEQ_time_left_handle_frame_get(seq); const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq); - while (timeline_frame < seq->enddisp && !*stop) { + while (timeline_frame < SEQ_time_right_handle_frame_get(seq) && !*stop) { ImBuf *ibuf = seq_cache_get( context, seq_orig, roundf(timeline_frame), SEQ_CACHE_STORE_THUMBNAIL); if (ibuf) { diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c index 2a2626d8abf..8d18e381171 100644 --- a/source/blender/sequencer/intern/sequence_lookup.c +++ b/source/blender/sequencer/intern/sequence_lookup.c @@ -6,6 +6,7 @@ */ #include "SEQ_sequencer.h" +#include "sequencer.h" #include "DNA_listBase.h" #include "DNA_scene_types.h" @@ -14,6 +15,7 @@ #include "SEQ_iterator.h" #include "BLI_ghash.h" +#include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_sys_types.h" #include "BLI_threads.h" @@ -24,24 +26,66 @@ static ThreadMutex lookup_lock = BLI_MUTEX_INITIALIZER; typedef struct SequenceLookup { - GHash *by_name; + GHash *seq_by_name; + GHash *meta_by_seq; + GHash *effects_by_seq; eSequenceLookupTag tag; } SequenceLookup; static void seq_sequence_lookup_init(struct SequenceLookup *lookup) { - lookup->by_name = BLI_ghash_str_new(__func__); + lookup->seq_by_name = BLI_ghash_str_new(__func__); + lookup->meta_by_seq = BLI_ghash_ptr_new(__func__); + lookup->effects_by_seq = BLI_ghash_ptr_new(__func__); lookup->tag |= SEQ_LOOKUP_TAG_INVALID; } -static void seq_sequence_lookup_build(const struct Scene *scene, struct SequenceLookup *lookup) +static void seq_sequence_lookup_append_effect(Sequence *input, + Sequence *effect, + struct SequenceLookup *lookup) +{ + if (input == NULL) { + return; + } + + SeqCollection *effects = BLI_ghash_lookup(lookup->effects_by_seq, input); + if (effects == NULL) { + effects = SEQ_collection_create(__func__); + BLI_ghash_insert(lookup->effects_by_seq, input, effects); + } + + SEQ_collection_append_strip(effect, effects); +} + +static void seq_sequence_lookup_build_effect(Sequence *seq, struct SequenceLookup *lookup) { - SeqCollection *all_strips = SEQ_query_all_strips_recursive(&scene->ed->seqbase); - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, all_strips) { - BLI_ghash_insert(lookup->by_name, seq->name + 2, seq); + if ((seq->type & SEQ_TYPE_EFFECT) == 0) { + return; } - SEQ_collection_free(all_strips); + + seq_sequence_lookup_append_effect(seq->seq1, seq, lookup); + seq_sequence_lookup_append_effect(seq->seq2, seq, lookup); +} + +static void seq_sequence_lookup_build_from_seqbase(Sequence *parent_meta, + const ListBase *seqbase, + struct SequenceLookup *lookup) +{ + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + BLI_ghash_insert(lookup->seq_by_name, seq->name + 2, seq); + BLI_ghash_insert(lookup->meta_by_seq, seq, parent_meta); + seq_sequence_lookup_build_effect(seq, lookup); + + if (seq->type == SEQ_TYPE_META) { + seq_sequence_lookup_build_from_seqbase(seq, &seq->seqbase, lookup); + } + } +} + +static void seq_sequence_lookup_build(const struct Scene *scene, struct SequenceLookup *lookup) +{ + Editing *ed = SEQ_editing_get(scene); + seq_sequence_lookup_build_from_seqbase(NULL, &ed->seqbase, lookup); lookup->tag &= ~SEQ_LOOKUP_TAG_INVALID; } @@ -58,8 +102,12 @@ static void seq_sequence_lookup_free(struct SequenceLookup **lookup) return; } - BLI_ghash_free((*lookup)->by_name, NULL, NULL); - (*lookup)->by_name = NULL; + BLI_ghash_free((*lookup)->seq_by_name, NULL, NULL); + BLI_ghash_free((*lookup)->meta_by_seq, NULL, NULL); + BLI_ghash_free((*lookup)->effects_by_seq, NULL, SEQ_collection_free_void_p); + (*lookup)->seq_by_name = NULL; + (*lookup)->meta_by_seq = NULL; + (*lookup)->effects_by_seq = NULL; MEM_freeN(*lookup); *lookup = NULL; } @@ -98,17 +146,39 @@ void SEQ_sequence_lookup_free(const Scene *scene) BLI_mutex_unlock(&lookup_lock); } -Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key) +Sequence *SEQ_sequence_lookup_seq_by_name(const Scene *scene, const char *key) +{ + BLI_assert(scene->ed); + BLI_mutex_lock(&lookup_lock); + seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup); + SequenceLookup *lookup = scene->ed->runtime.sequence_lookup; + Sequence *seq = BLI_ghash_lookup(lookup->seq_by_name, key); + BLI_mutex_unlock(&lookup_lock); + return seq; +} + +Sequence *seq_sequence_lookup_meta_by_seq(const Scene *scene, const Sequence *key) { BLI_assert(scene->ed); BLI_mutex_lock(&lookup_lock); seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup); SequenceLookup *lookup = scene->ed->runtime.sequence_lookup; - Sequence *seq = BLI_ghash_lookup(lookup->by_name, key); + Sequence *seq = BLI_ghash_lookup(lookup->meta_by_seq, key); BLI_mutex_unlock(&lookup_lock); return seq; } +SeqCollection *seq_sequence_lookup_effects_by_seq(const Scene *scene, const Sequence *key) +{ + BLI_assert(scene->ed); + BLI_mutex_lock(&lookup_lock); + seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup); + SequenceLookup *lookup = scene->ed->runtime.sequence_lookup; + SeqCollection *effects = BLI_ghash_lookup(lookup->effects_by_seq, key); + BLI_mutex_unlock(&lookup_lock); + return effects; +} + void SEQ_sequence_lookup_tag(const Scene *scene, eSequenceLookupTag tag) { if (!scene->ed) { diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h index 9f5bdf672c0..5e78c8c6f96 100644 --- a/source/blender/sequencer/intern/sequencer.h +++ b/source/blender/sequencer/intern/sequencer.h @@ -14,13 +14,37 @@ extern "C" { struct Scene; struct Sequence; struct StripProxy; +struct SeqCollection; /** * Cache must be freed before calling this function * since it leaves the seqbase in an invalid state. */ void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq, bool do_id_user); struct StripProxy *seq_strip_proxy_alloc(void); - +/** + * Find meta strip, that contains strip `key`. + * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be + * rebuilt. + * + * \param scene: scene that owns lookup hash + * \param key: pointer to Sequence inside of meta strip + * + * \return pointer to meta strip + */ +struct Sequence *seq_sequence_lookup_meta_by_seq(const struct Scene *scene, + const struct Sequence *key); +/** + * Find effect strips, that use strip `seq` as one of inputs. + * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be + * rebuilt. + * + * \param scene: scene that owns lookup hash + * \param key: pointer to Sequence inside of meta strip + * + * \return collection of effect strips + */ +struct SeqCollection *seq_sequence_lookup_effects_by_seq(const struct Scene *scene, + const struct Sequence *key); #ifdef __cplusplus } #endif diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c index 8076c600560..50c8b76a9a0 100644 --- a/source/blender/sequencer/intern/sound.c +++ b/source/blender/sequencer/intern/sound.c @@ -35,7 +35,6 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, for (seq = seqbase->first; seq; seq = seq->next) { if (seq->type == SEQ_TYPE_META) { if (sequencer_refresh_sound_length_recursive(bmain, scene, &seq->seqbase)) { - SEQ_time_update_sequence(scene, seqbase, seq); changed = true; } } @@ -55,7 +54,6 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, seq->endofs *= fac; seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */ - SEQ_time_update_sequence(scene, seqbase, seq); changed = true; } } @@ -99,8 +97,12 @@ void SEQ_sound_update_bounds(Scene *scene, Sequence *seq) /* We have to take into account start frame of the sequence's scene! */ int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra; - BKE_sound_move_scene_sound( - scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs, 0.0); + BKE_sound_move_scene_sound(scene, + seq->scene_sound, + SEQ_time_left_handle_frame_get(seq), + SEQ_time_right_handle_frame_get(seq), + startofs, + 0.0); } } else { diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 77b0fc946d9..4f0b2e38f56 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -51,6 +51,8 @@ #include "multiview.h" #include "proxy.h" +#include "sequencer.h" +#include "strip_time.h" #include "utils.h" void SEQ_add_load_data_init(SeqLoadData *load_data, @@ -70,12 +72,12 @@ void SEQ_add_load_data_init(SeqLoadData *load_data, load_data->channel = channel; } -static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq) +static void seq_add_generic_update(Scene *scene, Sequence *seq) { SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq); - SEQ_time_update_sequence(scene, seqbase, seq); - SEQ_sort(seqbase); SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID); + SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq)); } static void seq_add_set_name(Scene *scene, Sequence *seq, SeqLoadData *load_data) @@ -128,7 +130,7 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1; id_us_ensure_real((ID *)load_data->scene); seq_add_set_name(scene, seq, load_data); - seq_add_generic_update(scene, seqbase, seq); + seq_add_generic_update(scene, seq); return seq; } @@ -140,7 +142,7 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa seq->len = BKE_movieclip_get_duration(load_data->clip); id_us_ensure_real((ID *)load_data->clip); seq_add_set_name(scene, seq, load_data); - seq_add_generic_update(scene, seqbase, seq); + seq_add_generic_update(scene, seq); return seq; } @@ -152,7 +154,7 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData seq->len = BKE_mask_get_duration(load_data->mask); id_us_ensure_real((ID *)load_data->mask); seq_add_set_name(scene, seq, load_data); - seq_add_generic_update(scene, seqbase, seq); + seq_add_generic_update(scene, seq); return seq; } @@ -174,11 +176,12 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa if (!load_data->effect.seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ - SEQ_time_right_handle_frame_set(seq, load_data->effect.end_frame); + SEQ_time_right_handle_frame_set(scene, seq, load_data->effect.end_frame); } seq_add_set_name(scene, seq, load_data); - seq_add_generic_update(scene, seqbase, seq); + seq_add_generic_update(scene, seq); + seq_time_effect_range_set(seq); return seq; } @@ -264,7 +267,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL BLI_strncpy(scene->ed->act_imagedir, seq->strip->dir, sizeof(scene->ed->act_imagedir)); seq_add_set_view_transform(scene, seq, load_data); seq_add_set_name(scene, seq, load_data); - seq_add_generic_update(scene, seqbase, seq); + seq_add_generic_update(scene, seq); return seq; } @@ -335,7 +338,7 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL /* Set Last active directory. */ BLI_strncpy(scene->ed->act_sounddir, strip->dir, FILE_MAXDIR); seq_add_set_name(scene, seq, load_data); - seq_add_generic_update(scene, seqbase, seq); + seq_add_generic_update(scene, seq); return seq; } @@ -362,7 +365,6 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_ /* Set frames start and length. */ seqm->start = load_data->start_frame; seqm->len = 1; - SEQ_time_update_sequence(scene, seqbase, seqm); return seqm; } @@ -484,7 +486,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL seq_add_set_view_transform(scene, seq, load_data); seq_add_set_name(scene, seq, load_data); - seq_add_generic_update(scene, seqbase, seq); + seq_add_generic_update(scene, seq); MEM_freeN(anim_arr); return seq; @@ -509,11 +511,8 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo if (lock_range) { /* keep so we don't have to move the actual start and end points (only the data) */ - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); - SEQ_time_update_sequence(scene, seqbase, seq); - prev_startdisp = seq->startdisp; - prev_enddisp = seq->enddisp; + prev_startdisp = SEQ_time_left_handle_frame_get(seq); + prev_enddisp = SEQ_time_right_handle_frame_get(seq); } switch (seq->type) { @@ -656,13 +655,11 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo free_proxy_seq(seq); if (lock_range) { - SEQ_time_left_handle_frame_set(seq, prev_startdisp); - SEQ_time_right_handle_frame_set(seq, prev_enddisp); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_time_left_handle_frame_set(scene, seq, prev_startdisp); + SEQ_time_right_handle_frame_set(scene, seq, prev_enddisp); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); } - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); SEQ_relations_invalidate_cache_raw(scene, seq); } diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 96bfce8f740..bd439e3c9f8 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -84,8 +84,8 @@ int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_ SWAP(int, seq_a->startofs, seq_b->startofs); SWAP(int, seq_a->endofs, seq_b->endofs); SWAP(int, seq_a->machine, seq_b->machine); - SWAP(int, seq_a->startdisp, seq_b->startdisp); - SWAP(int, seq_a->enddisp, seq_b->enddisp); + seq_time_effect_range_set(seq_a); + seq_time_effect_range_set(seq_b); return 1; } @@ -230,7 +230,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, { /* Find the appropriate seqbase */ Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, src_seq); + ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, src_seq); if (dst_seqm->type != SEQ_TYPE_META) { *error_str = N_("Can not move strip to non-meta strip"); @@ -272,11 +272,11 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, return true; } -static void seq_split_set_left_hold_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_left_hold_offset(const Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes before strip. */ if (timeline_frame < seq->start) { - SEQ_time_left_handle_frame_set(seq, timeline_frame); + SEQ_time_left_handle_frame_set(scene, seq, timeline_frame); } /* Adjust within range of strip contents. */ else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) { @@ -290,19 +290,19 @@ static void seq_split_set_left_hold_offset(Sequence *seq, int timeline_frame) seq->start += timeline_frame - seq->start; seq->anim_startofs += seq->len - 1; seq->len = 1; - SEQ_time_left_handle_frame_set(seq, timeline_frame); - SEQ_time_right_handle_frame_set(seq, right_handle_backup); + SEQ_time_left_handle_frame_set(scene, seq, timeline_frame); + SEQ_time_right_handle_frame_set(scene, seq, right_handle_backup); } } -static void seq_split_set_right_hold_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_right_hold_offset(const Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes before strip. */ if (timeline_frame < seq->start) { const int left_handle_backup = SEQ_time_left_handle_frame_get(seq); seq->start = timeline_frame - 1; - SEQ_time_left_handle_frame_set(seq, left_handle_backup); - SEQ_time_right_handle_frame_set(seq, timeline_frame); + SEQ_time_left_handle_frame_set(scene, seq, left_handle_backup); + SEQ_time_right_handle_frame_set(scene, seq, timeline_frame); } /* Adjust within range of strip contents. */ else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) { @@ -311,11 +311,11 @@ static void seq_split_set_right_hold_offset(Sequence *seq, int timeline_frame) } /* Adjust within range of extended stillframes after strip. */ else if ((seq->start + seq->len) < timeline_frame) { - SEQ_time_right_handle_frame_set(seq, timeline_frame); + SEQ_time_right_handle_frame_set(scene, seq, timeline_frame); } } -static void seq_split_set_right_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_right_offset(const Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes before strip. */ if (timeline_frame < seq->start) { @@ -324,10 +324,10 @@ static void seq_split_set_right_offset(Sequence *seq, int timeline_frame) seq->startofs += content_offset; } - SEQ_time_right_handle_frame_set(seq, timeline_frame); + SEQ_time_right_handle_frame_set(scene, seq, timeline_frame); } -static void seq_split_set_left_offset(Sequence *seq, int timeline_frame) +static void seq_split_set_left_offset(const Scene *scene, Sequence *seq, int timeline_frame) { /* Adjust within range of extended stillframes after strip. */ if (timeline_frame > seq->start + seq->len) { @@ -336,17 +336,17 @@ static void seq_split_set_left_offset(Sequence *seq, int timeline_frame) seq->endofs += content_offset; } - SEQ_time_left_handle_frame_set(seq, timeline_frame); + SEQ_time_left_handle_frame_set(scene, seq, timeline_frame); } static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int timeline_frame) { - return timeline_frame > seq->startdisp && timeline_frame < seq->enddisp; + return timeline_frame > SEQ_time_left_handle_frame_get(seq) && + timeline_frame < SEQ_time_right_handle_frame_get(seq); } static void seq_edit_split_handle_strip_offsets(Main *bmain, Scene *scene, - ListBase *seqbase, Sequence *left_seq, Sequence *right_seq, const int timeline_frame, @@ -355,27 +355,25 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain, if (seq_edit_split_effect_intersect_check(right_seq, timeline_frame)) { switch (method) { case SEQ_SPLIT_SOFT: - seq_split_set_left_offset(right_seq, timeline_frame); + seq_split_set_left_offset(scene, right_seq, timeline_frame); break; case SEQ_SPLIT_HARD: - seq_split_set_left_hold_offset(right_seq, timeline_frame); + seq_split_set_left_hold_offset(scene, right_seq, timeline_frame); SEQ_add_reload_new_file(bmain, scene, right_seq, false); break; } - SEQ_time_update_sequence(scene, seqbase, right_seq); } if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) { switch (method) { case SEQ_SPLIT_SOFT: - seq_split_set_right_offset(left_seq, timeline_frame); + seq_split_set_right_offset(scene, left_seq, timeline_frame); break; case SEQ_SPLIT_HARD: - seq_split_set_right_hold_offset(left_seq, timeline_frame); + seq_split_set_right_hold_offset(scene, left_seq, timeline_frame); SEQ_add_reload_new_file(bmain, scene, left_seq, false); break; } - SEQ_time_update_sequence(scene, seqbase, left_seq); } } @@ -468,10 +466,6 @@ Sequence *SEQ_edit_strip_split(Main *bmain, SEQ_collection_free(collection); - /* Sort list, so that no strip can depend on next strip in list. - * This is important for SEQ_time_update_sequence functionality. */ - SEQ_sort(&left_strips); - /* Duplicate ListBase. */ ListBase right_strips = {NULL, NULL}; SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0); @@ -480,18 +474,23 @@ Sequence *SEQ_edit_strip_split(Main *bmain, Sequence *right_seq = right_strips.first; Sequence *return_seq = NULL; - /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal, - * SEQ_time_update_sequence can fail to update meta strips and they can't be renamed. - * This is because these functions check all strips in `Editing` to manage relationships. */ + /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal. */ BLI_movelisttolist(seqbase, &left_strips); BLI_movelisttolist(seqbase, &right_strips); + /* Rename duplicated strips. This has to be done immediately after adding + * strips to seqbase, for lookup cache to work correctly. */ + Sequence *seq_rename = right_seq; + for (; seq_rename; seq_rename = seq_rename->next) { + SEQ_ensure_unique_name(seq_rename, scene); + } + /* Split strips. */ while (left_seq && right_seq) { - if (left_seq->startdisp >= timeline_frame) { + if (SEQ_time_left_handle_frame_get(left_seq) >= timeline_frame) { SEQ_edit_flag_for_removal(scene, seqbase, left_seq); } - if (right_seq->enddisp <= timeline_frame) { + else if (SEQ_time_right_handle_frame_get(right_seq) <= timeline_frame) { SEQ_edit_flag_for_removal(scene, seqbase, right_seq); } else if (return_seq == NULL) { @@ -499,20 +498,12 @@ Sequence *SEQ_edit_strip_split(Main *bmain, return_seq = right_seq; } - seq_edit_split_handle_strip_offsets( - bmain, scene, seqbase, left_seq, right_seq, timeline_frame, method); + seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method); left_seq = left_seq->next; right_seq = right_seq->next; } SEQ_edit_remove_flagged_sequences(scene, seqbase); - - /* Rename duplicated strips. */ - Sequence *seq_rename = return_seq; - for (; seq_rename; seq_rename = seq_rename->next) { - SEQ_ensure_unique_name(seq_rename, scene); - } - SEQ_animation_restore_original(scene, &fcurves_original_backup); return return_seq; diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 1899cc99263..4acf2763ce5 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -47,7 +47,8 @@ static bool seq_relations_check_depend(Sequence *seq, Sequence *cur) } /* sequences are not intersecting in time, assume no dependency exists between them */ - if (cur->enddisp < seq->startdisp || cur->startdisp > seq->enddisp) { + if (SEQ_time_right_handle_frame_get(cur) < SEQ_time_left_handle_frame_get(seq) || + SEQ_time_left_handle_frame_get(cur) > SEQ_time_right_handle_frame_get(seq)) { return false; } @@ -290,8 +291,8 @@ static void sequencer_all_free_anim_ibufs(Editing *ed, } else { /* Limit frame range to meta strip. */ - meta_range[0] = max_ii(frame_range[0], seq->startdisp); - meta_range[1] = min_ii(frame_range[1], seq->enddisp); + meta_range[0] = max_ii(frame_range[0], SEQ_time_left_handle_frame_get(seq)); + meta_range[1] = min_ii(frame_range[1], SEQ_time_right_handle_frame_get(seq)); } sequencer_all_free_anim_ibufs(ed, &seq->seqbase, timeline_frame, meta_range); @@ -345,7 +346,7 @@ bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports) RPT_WARNING, "Recursion detected in video sequencer. Strip %s at frame %d will not be rendered", recursive_seq->name + 2, - recursive_seq->startdisp); + SEQ_time_left_handle_frame_get(recursive_seq)); LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) { if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) { diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index e4f7a5e87e8..4d6efb1639b 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -27,6 +27,7 @@ #include "SEQ_time.h" #include "SEQ_transform.h" +#include "sequencer.h" #include "strip_time.h" #include "utils.h" @@ -37,7 +38,7 @@ float seq_give_frame_index(Sequence *seq, float timeline_frame) int end = seq->start + seq->len - 1; if (seq->type & SEQ_TYPE_EFFECT) { - end = seq->enddisp; + end = SEQ_time_right_handle_frame_get(seq); } if (end < sta) { @@ -89,7 +90,7 @@ static int metaseq_end(Sequence *metaseq) return metaseq->start + metaseq->len - metaseq->endofs; } -static void seq_update_sound_bounds_recursive_impl(Scene *scene, +static void seq_update_sound_bounds_recursive_impl(const Scene *scene, Sequence *metaseq, int start, int end) @@ -131,33 +132,31 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene, } } -void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq) +void seq_update_sound_bounds_recursive(const Scene *scene, Sequence *metaseq) { seq_update_sound_bounds_recursive_impl( scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq)); } -static void seq_time_update_sequence_bounds(Scene *scene, Sequence *seq) +/* Update meta strip content start and end, update sound playback range. */ +void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta) { - seq->startdisp = seq->start + seq->startofs; - seq->enddisp = seq->start + seq->len - seq->endofs; - - if (seq->type == SEQ_TYPE_META) { - seq_update_sound_bounds_recursive(scene, seq); + if (seq_meta == NULL) { + return; } -} -static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta) -{ if (BLI_listbase_is_empty(&seq_meta->seqbase)) { return; } + const int strip_start = SEQ_time_left_handle_frame_get(seq_meta); + const int strip_end = SEQ_time_right_handle_frame_get(seq_meta); + int min = MAXFRAME * 2; int max = -MAXFRAME * 2; LISTBASE_FOREACH (Sequence *, seq, &seq_meta->seqbase) { - min = min_ii(seq->startdisp, min); - max = max_ii(seq->enddisp, max); + min = min_ii(SEQ_time_left_handle_frame_get(seq), min); + max = max_ii(SEQ_time_right_handle_frame_get(seq), max); } seq_meta->start = min + seq_meta->anim_startofs; @@ -166,144 +165,58 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta) seq_meta->len -= seq_meta->anim_endofs; seq_update_sound_bounds_recursive(scene, seq_meta); -} - -void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta) -{ - if (seq_meta == NULL) { - return; - } - - seq_time_update_meta_strip(scene, seq_meta); /* Prevent meta-strip to move in timeline. */ - SEQ_time_left_handle_frame_set(seq_meta, seq_meta->startdisp); - SEQ_time_right_handle_frame_set(seq_meta, seq_meta->enddisp); + SEQ_time_left_handle_frame_set(scene, seq_meta, strip_start); + SEQ_time_right_handle_frame_set(scene, seq_meta, strip_end); } -void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq) +void seq_time_effect_range_set(Sequence *seq) { - Sequence *seqm; - - /* Check all meta-strips recursively. */ - seqm = seq->seqbase.first; - while (seqm) { - if (seqm->seqbase.first) { - SEQ_time_update_sequence(scene, &seqm->seqbase, seqm); - } - seqm = seqm->next; + if (seq->seq1 == NULL && seq->seq2 == NULL) { + return; } - /* effects and meta: automatic start and end */ - if (seq->type & SEQ_TYPE_EFFECT) { - if (seq->seq1) { - seq->startofs = seq->endofs = 0; - if (seq->seq3) { - seq->start = seq->startdisp = max_iii( - seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp); - seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp); - } - else if (seq->seq2) { - seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp); - seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp); - } - else { - seq->start = seq->startdisp = seq->seq1->startdisp; - seq->enddisp = seq->seq1->enddisp; - } - /* we can't help if strips don't overlap, it won't give useful results. - * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */ - if (seq->enddisp < seq->startdisp) { - /* simple start/end swap */ - seq->start = seq->enddisp; - seq->enddisp = seq->startdisp; - seq->startdisp = seq->start; - seq->flag |= SEQ_INVALID_EFFECT; - } - else { - seq->flag &= ~SEQ_INVALID_EFFECT; - } - - seq->len = seq->enddisp - seq->startdisp; - } - else { - seq_time_update_sequence_bounds(scene, seq); - } + if (seq->seq1 && seq->seq2) { /* 2 - input effect. */ + seq->startdisp = max_ii(SEQ_time_left_handle_frame_get(seq->seq1), + SEQ_time_left_handle_frame_get(seq->seq2)); + seq->enddisp = min_ii(SEQ_time_right_handle_frame_get(seq->seq1), + SEQ_time_right_handle_frame_get(seq->seq2)); } - else if (seq->type == SEQ_TYPE_META) { - seq_time_update_meta_strip(scene, seq); + else if (seq->seq1) { /* Single input effect. */ + seq->startdisp = SEQ_time_right_handle_frame_get(seq->seq1); + seq->enddisp = SEQ_time_left_handle_frame_get(seq->seq1); } - else { - seq_time_update_sequence_bounds(scene, seq); + else if (seq->seq2) { /* Strip may be missing one of inputs. */ + seq->startdisp = SEQ_time_right_handle_frame_get(seq->seq2); + seq->enddisp = SEQ_time_left_handle_frame_get(seq->seq2); } - Editing *ed = SEQ_editing_get(scene); - - /* Strip is inside meta strip */ - if (seqbase != &ed->seqbase) { - Sequence *meta = SEQ_get_meta_by_seqbase(&ed->seqbase, seqbase); - SEQ_time_update_meta_strip_range(scene, meta); + if (seq->startdisp > seq->enddisp) { + SWAP(int, seq->startdisp, seq->enddisp); } - seq_time_update_sequence_bounds(scene, seq); + /* Values unusable for effects, these should be always 0. */ + seq->startofs = seq->endofs = seq->anim_startofs = seq->anim_endofs = 0; } -static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq) +/* Update strip startdisp and enddisp (n-input effects have no len to calculate these). */ +void seq_time_update_effects_strip_range(const Scene *scene, SeqCollection *effects) { - Sequence *subseq; - bool do_update = false; - - /* recurse downwards to see if this seq depends on the changed seq */ - - if (seq == NULL) { - return false; - } - - if (seq == changed_seq) { - do_update = true; - } - - for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) { - if (update_changed_seq_recurs(scene, subseq, changed_seq)) { - do_update = true; - } - } - - if (seq->seq1) { - if (update_changed_seq_recurs(scene, seq->seq1, changed_seq)) { - do_update = true; - } - } - if (seq->seq2 && (seq->seq2 != seq->seq1)) { - if (update_changed_seq_recurs(scene, seq->seq2, changed_seq)) { - do_update = true; - } - } - if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) { - if (update_changed_seq_recurs(scene, seq->seq3, changed_seq)) { - do_update = true; - } - } - - if (do_update) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); + if (effects == NULL) { + return; } - return do_update; -} - -void SEQ_time_update_recursive(Scene *scene, Sequence *changed_seq) -{ - Editing *ed = SEQ_editing_get(scene); Sequence *seq; - - if (ed == NULL) { - return; + /* First pass: Update length of immediate effects. */ + SEQ_ITERATOR_FOREACH (seq, effects) { + seq_time_effect_range_set(seq); } - for (seq = ed->seqbase.first; seq; seq = seq->next) { - update_changed_seq_recurs(scene, seq, changed_seq); + /* Second pass: Recursive call to update effects in chain and in order, so they inherit length + * correctly. */ + SEQ_ITERATOR_FOREACH (seq, effects) { + seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq)); } } @@ -342,12 +255,14 @@ int SEQ_time_find_next_prev_edit(Scene *scene, } if (do_center) { - seq_frames[0] = (seq->startdisp + seq->enddisp) / 2; + seq_frames[0] = (SEQ_time_left_handle_frame_get(seq) + + SEQ_time_right_handle_frame_get(seq)) / + 2; seq_frames_tot = 1; } else { - seq_frames[0] = seq->startdisp; - seq_frames[1] = seq->enddisp; + seq_frames[0] = SEQ_time_left_handle_frame_get(seq); + seq_frames[1] = SEQ_time_right_handle_frame_get(seq); seq_frames_tot = 2; } @@ -431,11 +346,11 @@ void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect) } LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if (rect->xmin > seq->startdisp - 1) { - rect->xmin = seq->startdisp - 1; + if (rect->xmin > SEQ_time_left_handle_frame_get(seq) - 1) { + rect->xmin = SEQ_time_left_handle_frame_get(seq) - 1; } - if (rect->xmax < seq->enddisp + 1) { - rect->xmax = seq->enddisp + 1; + if (rect->xmax < SEQ_time_right_handle_frame_get(seq) + 1) { + rect->xmax = SEQ_time_right_handle_frame_get(seq) + 1; } if (rect->ymax < seq->machine) { rect->ymax = seq->machine; @@ -507,7 +422,8 @@ void seq_time_gap_info_get(const Scene *scene, bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame) { - return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame); + return (SEQ_time_left_handle_frame_get(seq) <= timeline_frame) && + (SEQ_time_right_handle_frame_get(seq) > timeline_frame); } bool SEQ_time_has_left_still_frames(const Sequence *seq) @@ -525,21 +441,36 @@ bool SEQ_time_has_still_frames(const Sequence *seq) return SEQ_time_has_right_still_frames(seq) || SEQ_time_has_left_still_frames(seq); } -int SEQ_time_left_handle_frame_get(Sequence *seq) +int SEQ_time_left_handle_frame_get(const Sequence *seq) { + if (seq->seq1 || seq->seq2) { + return seq->startdisp; + } + return seq->start + seq->startofs; } -int SEQ_time_right_handle_frame_get(Sequence *seq) + +int SEQ_time_right_handle_frame_get(const Sequence *seq) { + if (seq->seq1 || seq->seq2) { + return seq->enddisp; + } + return seq->start + seq->len - seq->endofs; } -void SEQ_time_left_handle_frame_set(Sequence *seq, int val) +void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int val) { seq->startofs = val - seq->start; + seq->startdisp = val; /* Only to make files usable in older versions. */ + SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq)); + seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq)); } -void SEQ_time_right_handle_frame_set(Sequence *seq, int val) +void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int val) { seq->endofs = seq->start + seq->len - val; + seq->enddisp = val; /* Only to make files usable in older versions. */ + SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq)); + seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq)); } diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h index c96a016e646..7a75aeac1a6 100644 --- a/source/blender/sequencer/intern/strip_time.h +++ b/source/blender/sequencer/intern/strip_time.h @@ -14,9 +14,10 @@ extern "C" { struct ListBase; struct Scene; struct Sequence; +struct SeqCollection; float seq_give_frame_index(struct Sequence *seq, float timeline_frame); -void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq); +void seq_update_sound_bounds_recursive(const struct Scene *scene, struct Sequence *metaseq); /* Describes gap between strips in timeline. */ typedef struct GapInfo { @@ -37,6 +38,8 @@ void seq_time_gap_info_get(const struct Scene *scene, struct ListBase *seqbase, int initial_frame, struct GapInfo *r_gap_info); +void seq_time_effect_range_set(Sequence *seq); +void seq_time_update_effects_strip_range(const struct Scene *scene, struct SeqCollection *effects); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 8ff577240d6..19caf12ff2a 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -13,11 +13,13 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BKE_main.h" #include "BKE_scene.h" #include "BKE_sound.h" #include "SEQ_animation.h" #include "SEQ_channels.h" +#include "SEQ_edit.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" @@ -25,6 +27,9 @@ #include "SEQ_time.h" #include "SEQ_transform.h" +#include "sequencer.h" +#include "strip_time.h" + #include "CLG_log.h" static CLG_LogRef LOG = {"seq.strip_transform"}; @@ -86,16 +91,16 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase) return true; } -void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag) +void SEQ_transform_handle_xlimits(const Scene *scene, Sequence *seq, int leftflag, int rightflag) { if (leftflag) { if (SEQ_time_left_handle_frame_get(seq) >= SEQ_time_right_handle_frame_get(seq)) { - SEQ_time_left_handle_frame_set(seq, SEQ_time_right_handle_frame_get(seq) - 1); + SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(seq) - 1); } if (SEQ_transform_single_image_check(seq) == 0) { if (SEQ_time_left_handle_frame_get(seq) >= seq_tx_get_end(seq)) { - SEQ_time_left_handle_frame_set(seq, seq_tx_get_end(seq) - 1); + SEQ_time_left_handle_frame_set(scene, seq, seq_tx_get_end(seq) - 1); } /* TODO: This doesn't work at the moment. */ @@ -112,12 +117,12 @@ void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag) if (rightflag) { if (SEQ_time_right_handle_frame_get(seq) <= SEQ_time_left_handle_frame_get(seq)) { - SEQ_time_right_handle_frame_set(seq, SEQ_time_left_handle_frame_get(seq) + 1); + SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(seq) + 1); } if (SEQ_transform_single_image_check(seq) == 0) { if (SEQ_time_right_handle_frame_get(seq) <= seq_tx_get_start(seq)) { - SEQ_time_right_handle_frame_set(seq, seq_tx_get_start(seq) + 1); + SEQ_time_right_handle_frame_set(scene, seq, seq_tx_get_start(seq) + 1); } } } @@ -129,7 +134,7 @@ void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag) } } -void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq) +void SEQ_transform_fix_single_image_seq_offsets(const Scene *scene, Sequence *seq) { int left, start, offset; if (!SEQ_transform_single_image_check(seq)) { @@ -142,8 +147,8 @@ void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq) start = seq->start; if (start != left) { offset = left - start; - SEQ_time_left_handle_frame_set(seq, SEQ_time_left_handle_frame_get(seq) - offset); - SEQ_time_right_handle_frame_set(seq, SEQ_time_right_handle_frame_get(seq) - offset); + SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(seq) - offset); + SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(seq) - offset); seq->start += offset; } } @@ -156,7 +161,8 @@ bool SEQ_transform_sequence_can_be_translated(Sequence *seq) bool SEQ_transform_test_overlap_seq_seq(Sequence *seq1, Sequence *seq2) { return (seq1 != seq2 && seq1->machine == seq2->machine && - ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0); + ((SEQ_time_right_handle_frame_get(seq1) <= SEQ_time_left_handle_frame_get(seq2)) || + (SEQ_time_left_handle_frame_get(seq1) >= SEQ_time_right_handle_frame_get(seq2))) == 0); } bool SEQ_transform_test_overlap(ListBase *seqbasep, Sequence *test) @@ -180,9 +186,6 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt return; } - SEQ_offset_animdata(evil_scene, seq, delta); - seq->start += delta; - /* Meta strips requires special handling: their content is to be translated, and then frame range * of the meta is to be updated for the updated content. */ if (seq->type == SEQ_TYPE_META) { @@ -190,16 +193,21 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) { SEQ_transform_translate_sequence(evil_scene, seq_child, delta); } - /* Ensure that meta bounds are updated, but this function prevents resets seq->start and - * start/end point in timeline. */ - SEQ_time_update_meta_strip_range(evil_scene, seq); /* Move meta start/end points. */ - SEQ_time_left_handle_frame_set(seq, seq->startdisp + delta); - SEQ_time_right_handle_frame_set(seq, seq->enddisp + delta); + SEQ_time_left_handle_frame_set(evil_scene, seq, SEQ_time_left_handle_frame_get(seq) + delta); + SEQ_time_right_handle_frame_set(evil_scene, seq, SEQ_time_right_handle_frame_get(seq) + delta); + } + else { /* All other strip types. */ + seq->start += delta; + /* Only to make files usable in older versions. */ + seq->startdisp = SEQ_time_left_handle_frame_get(seq); + seq->enddisp = SEQ_time_right_handle_frame_get(seq); } - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(evil_scene)); - SEQ_time_update_sequence(evil_scene, seqbase, seq); + SEQ_offset_animdata(evil_scene, seq, delta); + SEQ_time_update_meta_strip_range(evil_scene, seq_sequence_lookup_meta_by_seq(evil_scene, seq)); + seq_time_update_effects_strip_range(evil_scene, + seq_sequence_lookup_effects_by_seq(evil_scene, seq)); } bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, @@ -211,16 +219,12 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, BLI_assert(ELEM(channel_delta, -1, 1)); test->machine += channel_delta; - SEQ_time_update_sequence(evil_scene, seqbasep, test); while (SEQ_transform_test_overlap(seqbasep, test)) { if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) { break; } test->machine += channel_delta; - - /* XXX: I don't think this is needed since were only moving vertically, Campbell. */ - SEQ_time_update_sequence(evil_scene, seqbasep, test); } if (!SEQ_valid_strip_channel(test)) { @@ -228,19 +232,18 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, * nicer to move it to the end */ Sequence *seq; - int new_frame = test->enddisp; + int new_frame = SEQ_time_right_handle_frame_get(test); for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->machine == orig_machine) { - new_frame = max_ii(new_frame, seq->enddisp); + new_frame = max_ii(new_frame, SEQ_time_right_handle_frame_get(seq)); } } test->machine = orig_machine; - new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */ + new_frame = new_frame + + (test->start - SEQ_time_left_handle_frame_get(test)); /* adjust by the startdisp */ SEQ_transform_translate_sequence(evil_scene, test, new_frame - test->start); - - SEQ_time_update_sequence(evil_scene, seqbasep, test); return false; } @@ -252,71 +255,68 @@ bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *ev return SEQ_transform_seqbase_shuffle_ex(seqbasep, test, evil_scene, 1); } -static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle, - ListBase *seqbasep, - char dir) +static bool shuffle_seq_test_overlap(const Sequence *seq1, const Sequence *seq2, const int offset) { - int offset = 0; - Sequence *seq; - - SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) { - LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) { - if (!SEQ_transform_test_overlap_seq_seq(seq, seq_other)) { - continue; - } - if (SEQ_relation_is_effect_of_strip(seq_other, seq)) { - continue; - } - if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) { - CLOG_WARN(&LOG, - "Strip overlaps with itself or another strip, that is to be shuffled. " - "This should never happen."); - continue; - } - if (dir == 'L') { - offset = min_ii(offset, seq_other->startdisp - seq->enddisp); - } - else { - offset = max_ii(offset, seq_other->enddisp - seq->startdisp); - } - } - } - return offset; + return ( + seq1 != seq2 && seq1->machine == seq2->machine && + ((SEQ_time_right_handle_frame_get(seq1) + offset <= SEQ_time_left_handle_frame_get(seq2)) || + (SEQ_time_left_handle_frame_get(seq1) + offset >= SEQ_time_right_handle_frame_get(seq2))) == + 0); } -static int shuffle_seq_time_offset(SeqCollection *strips_to_shuffle, - ListBase *seqbasep, - Scene *scene, - char dir) +static int shuffle_seq_time_offset_get(SeqCollection *strips_to_shuffle, + ListBase *seqbasep, + char dir) { - int ofs = 0; - int tot_ofs = 0; + int offset = 0; Sequence *seq; - while ((ofs = shuffle_seq_time_offset_test(strips_to_shuffle, seqbasep, dir))) { + bool all_conflicts_resolved = false; + + while (!all_conflicts_resolved) { + all_conflicts_resolved = true; SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) { - /* seq_test_overlap only tests display values */ - seq->startdisp += ofs; - seq->enddisp += ofs; - } + LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) { + if (!shuffle_seq_test_overlap(seq, seq_other, offset)) { + continue; + } + if (SEQ_relation_is_effect_of_strip(seq_other, seq)) { + continue; + } + if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) { + CLOG_WARN(&LOG, + "Strip overlaps with itself or another strip, that is to be shuffled. " + "This should never happen."); + continue; + } - tot_ofs += ofs; - } + all_conflicts_resolved = false; - SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) { - SEQ_time_update_sequence(scene, seqbasep, seq); /* corrects dummy startdisp/enddisp values */ + if (dir == 'L') { + offset = min_ii(offset, + SEQ_time_left_handle_frame_get(seq_other) - + SEQ_time_right_handle_frame_get(seq)); + } + else { + offset = max_ii(offset, + SEQ_time_right_handle_frame_get(seq_other) - + SEQ_time_left_handle_frame_get(seq)); + } + } + } } - return tot_ofs; + return offset; } bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle, + SeqCollection *time_dependent_strips, ListBase *seqbasep, Scene *evil_scene, ListBase *markers, const bool use_sync_markers) { - int offset_l = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'L'); - int offset_r = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'R'); + int offset_l = shuffle_seq_time_offset_get(strips_to_shuffle, seqbasep, 'L'); + int offset_r = shuffle_seq_time_offset_get(strips_to_shuffle, seqbasep, 'R'); int offset = (-offset_l < offset_r) ? offset_l : offset_r; if (offset) { @@ -326,6 +326,12 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle, seq->flag &= ~SEQ_OVERLAP; } + if (time_dependent_strips != NULL) { + SEQ_ITERATOR_FOREACH (seq, time_dependent_strips) { + SEQ_offset_animdata(evil_scene, seq, offset); + } + } + if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) { TimeMarker *marker; /* affect selected markers - it's unlikely that we will want to affect all in this way? */ @@ -340,15 +346,304 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle, return offset ? false : true; } +static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips) +{ + SeqCollection *collection = SEQ_collection_create(__func__); + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, transformed_strips) { + if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) { + SEQ_collection_append_strip(seq, collection); + } + } + return collection; +} + +/* Query strips positioned after left edge of transformed strips bound-box. */ +static SeqCollection *query_right_side_strips(ListBase *seqbase, + SeqCollection *transformed_strips, + SeqCollection *time_dependent_strips) +{ + int minframe = MAXFRAME; + { + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, transformed_strips) { + minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq)); + } + } + + SeqCollection *collection = SEQ_collection_create(__func__); + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (SEQ_collection_has_strip(seq, time_dependent_strips)) { + continue; + } + if (SEQ_collection_has_strip(seq, transformed_strips)) { + continue; + } + + if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) { + SEQ_collection_append_strip(seq, collection); + } + } + return collection; +} + +/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal + * to overlap of transformed strips. */ +static void seq_transform_handle_expand_to_fit(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips, + SeqCollection *time_dependent_strips, + bool use_sync_markers) +{ + ListBase *markers = &scene->markers; + + SeqCollection *right_side_strips = query_right_side_strips( + seqbasep, transformed_strips, time_dependent_strips); + + /* Temporarily move right side strips beyond timeline boundary. */ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, right_side_strips) { + seq->machine += MAXSEQ * 2; + } + + /* Shuffle transformed standalone strips. This is because transformed strips can overlap with + * strips on left side. */ + SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips); + SEQ_transform_seqbase_shuffle_time( + standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers); + SEQ_collection_free(standalone_strips); + + /* Move temporarily moved strips back to their original place and tag for shuffling. */ + SEQ_ITERATOR_FOREACH (seq, right_side_strips) { + seq->machine -= MAXSEQ * 2; + } + /* Shuffle again to displace strips on right side. Final effect shuffling is done in + * SEQ_transform_handle_overlap. */ + SEQ_transform_seqbase_shuffle_time( + right_side_strips, NULL, seqbasep, scene, markers, use_sync_markers); + SEQ_collection_free(right_side_strips); +} + +static SeqCollection *query_overwrite_targets(ListBase *seqbasep, + SeqCollection *transformed_strips) +{ + SeqCollection *collection = SEQ_query_unselected_strips(seqbasep); + + Sequence *seq, *seq_transformed; + SEQ_ITERATOR_FOREACH (seq, collection) { + bool does_overlap = false; + + SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) { + /* Effects of transformed strips can be unselected. These must not be included. */ + if (seq == seq_transformed) { + SEQ_collection_remove_strip(seq, collection); + } + if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) { + does_overlap = true; + } + } + + if (!does_overlap) { + SEQ_collection_remove_strip(seq, collection); + } + } + + return collection; +} + +typedef enum eOvelapDescrition { + /* No overlap. */ + STRIP_OVERLAP_NONE, + /* Overlapping strip covers overlapped completely. */ + STRIP_OVERLAP_IS_FULL, + /* Overlapping strip is inside overlapped. */ + STRIP_OVERLAP_IS_INSIDE, + /* Partial overlap between 2 strips. */ + STRIP_OVERLAP_LEFT_SIDE, + STRIP_OVERLAP_RIGHT_SIDE, +} eOvelapDescrition; + +static eOvelapDescrition overlap_description_get(const Sequence *transformed, + const Sequence *target) +{ + if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) && + SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) { + return STRIP_OVERLAP_IS_FULL; + } + if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) && + SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) { + return STRIP_OVERLAP_IS_INSIDE; + } + if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) && + SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) { + return STRIP_OVERLAP_LEFT_SIDE; + } + if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) && + SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) { + return STRIP_OVERLAP_RIGHT_SIDE; + } + return STRIP_OVERLAP_NONE; +} + +/* Split strip in 3 parts, remove middle part and fit transformed inside. */ +static void seq_transform_handle_overwrite_split(Scene *scene, + ListBase *seqbasep, + const Sequence *transformed, + Sequence *target) +{ + /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass + * NULL here. */ + Main *bmain = NULL; + + Sequence *split_strip = SEQ_edit_strip_split(bmain, + scene, + seqbasep, + target, + SEQ_time_left_handle_frame_get(transformed), + SEQ_SPLIT_SOFT, + NULL); + SEQ_edit_strip_split(bmain, + scene, + seqbasep, + split_strip, + SEQ_time_right_handle_frame_get(transformed), + SEQ_SPLIT_SOFT, + NULL); + SEQ_edit_flag_for_removal(scene, seqbasep, split_strip); + SEQ_edit_remove_flagged_sequences(scene, seqbasep); +} + +/* Trim strips by adjusting handle position. + * This is bit more complicated in case overlap happens on effect. */ +static void seq_transform_handle_overwrite_trim(Scene *scene, + ListBase *seqbasep, + const Sequence *transformed, + Sequence *target, + const eOvelapDescrition overlap) +{ + SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain); + + /* Expand collection by adding all target's children, effects and their children. */ + if ((target->type & SEQ_TYPE_EFFECT) != 0) { + SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain); + } + + /* Trim all non effects, that have influence on effect length which is overlapping. */ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, targets) { + if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) { + continue; + } + if (overlap == STRIP_OVERLAP_LEFT_SIDE) { + SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed)); + } + else { + BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE); + SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed)); + } + } + SEQ_collection_free(targets); +} + +static void seq_transform_handle_overwrite(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips) +{ + SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips); + SeqCollection *strips_to_delete = SEQ_collection_create(__func__); + + Sequence *target; + Sequence *transformed; + SEQ_ITERATOR_FOREACH (target, targets) { + SEQ_ITERATOR_FOREACH (transformed, transformed_strips) { + if (transformed->machine != target->machine) { + continue; + } + + const eOvelapDescrition overlap = overlap_description_get(transformed, target); + + if (overlap == STRIP_OVERLAP_IS_FULL) { + SEQ_collection_append_strip(target, strips_to_delete); + } + else if (overlap == STRIP_OVERLAP_IS_INSIDE) { + seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target); + } + else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) { + seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap); + } + } + } + + SEQ_collection_free(targets); + + /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()` + * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */ + if (SEQ_collection_len(strips_to_delete) > 0) { + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, strips_to_delete) { + SEQ_edit_flag_for_removal(scene, seqbasep, seq); + } + SEQ_edit_remove_flagged_sequences(scene, seqbasep); + } + SEQ_collection_free(strips_to_delete); +} + +static void seq_transform_handle_overlap_shuffle(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips, + SeqCollection *time_dependent_strips, + bool use_sync_markers) +{ + ListBase *markers = &scene->markers; + + /* Shuffle non strips with no effects attached. */ + SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips); + SEQ_transform_seqbase_shuffle_time( + standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers); + SEQ_collection_free(standalone_strips); +} + +void SEQ_transform_handle_overlap(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips, + SeqCollection *time_dependent_strips, + bool use_sync_markers) +{ + const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene); + + switch (overlap_mode) { + case SEQ_OVERLAP_EXPAND: + seq_transform_handle_expand_to_fit( + scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers); + break; + case SEQ_OVERLAP_OVERWRITE: + seq_transform_handle_overwrite(scene, seqbasep, transformed_strips); + break; + case SEQ_OVERLAP_SHUFFLE: + seq_transform_handle_overlap_shuffle( + scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers); + break; + } + + /* If any effects still overlap, we need to move them up. + * In some cases other strips can be overlapping still, see T90646. */ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, transformed_strips) { + if (SEQ_transform_test_overlap(seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(seqbasep, seq, scene); + } + seq->flag &= ~SEQ_OVERLAP; + } +} + void SEQ_transform_offset_after_frame(Scene *scene, ListBase *seqbase, const int delta, const int timeline_frame) { LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if (seq->startdisp >= timeline_frame) { + if (SEQ_time_left_handle_frame_get(seq) >= timeline_frame) { SEQ_transform_translate_sequence(scene, seq, delta); - SEQ_time_update_sequence(scene, seqbase, seq); SEQ_relations_invalidate_cache_preprocessed(scene, seq); } } diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 0cf47420d8f..3cfe63e284f 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -39,55 +39,9 @@ #include "multiview.h" #include "proxy.h" +#include "sequencer.h" #include "utils.h" -void SEQ_sort(ListBase *seqbase) -{ - if (seqbase == NULL) { - return; - } - - /* all strips together per kind, and in order of y location ("machine") */ - ListBase inputbase, effbase; - Sequence *seq, *seqt; - - BLI_listbase_clear(&inputbase); - BLI_listbase_clear(&effbase); - - while ((seq = BLI_pophead(seqbase))) { - - if (seq->type & SEQ_TYPE_EFFECT) { - seqt = effbase.first; - while (seqt) { - if (seqt->machine >= seq->machine) { - BLI_insertlinkbefore(&effbase, seqt, seq); - break; - } - seqt = seqt->next; - } - if (seqt == NULL) { - BLI_addtail(&effbase, seq); - } - } - else { - seqt = inputbase.first; - while (seqt) { - if (seqt->machine >= seq->machine) { - BLI_insertlinkbefore(&inputbase, seqt, seq); - break; - } - seqt = seqt->next; - } - if (seqt == NULL) { - BLI_addtail(&inputbase, seq); - } - } - } - - BLI_movelisttolist(seqbase, &inputbase); - BLI_movelisttolist(seqbase, &effbase); -} - typedef struct SeqUniqueInfo { Sequence *seq; char name_src[SEQ_NAME_MAXSTR]; @@ -263,7 +217,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0; - if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) { + if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL) && !openfile) { return; } @@ -414,20 +368,18 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame) return best_seq; } -ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq) +ListBase *SEQ_get_seqbase_by_seq(const Scene *scene, Sequence *seq) { - Sequence *iseq; - ListBase *lb = NULL; + Editing *ed = SEQ_editing_get(scene); + ListBase *main_seqbase = &ed->seqbase; + Sequence *seq_meta = seq_sequence_lookup_meta_by_seq(scene, seq); - for (iseq = seqbase->first; iseq; iseq = iseq->next) { - if (seq == iseq) { - return seqbase; - } - if (iseq->seqbase.first && (lb = SEQ_get_seqbase_by_seq(&iseq->seqbase, seq))) { - return lb; - } + if (seq_meta != NULL) { + return &seq_meta->seqbase; + } + if (BLI_findindex(main_seqbase, seq) >= 0) { + return main_seqbase; } - return NULL; } diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 73a5f1e6f8d..4c553d0edfe 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -39,7 +39,7 @@ set(SRC intern/wm_dragdrop.c intern/wm_draw.c intern/wm_event_query.c - intern/wm_event_system.c + intern/wm_event_system.cc intern/wm_files.c intern/wm_files_link.c intern/wm_gesture.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 890872a06bc..60cded3b869 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -388,6 +388,12 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C, wmUIHandlerRemoveFunc remove_fn, void *user_data, char flag); + +/** + * Return the first modal operator of type \a ot or NULL. + */ +wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot); + /** * \param postpone: Enable for `win->modalhandlers`, * this is in a running for () loop in wm_handlers_do(). @@ -732,6 +738,7 @@ void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct Pointe wmOperator *WM_operator_last_redo(const struct bContext *C); /** * Use for drag & drop a path or name with operators invoke() function. + * Returns null if no operator property is set to identify the file or ID to use. */ ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode); @@ -1400,6 +1407,14 @@ void WM_jobs_callbacks(struct wmJob *, void (*update)(void *), void (*endjob)(void *)); +void WM_jobs_callbacks_ex(wmJob *wm_job, + wm_jobs_start_callback startjob, + void (*initjob)(void *), + void (*update)(void *), + void (*endjob)(void *), + void (*completed)(void *), + void (*canceled)(void *)); + /** * If job running, the same owner gave it a new job. * if different owner starts existing startjob, it suspends itself @@ -1426,6 +1441,7 @@ void WM_jobs_kill_all_except(struct wmWindowManager *wm, const void *owner); void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type); bool WM_jobs_has_running(const struct wmWindowManager *wm); +bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type); void WM_job_main_thread_lock_acquire(struct wmJob *job); void WM_job_main_thread_lock_release(struct wmJob *job); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 9e9f195c430..aebd62ee91b 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -616,6 +616,7 @@ typedef enum eWM_EventFlag { */ WM_EVENT_FORCE_DRAG_THRESHOLD = (1 << 2), } eWM_EventFlag; +ENUM_OPERATORS(eWM_EventFlag, WM_EVENT_FORCE_DRAG_THRESHOLD); typedef struct wmTabletData { /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */ diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h index 80d29bb8c40..663c8a0baed 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h @@ -388,6 +388,8 @@ void WM_gizmomap_message_subscribe(const struct bContext *C, struct ARegion *region, struct wmMsgBus *mbus); bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap); +struct wmGizmo *WM_gizmomap_get_modal(const struct wmGizmoMap *gzmap); + /** * \note We could use a callback to define bounds, for now just use matrix location. */ diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index f481f19045d..f5974a2176b 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -229,6 +229,11 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap) return gzmap->gzmap_context.select.len != 0; } +wmGizmo *WM_gizmomap_get_modal(const wmGizmoMap *gzmap) +{ + return gzmap->gzmap_context.modal; +} + bool WM_gizmomap_minmax(const wmGizmoMap *gzmap, bool UNUSED(use_hidden), bool use_select, @@ -669,7 +674,7 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C, * This way we always use the first hit. */ if (has_3d) { - /* The depth buffer is needed for for gizmos to obscure eachother. */ + /* The depth buffer is needed for for gizmos to obscure each other. */ GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C)); /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c index af083630623..1c257424297 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c @@ -345,7 +345,7 @@ void WM_gizmo_target_property_anim_autokey(bContext *C, Scene *scene = CTX_data_scene(C); const float cfra = (float)CFRA; const int index = gz_prop->index == -1 ? 0 : gz_prop->index; - ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra); + ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra, false); } } diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index b7066178abd..fc992ef069d 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -383,7 +383,7 @@ void WM_cursor_time(wmWindow *win, int nr) /** * Because defining a cursor mixes declarations and executable code * each cursor needs its own scoping block or it would be split up - * over several hundred lines of code. To enforce/document this better + * over several hundred lines of code. To enforce/document this better * I define 2 pretty brain-dead macros so it's obvious what the extra "[]" * are for */ diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 8f96080c810..09ef4e15012 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -827,7 +827,7 @@ static void wm_drag_draw_icon(bContext *UNUSED(C), x = xy[0] - (wm_drag_imbuf_icon_width_get(drag) / 2); y = xy[1] - (wm_drag_imbuf_icon_height_get(drag) / 2); - float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ + const float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); immDrawPixelsTexTiled_scaling(&state, x, diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index d2ade7b0376..aaa28b1fd85 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -41,6 +41,7 @@ #include "GPU_debug.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" +#include "GPU_matrix.h" #include "GPU_state.h" #include "GPU_texture.h" #include "GPU_viewport.h" @@ -119,6 +120,216 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Draw Software Cursor + * + * Draw the cursor instead of relying on the graphical environment. + * Needed when setting the cursor position (warping) isn't supported (GHOST/WAYLAND). + * \{ */ + +/** + * Track the state of the last drawn cursor. + */ +static struct { + int8_t enabled; + int winid; + int xy[2]; +} g_software_cursor = { + .enabled = -1, + .winid = -1, +}; + +/** Reuse the result from #GHOST_GetCursorGrabState. */ +struct GrabState { + GHOST_TGrabCursorMode mode; + GHOST_TAxisFlag wrap_axis; + int bounds[4]; +}; + +static bool wm_software_cursor_needed(void) +{ + if (UNLIKELY(g_software_cursor.enabled == -1)) { + g_software_cursor.enabled = !GHOST_SupportsCursorWarp(); + } + return g_software_cursor.enabled; +} + +static bool wm_software_cursor_needed_for_window(const wmWindow *win, struct GrabState *grab_state) +{ + BLI_assert(wm_software_cursor_needed()); + if (GHOST_GetCursorVisibility(win->ghostwin)) { + /* NOTE: The value in `win->grabcursor` can't be used as it + * doesn't always match GHOST's value in the case of tablet events. */ + bool use_software_cursor; + GHOST_GetCursorGrabState(win->ghostwin, + &grab_state->mode, + &grab_state->wrap_axis, + grab_state->bounds, + &use_software_cursor); + if (use_software_cursor) { + return true; + } + } + return false; +} + +static bool wm_software_cursor_motion_test(const wmWindow *win) +{ + return (g_software_cursor.winid != win->winid) || + (g_software_cursor.xy[0] != win->eventstate->xy[0]) || + (g_software_cursor.xy[1] != win->eventstate->xy[1]); +} + +static void wm_software_cursor_motion_update(const wmWindow *win) +{ + + g_software_cursor.winid = win->winid; + g_software_cursor.xy[0] = win->eventstate->xy[0]; + g_software_cursor.xy[1] = win->eventstate->xy[1]; +} + +static void wm_software_cursor_motion_clear(void) +{ + g_software_cursor.winid = -1; + g_software_cursor.xy[0] = -1; + g_software_cursor.xy[1] = -1; +} + +static void wm_software_cursor_draw_bitmap(const int event_xy[2], + const GHOST_CursorBitmapRef *bitmap) +{ + GPU_blend(GPU_BLEND_ALPHA); + + float gl_matrix[4][4]; + GPUTexture *texture = GPU_texture_create_2d( + "softeare_cursor", bitmap->data_size[0], bitmap->data_size[1], 1, GPU_RGBA8, NULL); + GPU_texture_update(texture, GPU_DATA_UBYTE, bitmap->data); + GPU_texture_filter_mode(texture, false); + + GPU_matrix_push(); + + const int scale = (int)U.pixelsize; + + unit_m4(gl_matrix); + + gl_matrix[3][0] = event_xy[0] - (bitmap->hot_spot[0] * scale); + gl_matrix[3][1] = event_xy[1] - ((bitmap->data_size[1] - bitmap->hot_spot[1]) * scale); + + gl_matrix[0][0] = bitmap->data_size[0] * scale; + gl_matrix[1][1] = bitmap->data_size[1] * scale; + + GPU_matrix_mul(gl_matrix); + + GPUVertFormat *imm_format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint texCoord = GPU_vertformat_attr_add( + imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + /* Use 3D image for correct display of planar tracked images. */ + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + + immBindTexture("image", texture); + immUniform1f("alpha", 1.0f); + + immBegin(GPU_PRIM_TRI_FAN, 4); + + immAttr2f(texCoord, 0.0f, 1.0f); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + + immAttr2f(texCoord, 1.0f, 1.0f); + immVertex3f(pos, 1.0f, 0.0f, 0.0f); + + immAttr2f(texCoord, 1.0f, 0.0f); + immVertex3f(pos, 1.0f, 1.0f, 0.0f); + + immAttr2f(texCoord, 0.0f, 0.0f); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + + immEnd(); + + immUnbindProgram(); + + GPU_matrix_pop(); + GPU_texture_unbind(texture); + GPU_texture_free(texture); + + GPU_blend(GPU_BLEND_NONE); +} + +static void wm_software_cursor_draw_crosshair(const int event_xy[2]) +{ + /* Draw a primitive cross-hair cursor. + * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors + * are set by the operating-system, where the pixel information isn't easily available. */ + const float unit = max_ff(U.dpi_fac, 1.0f); + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4f(1, 1, 1, 1); + { + const int ofs_line = (8 * unit); + const int ofs_size = (2 * unit); + immRecti(pos, + event_xy[0] - ofs_line, + event_xy[1] - ofs_size, + event_xy[0] + ofs_line, + event_xy[1] + ofs_size); + immRecti(pos, + event_xy[0] - ofs_size, + event_xy[1] - ofs_line, + event_xy[0] + ofs_size, + event_xy[1] + ofs_line); + } + immUniformColor4f(0, 0, 0, 1); + { + const int ofs_line = (7 * unit); + const int ofs_size = (1 * unit); + immRecti(pos, + event_xy[0] - ofs_line, + event_xy[1] - ofs_size, + event_xy[0] + ofs_line, + event_xy[1] + ofs_size); + immRecti(pos, + event_xy[0] - ofs_size, + event_xy[1] - ofs_line, + event_xy[0] + ofs_size, + event_xy[1] + ofs_line); + } + immUnbindProgram(); +} + +static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state) +{ + int event_xy[2] = {UNPACK2(win->eventstate->xy)}; + + if (grab_state->wrap_axis & GHOST_kAxisX) { + const int min = grab_state->bounds[0]; + const int max = grab_state->bounds[2]; + if (min != max) { + event_xy[0] = mod_i(event_xy[0] - min, max - min) + min; + } + } + if (grab_state->wrap_axis & GHOST_kGrabAxisY) { + const int height = WM_window_pixels_y(win); + const int min = height - grab_state->bounds[1]; + const int max = height - grab_state->bounds[3]; + if (min != max) { + event_xy[1] = mod_i(event_xy[1] - max, min - max) + max; + } + } + + GHOST_CursorBitmapRef bitmap = {0}; + if (GHOST_GetCursorBitmap(win->ghostwin, &bitmap) == GHOST_kSuccess) { + wm_software_cursor_draw_bitmap(event_xy, &bitmap); + } + else { + wm_software_cursor_draw_crosshair(event_xy); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Post Draw Region on display handlers * \{ */ @@ -862,6 +1073,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) /* always draw, not only when screen tagged */ if (win->gesture.first) { wm_gesture_draw(win); + wmWindowViewport(win); } /* Needs pixel coords in screen. */ @@ -870,6 +1082,17 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) wmWindowViewport(win); } + if (wm_software_cursor_needed()) { + struct GrabState grab_state; + if (wm_software_cursor_needed_for_window(win, &grab_state)) { + wm_software_cursor_draw(win, &grab_state); + wm_software_cursor_motion_update(win); + } + else { + wm_software_cursor_motion_clear(); + } + } + GPU_debug_group_end(); } @@ -1020,6 +1243,22 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win) return true; } + if (wm_software_cursor_needed()) { + struct GrabState grab_state; + if (wm_software_cursor_needed_for_window(win, &grab_state)) { + if (wm_software_cursor_motion_test(win)) { + return true; + } + } + else { + /* Detect the edge case when the previous draw used the software cursor but this one doesn't, + * it's important to redraw otherwise the software cursor will remain displayed. */ + if (g_software_cursor.winid != -1) { + return true; + } + } + } + #ifndef WITH_XR_OPENXR UNUSED_VARS(wm); #endif diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.cc index 3ff3117dafe..51486f664c7 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -9,9 +9,9 @@ * Also some operator reports utility functions. */ -#include <math.h> -#include <stdlib.h> -#include <string.h> +#include <cmath> +#include <cstdlib> +#include <cstring> #include "DNA_listBase.h" #include "DNA_scene_types.h" @@ -116,11 +116,11 @@ wmEvent *wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after) { - wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent"); + wmEvent *event = MEM_new<wmEvent>(__func__); *event = *event_to_add; - if (event_to_add_after == NULL) { + if (event_to_add_after == nullptr) { BLI_addtail(&win->event_queue, event); } else { @@ -133,14 +133,14 @@ wmEvent *wm_event_add_ex(wmWindow *win, wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add) { - return wm_event_add_ex(win, event_to_add, NULL); + return wm_event_add_ex(win, event_to_add, nullptr); } wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add) { if ((G.f & G_FLAG_EVENT_SIMULATE) == 0) { BLI_assert_unreachable(); - return NULL; + return nullptr; } wmEvent *event = wm_event_add(win, event_to_add); @@ -166,7 +166,7 @@ static void wm_event_custom_free(wmEvent *event) /* NOTE: pointer to #ListBase struct elsewhere. */ if (event->custom == EVT_DATA_DRAGDROP) { - ListBase *lb = event->customdata; + ListBase *lb = static_cast<ListBase *>(event->customdata); WM_drag_free_list(lb); } else { @@ -177,7 +177,7 @@ static void wm_event_custom_free(wmEvent *event) static void wm_event_custom_clear(wmEvent *event) { event->custom = 0; - event->customdata = NULL; + event->customdata = nullptr; event->customdata_free = false; } @@ -209,7 +209,7 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event) * As this function should be interchangeable with #wm_event_free. */ #ifndef NDEBUG { - wmEvent *event_copy = MEM_dupallocN(event); + wmEvent *event_copy = static_cast<wmEvent *>(MEM_dupallocN(event)); MEM_freeN(event); event = event_copy; } @@ -227,8 +227,8 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event) static void wm_event_free_last(wmWindow *win) { - wmEvent *event = BLI_poptail(&win->event_queue); - if (event != NULL) { + wmEvent *event = static_cast<wmEvent *>(BLI_poptail(&win->event_queue)); + if (event != nullptr) { wm_event_free(event); } } @@ -236,7 +236,7 @@ static void wm_event_free_last(wmWindow *win) void wm_event_free_all(wmWindow *win) { wmEvent *event; - while ((event = BLI_pophead(&win->event_queue))) { + while ((event = static_cast<wmEvent *>(BLI_pophead(&win->event_queue)))) { wm_event_free(event); } } @@ -270,7 +270,7 @@ void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint typ return; } - wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier"); + wmNotifier *note = MEM_cnew<wmNotifier>(__func__); BLI_addtail(&wm->notifier_queue, note); @@ -293,13 +293,13 @@ void WM_event_add_notifier(const bContext *C, uint type, void *reference) void WM_main_add_notifier(unsigned int type, void *reference) { Main *bmain = G_MAIN; - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); if (!wm || wm_test_duplicate_notifier(wm, type, reference)) { return; } - wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier"); + wmNotifier *note = MEM_cnew<wmNotifier>(__func__); BLI_addtail(&wm->notifier_queue, note); @@ -314,7 +314,7 @@ void WM_main_add_notifier(unsigned int type, void *reference) void WM_main_remove_notifier_reference(const void *reference) { Main *bmain = G_MAIN; - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); if (wm) { LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) { @@ -341,8 +341,8 @@ static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_da static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data) { - struct wmMsgBus *mbus = user_data; - if (new_id != NULL) { + wmMsgBus *mbus = static_cast<wmMsgBus *>(user_data); + if (new_id != nullptr) { WM_msg_id_update(mbus, old_id, new_id); } else { @@ -350,7 +350,7 @@ static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data) } } -void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings) +void WM_main_remap_editor_id_reference(const IDRemapper *mappings) { Main *bmain = G_MAIN; @@ -362,9 +362,9 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings) } } - BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, NULL); + BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, nullptr); - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); if (wm && wm->message_bus) { BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus); } @@ -372,7 +372,7 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings) static void wm_notifier_clear(wmNotifier *note) { - /* NULL the entire notifier, only leaving (`next`, `prev`) members intact. */ + /* nullptr the entire notifier, only leaving (`next`, `prev`) members intact. */ memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link)); } @@ -435,22 +435,22 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C) wm_event_do_depsgraph(C, false); - CTX_wm_window_set(C, NULL); + CTX_wm_window_set(C, nullptr); } static void wm_event_execute_timers(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); - if (UNLIKELY(wm == NULL)) { + if (UNLIKELY(wm == nullptr)) { return; } /* Set the first window as context, so that there is some minimal context. This avoids crashes * when calling code that assumes that there is always a window in the context (which many * operators do). */ - CTX_wm_window_set(C, wm->windows.first); + CTX_wm_window_set(C, static_cast<wmWindow *>(wm->windows.first)); BLI_timer_execute(); - CTX_wm_window_set(C, NULL); + CTX_wm_window_set(C, nullptr); } void wm_event_do_notifiers(bContext *C) @@ -459,7 +459,7 @@ void wm_event_do_notifiers(bContext *C) wm_event_execute_timers(C); wmWindowManager *wm = CTX_wm_manager(C); - if (wm == NULL) { + if (wm == nullptr) { return; } @@ -489,7 +489,7 @@ void wm_event_do_notifiers(bContext *C) if (note->window == win) { if (note->category == NC_SCREEN) { if (note->data == ND_WORKSPACE_SET) { - WorkSpace *ref_ws = note->reference; + WorkSpace *ref_ws = static_cast<WorkSpace *>(note->reference); UI_popup_handlers_remove_all(C, &win->modalhandlers); @@ -499,7 +499,7 @@ void wm_event_do_notifiers(bContext *C) } } else if (note->data == ND_WORKSPACE_DELETE) { - WorkSpace *workspace = note->reference; + WorkSpace *workspace = static_cast<WorkSpace *>(note->reference); ED_workspace_delete( workspace, CTX_data_main(C), C, wm); /* XXX: hum, think this over! */ @@ -508,7 +508,8 @@ void wm_event_do_notifiers(bContext *C) } } else if (note->data == ND_LAYOUTBROWSE) { - bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference); + bScreen *ref_screen = BKE_workspace_layout_screen_get( + static_cast<WorkSpaceLayout *>(note->reference)); /* Free popup handlers only T35434. */ UI_popup_handlers_remove_all(C, &win->modalhandlers); @@ -520,7 +521,7 @@ void wm_event_do_notifiers(bContext *C) } else if (note->data == ND_LAYOUTDELETE) { WorkSpace *workspace = WM_window_get_active_workspace(win); - WorkSpaceLayout *layout = note->reference; + WorkSpaceLayout *layout = static_cast<WorkSpaceLayout *>(note->reference); ED_workspace_layout_delete(workspace, layout, C); /* XXX: hum, think this over! */ if (G.debug & G_DEBUG_EVENTS) { @@ -530,7 +531,8 @@ void wm_event_do_notifiers(bContext *C) } } - if (note->window == win || (note->window == NULL && (ELEM(note->reference, NULL, scene)))) { + if (note->window == win || + (note->window == nullptr && (ELEM(note->reference, nullptr, scene)))) { if (note->category == NC_SCENE) { if (note->data == ND_FRAME) { do_anim = true; @@ -546,7 +548,7 @@ void wm_event_do_notifiers(bContext *C) /* Only do once since adding notifiers is slow when there are many. */ ViewLayer *view_layer = CTX_data_view_layer(C); ED_info_stats_clear(wm, view_layer); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, nullptr); } if (do_anim) { @@ -564,7 +566,7 @@ void wm_event_do_notifiers(bContext *C) /* The notifiers are sent without context, to keep it clean. */ wmNotifier *note; - while ((note = BLI_pophead(&wm->notifier_queue))) { + while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { Scene *scene = WM_window_get_active_scene(win); bScreen *screen = WM_window_get_active_screen(win); @@ -591,13 +593,13 @@ void wm_event_do_notifiers(bContext *C) ED_screen_do_listen(C, note); LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { - wmRegionListenerParams region_params = { - .window = win, - .area = NULL, - .region = region, - .scene = scene, - .notifier = note, - }; + wmRegionListenerParams region_params{}; + region_params.window = win; + region_params.area = nullptr; + region_params.region = region; + region_params.scene = scene; + region_params.notifier = note; + ED_region_do_listen(®ion_params); } @@ -609,21 +611,19 @@ void wm_event_do_notifiers(bContext *C) continue; } } - wmSpaceTypeListenerParams area_params = { - .window = win, - .area = area, - .notifier = note, - .scene = scene, - }; + wmSpaceTypeListenerParams area_params{}; + area_params.window = win; + area_params.area = area; + area_params.notifier = note; + area_params.scene = scene; ED_area_do_listen(&area_params); LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - wmRegionListenerParams region_params = { - .window = win, - .area = area, - .region = region, - .scene = scene, - .notifier = note, - }; + wmRegionListenerParams region_params{}; + region_params.window = win; + region_params.area = area; + region_params.region = region; + region_params.scene = scene; + region_params.notifier = note; ED_region_do_listen(®ion_params); } } @@ -640,7 +640,7 @@ void wm_event_do_notifiers(bContext *C) CTX_wm_window_set(C, win); WM_msgbus_handle(wm->message_bus, C); } - CTX_wm_window_set(C, NULL); + CTX_wm_window_set(C, nullptr); } wm_event_do_refresh_wm_and_depsgraph(C); @@ -650,7 +650,7 @@ void wm_event_do_notifiers(bContext *C) wmWindow *win = wm->winactive; CTX_wm_window_set(C, win); WM_window_cursor_keymap_status_refresh(C, win); - CTX_wm_window_set(C, NULL); + CTX_wm_window_set(C, nullptr); } /* Auto-run warning. */ @@ -668,7 +668,7 @@ static int wm_event_always_pass(const wmEvent *event) * 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 `NULL`), because the event will have been freed then. + * returning `nullptr`), because the event will have been freed then. */ BLI_INLINE void wm_event_handler_return_value_check(const wmEvent *event, const int action) { @@ -739,9 +739,9 @@ static int wm_handler_ui_call(bContext *C, } else { /* This special cases is for areas and regions that get removed. */ - CTX_wm_area_set(C, NULL); - CTX_wm_region_set(C, NULL); - CTX_wm_menu_set(C, NULL); + CTX_wm_area_set(C, nullptr); + CTX_wm_region_set(C, nullptr); + CTX_wm_menu_set(C, nullptr); } if (retval == WM_UI_HANDLER_BREAK) { @@ -768,12 +768,12 @@ void wm_event_handler_ui_cancel_ex(bContext *C, LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, ®ion->handlers) { if (handler_base->type == WM_HANDLER_TYPE_UI) { wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base; - BLI_assert(handler->handle_fn != NULL); + BLI_assert(handler->handle_fn != nullptr); wmEvent event; wm_event_init_from_window(win, &event); event.type = EVT_BUT_CANCEL; event.val = reactivate_button ? 0 : 1; - event.flag = 0; + event.flag = (eWM_EventFlag)0; handler->handle_fn(C, &event, handler->user_data); } } @@ -796,24 +796,24 @@ static void wm_event_handler_ui_cancel(bContext *C) void WM_report_banner_show(void) { - wmWindowManager *wm = G_MAIN->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first); ReportList *wm_reports = &wm->reports; /* After adding reports to the global list, reset the report timer. */ - WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); + WM_event_remove_timer(wm, nullptr, wm_reports->reporttimer); /* Records time since last report was added. */ wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05); - ReportTimerInfo *rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); + ReportTimerInfo *rti = MEM_cnew<ReportTimerInfo>(__func__); wm_reports->reporttimer->customdata = rti; } void WM_report_banners_cancel(Main *bmain) { - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); BKE_reports_clear(&wm->reports); - WM_event_remove_timer(wm, NULL, wm->reports.reporttimer); + WM_event_remove_timer(wm, nullptr, wm->reports.reporttimer); } #ifdef WITH_INPUT_NDOF @@ -827,7 +827,7 @@ static void wm_add_reports(ReportList *reports) { /* If the caller owns them, handle this. */ if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) { - wmWindowManager *wm = G_MAIN->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first); /* Add reports to the global list, otherwise they are not seen. */ BLI_movelisttolist(&wm->reports.list, &reports->list); @@ -873,7 +873,7 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot) { LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) { - wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, 0); + wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, false); if (!WM_operator_poll(C, ot_macro)) { return false; @@ -894,15 +894,16 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot) bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context) { /* Sets up the new context and calls #wm_operator_invoke() with poll_only. */ - return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL); + return wm_operator_call_internal( + C, ot, nullptr, nullptr, static_cast<wmOperatorCallContext>(context), true, nullptr); } bool WM_operator_check_ui_empty(wmOperatorType *ot) { - if (ot->macro.first != NULL) { + if (ot->macro.first != nullptr) { /* For macros, check all have exec() we can call. */ LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) { - wmOperatorType *otm = WM_operatortype_find(macro->idname, 0); + wmOperatorType *otm = WM_operatortype_find(macro->idname, false); if (otm && !WM_operator_check_ui_empty(otm)) { return false; } @@ -951,8 +952,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (win_prev == NULL) { - CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); + if (win_prev == nullptr) { + CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first)); } UI_popup_menu_reports(C, op->reports); @@ -982,7 +983,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca /* Refresh Info Editor with reports immediately, even if op returned #OPERATOR_CANCELLED. */ if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, nullptr); } /* If the caller owns them, handle this. */ wm_add_reports(op->reports); @@ -1008,7 +1009,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, CLEAR, } hud_status = NOP; - op->customdata = NULL; + op->customdata = nullptr; if (store) { WM_operator_last_properties_store(op); @@ -1064,7 +1065,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, } } else if (hud_status == CLEAR) { - ED_area_type_hud_clear(wm, NULL); + ED_area_type_hud_clear(wm, nullptr); } else { BLI_assert_unreachable(); @@ -1082,7 +1083,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons CTX_wm_operator_poll_msg_clear(C); - if (op == NULL || op->type == NULL) { + if (op == nullptr || op->type == nullptr) { return retval; } @@ -1130,7 +1131,7 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op) { int retval = OPERATOR_CANCELLED; - if (op == NULL || op->type == NULL || op->type->exec == NULL) { + if (op == nullptr || op->type == nullptr || op->type->exec == nullptr) { return retval; } @@ -1173,14 +1174,14 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op) } bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op) { - if (op->type->exec != NULL) { + if (op->type->exec != nullptr) { return true; } if (op->opm) { /* For macros, check all have exec() we can call. */ LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) { - wmOperatorType *otm = WM_operatortype_find(macro->idname, 0); - if (otm && otm->exec == NULL) { + wmOperatorType *otm = WM_operatortype_find(macro->idname, false); + if (otm && otm->exec == nullptr) { return false; } } @@ -1194,9 +1195,9 @@ bool WM_operator_is_repeat(const bContext *C, const wmOperator *op) { /* May be in the operators list or not. */ wmOperator *op_prev; - if (op->prev == NULL && op->next == NULL) { + if (op->prev == nullptr && op->next == nullptr) { wmWindowManager *wm = CTX_wm_manager(C); - op_prev = wm->operators.last; + op_prev = static_cast<wmOperator *>(wm->operators.last); } else { op_prev = op->prev; @@ -1210,16 +1211,16 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, ReportList *reports) { /* Operator-type names are static still. pass to allocation name for debugging. */ - wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname); + wmOperator *op = MEM_cnew<wmOperator>(ot->idname); /* Adding new operator could be function, only happens here now. */ op->type = ot; BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME); /* Initialize properties, either copy or create. */ - op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA"); + op->ptr = MEM_cnew<PointerRNA>("wmOperatorPtrRNA"); if (properties && properties->data) { - op->properties = IDP_CopyProperty(properties->data); + op->properties = IDP_CopyProperty(static_cast<const IDProperty *>(properties->data)); } else { IDPropertyTemplate val = {0}; @@ -1232,36 +1233,36 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, op->reports = reports; /* Must be initialized already. */ } else { - op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); + op->reports = MEM_cnew<ReportList>("wmOperatorReportList"); BKE_reports_init(op->reports, RPT_STORE | RPT_FREE); } /* Recursive filling of operator macro list. */ if (ot->macro.first) { - static wmOperator *motherop = NULL; + static wmOperator *motherop = nullptr; int root = 0; /* Ensure all ops are in execution order in 1 list. */ - if (motherop == NULL) { + if (motherop == nullptr) { motherop = op; root = 1; } /* If properties exist, it will contain everything needed. */ if (properties) { - wmOperatorTypeMacro *otmacro = ot->macro.first; + wmOperatorTypeMacro *otmacro = static_cast<wmOperatorTypeMacro *>(ot->macro.first); RNA_STRUCT_BEGIN (properties, prop) { - if (otmacro == NULL) { + if (otmacro == nullptr) { break; } /* Skip invalid properties. */ if (STREQ(RNA_property_identifier(prop), otmacro->idname)) { - wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0); + wmOperatorType *otm = WM_operatortype_find(otmacro->idname, false); PointerRNA someptr = RNA_property_pointer_get(properties, prop); - wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL); + wmOperator *opm = wm_operator_create(wm, otm, &someptr, nullptr); IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties); @@ -1275,8 +1276,8 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, } else { LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) { - wmOperatorType *otm = WM_operatortype_find(macro->idname, 0); - wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL); + wmOperatorType *otm = WM_operatortype_find(macro->idname, false); + wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, nullptr); BLI_addtail(&motherop->macro, opm); opm->opm = motherop; /* Pointer to mom, for modal(). */ @@ -1284,11 +1285,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, } if (root) { - motherop = NULL; + motherop = nullptr; } } - WM_operator_properties_sanitize(op->ptr, 0); + WM_operator_properties_sanitize(op->ptr, false); return op; } @@ -1302,12 +1303,12 @@ static void wm_region_tag_draw_on_gizmo_delay_refresh_for_tweak(wmWindow *win) bScreen *screen = WM_window_get_active_screen(win); /* Unlikely but not impossible as this runs after events have been handled. */ - if (UNLIKELY(screen == NULL)) { + if (UNLIKELY(screen == nullptr)) { return; } ED_screen_areas_iter (win, screen, area) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->gizmo_map != NULL) { + if (region->gizmo_map != nullptr) { if (WM_gizmomap_tag_delay_refresh_for_tweak_check(region->gizmo_map)) { ED_region_tag_redraw(region); } @@ -1332,7 +1333,7 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event) } /** - * Also used for exec when 'event' is NULL. + * Also used for exec when 'event' is nullptr. */ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, @@ -1353,12 +1354,12 @@ static int wm_operator_invoke(bContext *C, if (WM_operator_poll(C, ot)) { wmWindowManager *wm = CTX_wm_manager(C); - /* If `reports == NULL`, they'll be initialized. */ + /* If `reports == nullptr`, they'll be initialized. */ wmOperator *op = wm_operator_create(wm, ot, properties, reports); const bool is_nested_call = (wm->op_undo_depth != 0); - if (event != NULL) { + if (event != nullptr) { op->flag |= OP_IS_INVOKE; } @@ -1367,7 +1368,7 @@ static int wm_operator_invoke(bContext *C, WM_operator_last_properties_init(op); } - if ((event == NULL) || (event->type != MOUSEMOVE)) { + if ((event == nullptr) || (event->type != MOUSEMOVE)) { CLOG_INFO(WM_LOG_HANDLERS, 2, "handle evt %d win %p op %s", @@ -1378,7 +1379,7 @@ static int wm_operator_invoke(bContext *C, if (op->type->invoke && event) { /* Temporarily write into `mval` (not technically `const` correct) but this is restored. */ - int mval_prev[2] = {UNPACK2(event->mval)}; + const int mval_prev[2] = {UNPACK2(event->mval)}; wm_region_mouse_co(C, (wmEvent *)event); if (op->type->flag & OPTYPE_UNDO) { @@ -1415,7 +1416,7 @@ static int wm_operator_invoke(bContext *C, * them currently Python only uses this. */ if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) { /* Only show the report if the report list was not given in the function. */ - wm_operator_reports(C, op, retval, (reports != NULL)); + wm_operator_reports(C, op, retval, (reports != nullptr)); } if (retval & OPERATOR_HANDLED) { @@ -1451,7 +1452,7 @@ static int wm_operator_invoke(bContext *C, } if (wrap) { - const rcti *winrect = NULL; + const rcti *winrect = nullptr; ARegion *region = CTX_wm_region(C); ScrArea *area = CTX_wm_area(C); @@ -1514,7 +1515,7 @@ static int wm_operator_call_internal(bContext *C, if (ot) { wmWindow *window = CTX_wm_window(C); - if (event == NULL) { + if (event == nullptr) { switch (context) { case WM_OP_INVOKE_DEFAULT: case WM_OP_INVOKE_REGION_WIN: @@ -1523,7 +1524,7 @@ static int wm_operator_call_internal(bContext *C, case WM_OP_INVOKE_AREA: case WM_OP_INVOKE_SCREEN: /* Window is needed for invoke and cancel operators. */ - if (window == NULL) { + if (window == nullptr) { if (poll_only) { CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context"); } @@ -1534,7 +1535,7 @@ static int wm_operator_call_internal(bContext *C, } break; default: - event = NULL; + event = nullptr; break; } } @@ -1546,7 +1547,7 @@ static int wm_operator_call_internal(bContext *C, case WM_OP_EXEC_REGION_CHANNELS: case WM_OP_EXEC_AREA: case WM_OP_EXEC_SCREEN: - event = NULL; + event = nullptr; default: break; } @@ -1604,7 +1605,7 @@ static int wm_operator_call_internal(bContext *C, /* Remove region from context. */ ARegion *region = CTX_wm_region(C); - CTX_wm_region_set(C, NULL); + CTX_wm_region_set(C, nullptr); retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true); CTX_wm_region_set(C, region); @@ -1616,8 +1617,8 @@ static int wm_operator_call_internal(bContext *C, ARegion *region = CTX_wm_region(C); ScrArea *area = CTX_wm_area(C); - CTX_wm_region_set(C, NULL); - CTX_wm_area_set(C, NULL); + CTX_wm_region_set(C, nullptr); + CTX_wm_area_set(C, nullptr); retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true); CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); @@ -1640,7 +1641,7 @@ int WM_operator_name_call_ptr(bContext *C, const wmEvent *event) { BLI_assert(ot == WM_operatortype_find(ot->idname, true)); - return wm_operator_call_internal(C, ot, properties, NULL, context, false, event); + return wm_operator_call_internal(C, ot, properties, nullptr, context, false, event); } int WM_operator_name_call(bContext *C, const char *opstring, @@ -1648,7 +1649,7 @@ int WM_operator_name_call(bContext *C, PointerRNA *properties, const wmEvent *event) { - wmOperatorType *ot = WM_operatortype_find(opstring, 0); + wmOperatorType *ot = WM_operatortype_find(opstring, false); if (ot) { return WM_operator_name_call_ptr(C, ot, context, properties, event); } @@ -1658,7 +1659,7 @@ int WM_operator_name_call(bContext *C, bool WM_operator_name_poll(bContext *C, const char *opstring) { - wmOperatorType *ot = WM_operatortype_find(opstring, 0); + wmOperatorType *ot = WM_operatortype_find(opstring, false); if (!ot) { return false; } @@ -1666,15 +1667,16 @@ bool WM_operator_name_poll(bContext *C, const char *opstring) return WM_operator_poll(C, ot); } -int WM_operator_name_call_with_properties(struct bContext *C, +int WM_operator_name_call_with_properties(bContext *C, const char *opstring, wmOperatorCallContext context, - struct IDProperty *properties, + IDProperty *properties, const wmEvent *event) { PointerRNA props_ptr; wmOperatorType *ot = WM_operatortype_find(opstring, false); - RNA_pointer_create(G_MAIN->wm.first, ot->srna, properties, &props_ptr); + RNA_pointer_create( + &static_cast<wmWindowManager *>(G_MAIN->wm.first)->id, ot->srna, properties, &props_ptr); return WM_operator_name_call_ptr(C, ot, context, &props_ptr, event); } @@ -1684,7 +1686,7 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context) PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, "name", menu_name); - WM_operator_name_call_ptr(C, ot, context, &ptr, NULL); + WM_operator_name_call_ptr(C, ot, static_cast<wmOperatorCallContext>(context), &ptr, nullptr); WM_operator_properties_free(&ptr); } @@ -1703,7 +1705,7 @@ int WM_operator_call_py(bContext *C, wm->op_undo_depth++; } - retval = wm_operator_call_internal(C, ot, properties, reports, context, false, NULL); + retval = wm_operator_call_internal(C, ot, properties, reports, context, false, nullptr); if (!is_undo && wm && (wm == CTX_wm_manager(C))) { wm->op_undo_depth--; @@ -1722,18 +1724,18 @@ int WM_operator_call_py(bContext *C, * See: #OPTYPE_DEPENDS_ON_CURSOR doc-string for more information. * \{ */ -typedef struct uiOperatorWaitForInput { +struct uiOperatorWaitForInput { ScrArea *area; wmOperatorCallParams optype_params; bContextStore *context; -} uiOperatorWaitForInput; +}; static void ui_handler_wait_for_input_remove(bContext *C, void *userdata) { - uiOperatorWaitForInput *opwait = userdata; + uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata); if (opwait->optype_params.opptr) { if (opwait->optype_params.opptr->data) { - IDP_FreeProperty(opwait->optype_params.opptr->data); + IDP_FreeProperty(static_cast<IDProperty *>(opwait->optype_params.opptr->data)); } MEM_freeN(opwait->optype_params.opptr); } @@ -1741,11 +1743,11 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata) CTX_store_free(opwait->context); } - if (opwait->area != NULL) { - ED_area_status_text(opwait->area, NULL); + if (opwait->area != nullptr) { + ED_area_status_text(opwait->area, nullptr); } else { - ED_workspace_status_text(C, NULL); + ED_workspace_status_text(C, nullptr); } MEM_freeN(opwait); @@ -1753,7 +1755,7 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata) static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *userdata) { - uiOperatorWaitForInput *opwait = userdata; + uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata); enum { CONTINUE = 0, EXECUTE, CANCEL } state = CONTINUE; state = CONTINUE; @@ -1798,7 +1800,7 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us opwait->optype_params.opcontext, opwait->optype_params.opptr, event); - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); } WM_event_remove_ui_handler(&win->modalhandlers, @@ -1825,8 +1827,8 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, int flag = ot->flag; LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) { - wmOperatorType *otm = WM_operatortype_find(macro->idname, 0); - if (otm != NULL) { + wmOperatorType *otm = WM_operatortype_find(macro->idname, false); + if (otm != nullptr) { flag |= otm->flag; } } @@ -1840,7 +1842,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, /* The operator context is applied when the operator is called, * the check for the area needs to be explicitly limited here. * Useful so it's possible to screen-shot an area without drawing into it's header. */ - ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : NULL; + ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : nullptr; { char header_text[UI_MAX_DRAW_STR]; @@ -1848,7 +1850,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, "%s %s", IFACE_("Input pending "), (drawstr && drawstr[0]) ? drawstr : CTX_IFACE_(ot->translation_context, ot->name)); - if (area != NULL) { + if (area != nullptr) { ED_area_status_text(area, header_text); } else { @@ -1858,7 +1860,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, WM_cursor_modal_set(win, ot->cursor_pending); - uiOperatorWaitForInput *opwait = MEM_callocN(sizeof(*opwait), __func__); + uiOperatorWaitForInput *opwait = MEM_cnew<uiOperatorWaitForInput>(__func__); opwait->optype_params.optype = ot; opwait->optype_params.opcontext = opcontext; opwait->optype_params.opptr = properties; @@ -1866,10 +1868,11 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, opwait->area = area; if (properties) { - opwait->optype_params.opptr = MEM_mallocN(sizeof(*opwait->optype_params.opptr), __func__); + opwait->optype_params.opptr = MEM_cnew<PointerRNA>(__func__); *opwait->optype_params.opptr = *properties; - if (properties->data != NULL) { - opwait->optype_params.opptr->data = IDP_CopyProperty(properties->data); + if (properties->data != nullptr) { + opwait->optype_params.opptr->data = IDP_CopyProperty( + static_cast<IDProperty *>(properties->data)); } } @@ -1916,18 +1919,18 @@ static void wm_handler_op_context_get_if_valid(bContext *C, * possible. */ bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C); - *r_area = NULL; - *r_region = NULL; + *r_area = nullptr; + *r_region = nullptr; - if (screen == NULL || handler->op == NULL) { + if (screen == nullptr || handler->op == nullptr) { return; } - if (handler->context.area == NULL) { + if (handler->context.area == nullptr) { /* Pass */ } else { - ScrArea *area = NULL; + ScrArea *area = nullptr; ED_screen_areas_iter (win, screen, area_iter) { if (area_iter == handler->context.area) { @@ -1936,10 +1939,10 @@ static void wm_handler_op_context_get_if_valid(bContext *C, } } - if (area == NULL) { + if (area == nullptr) { /* When changing screen layouts with running modal handlers (like render display), this * is not an error to print. */ - if (handler->op == NULL) { + if (handler->op == nullptr) { CLOG_ERROR(WM_LOG_HANDLERS, "internal error: handler (%s) has invalid area", handler->op->type->idname); @@ -1947,7 +1950,7 @@ static void wm_handler_op_context_get_if_valid(bContext *C, } else { ARegion *region; - wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL; + wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : nullptr; *r_area = area; if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) { @@ -1957,10 +1960,10 @@ static void wm_handler_op_context_get_if_valid(bContext *C, } } else { - region = NULL; + region = nullptr; } - if ((region == NULL) && handler->context.region) { + if ((region == nullptr) && handler->context.region) { if (BLI_findindex(&area->regionbase, handler->context.region) != -1) { region = handler->context.region; } @@ -1976,8 +1979,8 @@ static void wm_handler_op_context_get_if_valid(bContext *C, static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event) { - ScrArea *area = NULL; - ARegion *region = NULL; + ScrArea *area = nullptr; + ARegion *region = nullptr; wm_handler_op_context_get_if_valid(C, handler, event, &area, ®ion); CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); @@ -1989,7 +1992,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) /* C is zero on freeing database, modal handlers then already were freed. */ wmEventHandler *handler_base; - while ((handler_base = BLI_pophead(handlers))) { + while ((handler_base = static_cast<wmEventHandler *>(BLI_pophead(handlers)))) { BLI_assert(handler_base->type != 0); if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; @@ -2028,7 +2031,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) CTX_wm_region_set(C, region); } - WM_cursor_grab_disable(win, NULL); + WM_cursor_grab_disable(win, nullptr); if (handler->is_fileselect) { wm_operator_free_for_fileselect(handler->op); @@ -2132,25 +2135,26 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi) /* Account for rare case of when these keys are used as the 'type' not as modifiers. */ if (kmi->shift != KM_ANY) { const bool shift = (winevent->modifier & KM_SHIFT) != 0; - if ((shift != kmi->shift) && !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) { + if ((shift != (bool)kmi->shift) && + !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) { return false; } } if (kmi->ctrl != KM_ANY) { const bool ctrl = (winevent->modifier & KM_CTRL) != 0; - if (ctrl != kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) { + if (ctrl != (bool)kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) { return false; } } if (kmi->alt != KM_ANY) { const bool alt = (winevent->modifier & KM_ALT) != 0; - if (alt != kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) { + if (alt != (bool)kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) { return false; } } if (kmi->oskey != KM_ANY) { const bool oskey = (winevent->modifier & KM_OSKEY) != 0; - if ((oskey != kmi->oskey) && (winevent->type != EVT_OSKEY)) { + if ((oskey != (bool)kmi->oskey) && (winevent->type != EVT_OSKEY)) { return false; } } @@ -2175,12 +2179,12 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, /* Should already be handled by #wm_user_modal_keymap_set_items. */ BLI_assert(kmi->propvalue_str[0] == '\0'); if (wm_eventmatch(event, kmi)) { - if ((keymap->poll_modal_item == NULL) || (keymap->poll_modal_item(op, kmi->propvalue))) { + if ((keymap->poll_modal_item == nullptr) || (keymap->poll_modal_item(op, kmi->propvalue))) { return kmi; } } } - return NULL; + return nullptr; } struct wmEvent_ModalMapStore { @@ -2203,7 +2207,7 @@ struct wmEvent_ModalMapStore { static void wm_event_modalkeymap_begin(const bContext *C, wmOperator *op, wmEvent *event, - struct wmEvent_ModalMapStore *event_backup) + wmEvent_ModalMapStore *event_backup) { BLI_assert(event->type != EVT_MODAL_MAP); @@ -2216,9 +2220,9 @@ static void wm_event_modalkeymap_begin(const bContext *C, if (op->type->modalkeymap) { wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap); - wmKeyMapItem *kmi = NULL; + wmKeyMapItem *kmi = nullptr; - const wmEvent *event_match = NULL; + const wmEvent *event_match = nullptr; wmEvent event_no_dbl_click; if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, event))) { @@ -2232,7 +2236,7 @@ static void wm_event_modalkeymap_begin(const bContext *C, } } - if (event_match != NULL) { + if (event_match != nullptr) { event_backup->prev_type = event->prev_type; event_backup->prev_val = event->prev_val; @@ -2267,8 +2271,7 @@ static void wm_event_modalkeymap_begin(const bContext *C, * better restore event type for checking of #KM_CLICK for example. * Modal maps could use different method (ton). */ -static void wm_event_modalkeymap_end(wmEvent *event, - const struct wmEvent_ModalMapStore *event_backup) +static void wm_event_modalkeymap_end(wmEvent *event, const wmEvent_ModalMapStore *event_backup) { if (event->type == EVT_MODAL_MAP) { event->type = event->prev_type; @@ -2297,7 +2300,7 @@ static int wm_handler_operator_call(bContext *C, /* Derived, modal or blocking operator. */ if ((handler_base->type == WM_HANDLER_TYPE_OP) && - (((wmEventHandler_Op *)handler_base)->op != NULL)) { + (((wmEventHandler_Op *)handler_base)->op != nullptr)) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; wmOperator *op = handler->op; wmOperatorType *ot = op->type; @@ -2316,7 +2319,7 @@ static int wm_handler_operator_call(bContext *C, wm_handler_op_context(C, handler, event); wm_region_mouse_co(C, event); - struct wmEvent_ModalMapStore event_backup; + wmEvent_ModalMapStore event_backup; wm_event_modalkeymap_begin(C, op, event, &event_backup); if (ot->flag & OPTYPE_UNDO) { @@ -2352,14 +2355,14 @@ static int wm_handler_operator_call(bContext *C, } } - /* Important to run 'wm_operator_finished' before NULL-ing the context members. */ + /* Important to run 'wm_operator_finished' before nullptr-ing the context members. */ if (retval & OPERATOR_FINISHED) { wm_operator_finished(C, op, false, true); - handler->op = NULL; + handler->op = nullptr; } else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) { WM_operator_free(op); - handler->op = NULL; + handler->op = nullptr; } /* Putting back screen context, `reval` can pass through after modal failures! */ @@ -2369,8 +2372,8 @@ static int wm_handler_operator_call(bContext *C, } else { /* This special cases is for areas and regions that get removed. */ - CTX_wm_area_set(C, NULL); - CTX_wm_region_set(C, NULL); + CTX_wm_area_set(C, nullptr); + CTX_wm_region_set(C, nullptr); } /* Update gizmos during modal handlers. */ @@ -2378,7 +2381,7 @@ static int wm_handler_operator_call(bContext *C, /* Remove modal handler, operator itself should have been canceled and freed. */ if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) { - WM_cursor_grab_disable(CTX_wm_window(C), NULL); + WM_cursor_grab_disable(CTX_wm_window(C), nullptr); BLI_remlink(handlers, handler); wm_event_free_handler(&handler->head); @@ -2393,13 +2396,13 @@ static int wm_handler_operator_call(bContext *C, } } else { - wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0); + wmOperatorType *ot = WM_operatortype_find(kmi_idname, false); if (ot && wm_operator_check_locked_interface(C, ot)) { bool use_last_properties = true; - PointerRNA tool_properties = {0}; + PointerRNA tool_properties = {nullptr}; - bToolRef *keymap_tool = NULL; + bToolRef *keymap_tool = nullptr; if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) { keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool; } @@ -2411,7 +2414,7 @@ static int wm_handler_operator_call(bContext *C, } } - const bool is_tool = (keymap_tool != NULL); + const bool is_tool = (keymap_tool != nullptr); const bool use_tool_properties = is_tool; if (use_tool_properties) { @@ -2421,7 +2424,7 @@ static int wm_handler_operator_call(bContext *C, use_last_properties = false; } - retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties); + retval = wm_operator_invoke(C, ot, event, properties, nullptr, false, use_last_properties); if (use_tool_properties) { WM_operator_properties_free(&tool_properties); @@ -2434,10 +2437,10 @@ static int wm_handler_operator_call(bContext *C, if (tref_rt->gizmo_group[0]) { const char *idname = tref_rt->gizmo_group; wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false); - if (gzgt != NULL) { + if (gzgt != nullptr) { if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) { ARegion *region = CTX_wm_region(C); - if (region != NULL) { + if (region != nullptr) { wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params); WM_gizmo_group_type_ensure_ptr_ex(gzgt, gzmap_type); wmGizmoGroup *gzgroup = WM_gizmomaptype_group_init_runtime_with_region( @@ -2477,9 +2480,9 @@ static void wm_operator_free_for_fileselect(wmOperator *file_operator) LISTBASE_FOREACH (bScreen *, screen, &G_MAIN->screens) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_FILE) { - SpaceFile *sfile = area->spacedata.first; + SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first); if (sfile->op == file_operator) { - sfile->op = NULL; + sfile->op = nullptr; } } } @@ -2551,16 +2554,16 @@ static int wm_handler_fileselect_do(bContext *C, if (val == EVT_FILESELECT_EXTERNAL_CANCEL) { /* The window might have been freed already. */ if (BLI_findindex(&wm->windows, handler->context.win) == -1) { - handler->context.win = NULL; + handler->context.win = nullptr; } } else { ScrArea *ctx_area = CTX_wm_area(C); - wmWindow *temp_win = NULL; + wmWindow *temp_win = nullptr; LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { bScreen *screen = WM_window_get_active_screen(win); - ScrArea *file_area = screen->areabase.first; + ScrArea *file_area = static_cast<ScrArea *>(screen->areabase.first); if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) { continue; @@ -2576,14 +2579,15 @@ static int wm_handler_fileselect_do(bContext *C, int win_size[2]; bool is_maximized; ED_fileselect_window_params_get(win, win_size, &is_maximized); - ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized); + ED_fileselect_params_to_userdef( + static_cast<SpaceFile *>(file_area->spacedata.first), win_size, is_maximized); if (BLI_listbase_is_single(&file_area->spacedata)) { BLI_assert(root_win != win); wm_window_close(C, wm, win); - CTX_wm_window_set(C, root_win); /* #wm_window_close() NULLs. */ + CTX_wm_window_set(C, root_win); /* #wm_window_close() nullptrs. */ /* Some operators expect a drawable context (for #EVT_FILESELECT_EXEC). */ wm_window_make_drawable(wm, root_win); /* Ensure correct cursor position, otherwise, popups may close immediately after @@ -2603,7 +2607,8 @@ static int wm_handler_fileselect_do(bContext *C, } if (!temp_win && ctx_area->full) { - ED_fileselect_params_to_userdef(ctx_area->spacedata.first, NULL, false); + ED_fileselect_params_to_userdef( + static_cast<SpaceFile *>(ctx_area->spacedata.first), nullptr, false); ED_screen_full_prevspace(C, ctx_area); } } @@ -2656,8 +2661,8 @@ static int wm_handler_fileselect_do(bContext *C, ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (win_prev == NULL) { - CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); + if (win_prev == nullptr) { + CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first)); } BKE_report_print_level_set(handler->op->reports, RPT_WARNING); @@ -2701,7 +2706,7 @@ static int wm_handler_fileselect_do(bContext *C, wm_operator_free_for_fileselect(handler->op); } - CTX_wm_area_set(C, NULL); + CTX_wm_area_set(C, nullptr); wm_event_free_handler(&handler->head); @@ -2763,18 +2768,18 @@ static const char *keymap_handler_log_kmi_op_str(bContext *C, size_t buf_maxlen) { /* The key-map item properties can further help distinguish this item from others. */ - char *kmi_props = NULL; - if (kmi->properties != NULL) { - wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); + char *kmi_props = nullptr; + if (kmi->properties != nullptr) { + wmOperatorType *ot = WM_operatortype_find(kmi->idname, false); if (ot) { kmi_props = RNA_pointer_as_string_keywords(C, kmi->ptr, false, false, true, 512); } else { /* Fallback. */ - kmi_props = IDP_reprN(kmi->properties, NULL); + kmi_props = IDP_reprN(kmi->properties, nullptr); } } BLI_snprintf(buf, buf_maxlen, "%s(%s)", kmi->idname, kmi_props ? kmi_props : ""); - if (kmi_props != NULL) { + if (kmi_props != nullptr) { MEM_freeN(kmi_props); } return buf; @@ -2796,8 +2801,8 @@ static int wm_handlers_do_keymap_with_keymap_handler( { int action = WM_HANDLER_CONTINUE; - if (keymap == NULL) { - /* Only callback is allowed to have NULL key-maps. */ + if (keymap == nullptr) { + /* Only callback is allowed to have nullptr key-maps. */ BLI_assert(handler->dynamic.keymap_fn); } else { @@ -2809,7 +2814,7 @@ static int wm_handlers_do_keymap_with_keymap_handler( LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if (wm_eventmatch(event, kmi)) { - struct wmEventHandler_KeymapPost keymap_post = handler->post; + wmEventHandler_KeymapPost keymap_post = handler->post; action |= wm_handler_operator_call( C, handlers, &handler->head, event, kmi->ptr, kmi->idname); @@ -2826,7 +2831,7 @@ static int wm_handlers_do_keymap_with_keymap_handler( if (action & WM_HANDLER_BREAK) { /* Not always_pass here, it denotes removed handler_base. */ - if (keymap_post.post_fn != NULL) { + if (keymap_post.post_fn != nullptr) { keymap_post.post_fn(keymap, kmi, keymap_post.user_data); } break; @@ -2872,7 +2877,7 @@ static int wm_handlers_do_keymap_with_gizmo_handler( action |= wm_handler_operator_call( C, handlers, &handler->head, event, kmi->ptr, kmi->idname); - CTX_wm_gizmo_group_set(C, NULL); + CTX_wm_gizmo_group_set(C, nullptr); if (action & WM_HANDLER_BREAK) { if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) { @@ -2922,7 +2927,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); wmGizmoMap *gzmap = handler->gizmo_map; - BLI_assert(gzmap != NULL); + BLI_assert(gzmap != nullptr); wmGizmo *gz = wm_gizmomap_highlight_get(gzmap); /* Needed so UI blocks over gizmos don't let events fall through to the gizmos, @@ -2930,25 +2935,25 @@ static int wm_handlers_do_gizmo_handler(bContext *C, * note we still allow for starting the gizmo drag outside, then travel 'inside' the node. */ if (region->type->clip_gizmo_events_by_ui) { if (UI_region_block_find_mouse_over(region, event->xy, true)) { - if (gz != NULL && event->type != EVT_GIZMO_UPDATE) { + if (gz != nullptr && event->type != EVT_GIZMO_UPDATE) { if (restore_highlight_unless_activated == false) { WM_tooltip_clear(C, CTX_wm_window(C)); - wm_gizmomap_highlight_set(gzmap, C, NULL, 0); + wm_gizmomap_highlight_set(gzmap, C, nullptr, 0); } } return action; } } - struct { + struct PrevGizmoData { wmGizmo *gz_modal; wmGizmo *gz; int part; - } prev = { - .gz_modal = wm_gizmomap_modal_get(gzmap), - .gz = gz, - .part = gz ? gz->highlight_part : 0, }; + PrevGizmoData prev{}; + prev.gz_modal = wm_gizmomap_modal_get(gzmap); + prev.gz = gz; + prev.part = gz ? gz->highlight_part : 0; if (region->gizmo_map != handler->gizmo_map) { WM_gizmomap_tag_refresh(handler->gizmo_map); @@ -2961,7 +2966,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, bool handle_keymap = false; /* Handle gizmo highlighting. */ - if ((prev.gz_modal == NULL) && + if ((prev.gz_modal == nullptr) && ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) { handle_highlight = true; if (is_event_modifier || is_event_drag) { @@ -2992,7 +2997,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, } if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { - if (gz != NULL) { + if (gz != nullptr) { if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) { WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); } @@ -3005,7 +3010,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (handle_keymap) { /* Handle highlight gizmo. */ - if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) { + if ((gz != nullptr) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) { bool keymap_poll = false; wmGizmoGroup *gzgroup = gz->parent_gzgroup; wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap); @@ -3026,7 +3031,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if ((kmi->flag & KMI_INACTIVE) == 0) { if (wm_eventmatch(&event_test_click, kmi) || wm_eventmatch(&event_test_click_drag, kmi)) { - wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); + wmOperatorType *ot = WM_operatortype_find(kmi->idname, false); if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) { is_event_handle_all = true; break; @@ -3040,7 +3045,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, } /* Don't use from now on. */ - gz = NULL; + gz = nullptr; /* Fallback to selected gizmo (when un-handled). */ if ((action & WM_HANDLER_BREAK) == 0) { @@ -3050,7 +3055,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (wm_gizmogroup_is_any_selected(gzgroup)) { wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap); action |= wm_handlers_do_keymap_with_gizmo_handler( - C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL); + C, event, handlers, handler, gzgroup, keymap, do_debug_handler, nullptr); if (action & WM_HANDLER_BREAK) { break; } @@ -3099,7 +3104,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis wmWindowManager *wm = CTX_wm_manager(C); int action = WM_HANDLER_CONTINUE; - if (handlers == NULL) { + if (handlers == nullptr) { wm_event_handler_return_value_check(event, action); return action; } @@ -3110,7 +3115,8 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis * by the event that's called, for eg: * * Calling a python script which changes the area.type, see T32232. */ - for (wmEventHandler *handler_base = handlers->first, *handler_base_next; + for (wmEventHandler *handler_base = static_cast<wmEventHandler *>(handlers->first), + *handler_base_next; handler_base && handlers->first; handler_base = handler_base_next) { handler_base_next = handler_base->next; @@ -3119,7 +3125,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis if (handler_base->flag & WM_HANDLER_DO_FREE) { /* Pass. */ } - else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) { + else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) { /* In advance to avoid access to freed event on window close. */ const int always_pass = wm_event_always_pass(event); @@ -3148,14 +3154,14 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis * are kept when a modal operators starts (annoying but otherwise harmless). */ if (action & WM_HANDLER_BREAK) { /* Window may be gone after file read. */ - if (CTX_wm_window(C) != NULL) { + if (CTX_wm_window(C) != nullptr) { WM_tooltip_clear(C, CTX_wm_window(C)); } } } else if (handler_base->type == WM_HANDLER_TYPE_UI) { wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base; - BLI_assert(handler->handle_fn != NULL); + BLI_assert(handler->handle_fn != nullptr); if (!wm->is_interface_locked) { action |= wm_handler_ui_call(C, handler, event, always_pass); } @@ -3173,13 +3179,13 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis /* Pass single matched #wmDrag onto the operator. */ BLI_remlink(lb, drag); - ListBase single_lb = {0}; + ListBase single_lb = {nullptr}; BLI_addtail(&single_lb, drag); event->customdata = &single_lb; const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); int op_retval = wm_operator_call_internal( - C, drop->ot, drop->ptr, NULL, opcontext, false, event); + C, drop->ot, drop->ptr, nullptr, opcontext, false, event); OPERATOR_RETVAL_CHECK(op_retval); if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) { @@ -3197,7 +3203,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis wm_drop_end(C, drag, drop); /* XXX file-read case. */ - if (CTX_wm_window(C) == NULL) { + if (CTX_wm_window(C) == nullptr) { return action; } @@ -3224,7 +3230,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis } } else { - action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL); + action |= wm_handler_operator_call(C, handlers, handler_base, event, nullptr, nullptr); } } else { @@ -3244,7 +3250,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis /* File-read case, if the wm is freed then the handler's * will have been too so the code below need not run. */ - if (CTX_wm_window(C) == NULL) { + if (CTX_wm_window(C) == nullptr) { return action; } @@ -3265,7 +3271,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) != NULL) { + if (CTX_wm_window(C) != nullptr) { wm_event_handler_return_value_check(event, action); } return action; @@ -3278,9 +3284,9 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) { int action = wm_handlers_do_intern(C, CTX_wm_window(C), event, handlers); - /* Will be NULL in the file read case. */ + /* Will be nullptr in the file read case. */ wmWindow *win = CTX_wm_window(C); - if (win == NULL) { + if (win == nullptr) { return action; } @@ -3370,11 +3376,10 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } - if (event->prev_press_type == event->type) { - - if (event->val == KM_RELEASE) { + if (event->val == KM_RELEASE) { + if (event->prev_press_type == event->type) { if (event->prev_val == KM_PRESS) { - if (win->event_queue_check_click == true) { + if (win->event_queue_check_click) { if (WM_event_drag_test(event, event->prev_press_xy)) { win->event_queue_check_click = false; if (win->event_queue_check_drag) { @@ -3387,7 +3392,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) else { /* Position is where the actual click happens, for more * accurate selecting in case the mouse drifts a little. */ - int xy[2] = {UNPACK2(event->xy)}; + const int xy[2] = {UNPACK2(event->xy)}; copy_v2_v2_int(event->xy, event->prev_press_xy); event->val = KM_CLICK; @@ -3402,15 +3407,15 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } } - else if (event->val == KM_DBL_CLICK) { - /* The underlying event is a press, so try and handle this. */ - event->val = KM_PRESS; - action |= wm_handlers_do_intern(C, win, event, handlers); + } + else if (event->val == KM_DBL_CLICK) { + /* The underlying event is a press, so try and handle this. */ + event->val = KM_PRESS; + action |= wm_handlers_do_intern(C, win, event, handlers); - /* Revert value if not handled. */ - if (wm_action_not_handled(action)) { - event->val = KM_DBL_CLICK; - } + /* Revert value if not handled. */ + if (wm_action_not_handled(action)) { + event->val = KM_DBL_CLICK; } } } @@ -3474,7 +3479,7 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2]) } } } - return NULL; + return nullptr; } static ARegion *region_event_inside(bContext *C, const int xy[2]) @@ -3489,14 +3494,14 @@ static ARegion *region_event_inside(bContext *C, const int xy[2]) } } } - return NULL; + return nullptr; } static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region) { if (region) { for (; pc; pc = pc->next) { - if (pc->poll == NULL || pc->poll(C)) { + if (pc->poll == nullptr || pc->poll(C)) { wmWindow *win = CTX_wm_window(C); WM_paint_cursor_tag_redraw(win, region); } @@ -3517,17 +3522,18 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event) ARegion *region = CTX_wm_region(C); if (region) { - wm_paintcursor_tag(C, wm->paintcursors.first, region); + wm_paintcursor_tag(C, static_cast<wmPaintCursor *>(wm->paintcursors.first), region); } /* If previous position was not in current region, we have to set a temp new context. */ - if (region == NULL || !BLI_rcti_isect_pt_v(®ion->winrct, event->prev_xy)) { + if (region == nullptr || !BLI_rcti_isect_pt_v(®ion->winrct, event->prev_xy)) { ScrArea *area = CTX_wm_area(C); CTX_wm_area_set(C, area_event_inside(C, event->prev_xy)); CTX_wm_region_set(C, region_event_inside(C, event->prev_xy)); - wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C)); + wm_paintcursor_tag( + C, static_cast<wmPaintCursor *>(wm->paintcursors.first), CTX_wm_region(C)); CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); @@ -3644,27 +3650,29 @@ static void wm_event_handle_xrevent(bContext *C, int action = wm_handlers_do(C, event, &win->modalhandlers); if ((action & WM_HANDLER_BREAK) == 0) { - wmXrActionData *actiondata = event->customdata; + wmXrActionData *actiondata = static_cast<wmXrActionData *>(event->customdata); if (actiondata->ot->modal && event->val == KM_RELEASE) { /* Don't execute modal operators on release. */ } else { - PointerRNA properties = {.type = actiondata->ot->srna, .data = actiondata->op_properties}; + PointerRNA properties{}; + properties.type = actiondata->ot->srna; + properties.data = actiondata->op_properties; if (actiondata->ot->invoke) { /* Invoke operator, either executing operator or transferring responsibility to window * modal handlers. */ wm_operator_invoke(C, actiondata->ot, event, - actiondata->op_properties ? &properties : NULL, - NULL, + actiondata->op_properties ? &properties : nullptr, + nullptr, false, false); } else { /* Execute operator. */ wmOperator *op = wm_operator_create( - wm, actiondata->ot, actiondata->op_properties ? &properties : NULL, NULL); + wm, actiondata->ot, actiondata->op_properties ? &properties : nullptr, nullptr); if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) { WM_operator_free(op); } @@ -3672,8 +3680,8 @@ static void wm_event_handle_xrevent(bContext *C, } } - CTX_wm_region_set(C, NULL); - CTX_wm_area_set(C, NULL); + CTX_wm_region_set(C, nullptr); + CTX_wm_area_set(C, nullptr); } #endif /* WITH_XR_OPENXR */ @@ -3743,16 +3751,16 @@ void wm_event_do_handlers(bContext *C) BLI_assert(WM_window_get_active_screen(win)); BLI_assert(WM_window_get_active_workspace(win)); - if (screen == NULL) { + if (screen == nullptr) { wm_event_free_all(win); } else { Scene *scene = WM_window_get_active_scene(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer); - Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL; + Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr; - if (scene_eval != NULL) { + if (scene_eval != nullptr) { const int is_playing_sound = BKE_sound_scene_playing(scene_eval); if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) { @@ -3762,7 +3770,7 @@ void wm_event_do_handlers(bContext *C) else if (is_playing_sound != -1) { bool is_playing_screen; - is_playing_screen = (ED_screen_animation_playing(wm) != NULL); + is_playing_screen = (ED_screen_animation_playing(wm) != nullptr); if (((is_playing_sound == 1) && (is_playing_screen == 0)) || ((is_playing_sound == 0) && (is_playing_screen == 1))) { @@ -3788,7 +3796,7 @@ void wm_event_do_handlers(bContext *C) if (ncfra != scene->r.cfra) { scene->r.cfra = ncfra; ED_update_for_newframe(CTX_data_main(C), depsgraph); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, nullptr); } } } @@ -3797,7 +3805,7 @@ void wm_event_do_handlers(bContext *C) } wmEvent *event; - while ((event = win->event_queue.first)) { + while ((event = static_cast<wmEvent *>(win->event_queue.first))) { int action = WM_HANDLER_CONTINUE; /* Force handling drag if a key is pressed even if the drag threshold has not been met. @@ -3869,7 +3877,7 @@ void wm_event_do_handlers(bContext *C) action |= wm_handlers_do(C, event, &win->modalhandlers); /* File-read case. */ - if (CTX_wm_window(C) == NULL) { + if (CTX_wm_window(C) == nullptr) { wm_event_free_and_remove_from_queue_if_valid(event); return; } @@ -3905,7 +3913,7 @@ void wm_event_do_handlers(bContext *C) ED_screen_areas_iter (win, screen, area) { /* After restoring a screen from SCREENMAXIMIZED we have to wait * with the screen handling till the region coordinates are updated. */ - if (screen->skip_handling == true) { + if (screen->skip_handling) { /* Restore for the next iteration of wm_event_do_handlers. */ screen->skip_handling = false; break; @@ -3923,18 +3931,18 @@ void wm_event_do_handlers(bContext *C) action |= wm_event_do_handlers_area_regions(C, event, area); /* File-read case (Python), T29489. */ - if (CTX_wm_window(C) == NULL) { + if (CTX_wm_window(C) == nullptr) { wm_event_free_and_remove_from_queue_if_valid(event); return; } - CTX_wm_region_set(C, NULL); + CTX_wm_region_set(C, nullptr); if ((action & WM_HANDLER_BREAK) == 0) { wm_region_mouse_co(C, event); /* Only invalidates `event->mval` in this case. */ action |= wm_handlers_do(C, event, &area->handlers); } - CTX_wm_area_set(C, NULL); + CTX_wm_area_set(C, nullptr); /* NOTE: do not escape on #WM_HANDLER_BREAK, * mouse-move needs handled for previous area. */ @@ -3951,7 +3959,7 @@ void wm_event_do_handlers(bContext *C) action |= wm_handlers_do(C, event, &win->handlers); /* File-read case. */ - if (CTX_wm_window(C) == NULL) { + if (CTX_wm_window(C) == nullptr) { wm_event_free_and_remove_from_queue_if_valid(event); return; } @@ -3992,12 +4000,12 @@ void wm_event_do_handlers(bContext *C) tevent.val = KM_NOTHING; tevent.prev_xy[0] = tevent.xy[0]; tevent.prev_xy[1] = tevent.xy[1]; - tevent.flag = 0; + tevent.flag = (eWM_EventFlag)0; wm_event_add(win, &tevent); win->addmousemove = 0; } - CTX_wm_window_set(C, NULL); + CTX_wm_window_set(C, nullptr); } /* Update key configuration after handling events. */ @@ -4019,7 +4027,7 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval event.type = EVT_FILESELECT; event.val = eventval; - event.flag = 0; + event.flag = (eWM_EventFlag)0; event.customdata = ophandle; /* Only as void pointer type check. */ wm_event_add(win, &event); @@ -4063,8 +4071,9 @@ static wmWindow *wm_event_find_fileselect_root_window_from_context(const bContex /* Fallback to the first window. */ const wmWindowManager *wm = CTX_wm_manager(C); - BLI_assert(!ED_fileselect_handler_area_find_any_with_op(wm->windows.first)); - return wm->windows.first; + BLI_assert(!ED_fileselect_handler_area_find_any_with_op( + static_cast<const wmWindow *>(wm->windows.first))); + return static_cast<wmWindow *>(wm->windows.first); } /* Operator is supposed to have a filled "path" property. */ @@ -4079,8 +4088,8 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) * File Browser operation, to be restored for eventually executing the file operation. */ wmWindow *root_win = wm_event_find_fileselect_root_window_from_context(C); /* Determined later. */ - ScrArea *root_area = NULL; - ARegion *root_region = NULL; + ScrArea *root_area = nullptr; + ARegion *root_region = nullptr; /* Close any popups, like when opening a file browser from the splash. */ UI_popup_handlers_remove_all(C, &root_win->modalhandlers); @@ -4117,7 +4126,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) } } - BLI_assert(root_win != NULL); + BLI_assert(root_win != nullptr); /* When not reusing the root context from a previous file browsing operation, use the current * area & region, if they are inside the root window. */ if (!root_area && ctx_win == root_win) { @@ -4125,7 +4134,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) root_region = CTX_wm_region(C); } - wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__); + wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__); handler->head.type = WM_HANDLER_TYPE_OP; handler->is_fileselect = true; @@ -4165,7 +4174,7 @@ static void WM_event_set_handler_flag(wmEventHandler *handler, int flag) wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op) { - wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__); + wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__); handler->head.type = WM_HANDLER_TYPE_OP; wmWindow *win = CTX_wm_window(C); @@ -4219,7 +4228,7 @@ void WM_event_modal_handler_region_replace(wmWindow *win, * it needs to keep old region stored in handler, so don't change it. */ if ((handler->context.region == old_region) && (handler->is_fileselect == false)) { handler->context.region = new_region; - handler->context.region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW; + handler->context.region_type = new_region ? new_region->regiontype : (int)RGN_TYPE_WINDOW; } } } @@ -4228,8 +4237,8 @@ void WM_event_modal_handler_region_replace(wmWindow *win, wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap) { if (!keymap) { - CLOG_WARN(WM_LOG_HANDLERS, "called with NULL key-map"); - return NULL; + CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr key-map"); + return nullptr; } /* Only allow same key-map once. */ @@ -4242,7 +4251,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap } } - wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__); + wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__); handler->head.type = WM_HANDLER_TYPE_KEYMAP; BLI_addtail(handlers, handler); handler->keymap = keymap; @@ -4274,16 +4283,16 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm, const char *keymap_id_list[ARRAY_SIZE(km_result->keymaps)]; int keymap_id_list_len = 0; - /* NOTE(@campbellbarton): If `win` is NULL, this function may not behave as expected. + /* NOTE(@campbellbarton): If `win` is nullptr, this function may not behave as expected. * Assert since this should not happen in practice. * If it does, the window could be looked up in `wm` using the `area`. - * Keep NULL checks in run-time code since any crashes here are difficult to redo. */ - BLI_assert_msg(win != NULL, "The window should always be set for tool interactions!"); - const Scene *scene = win ? win->scene : NULL; + * Keep nullptr checks in run-time code since any crashes here are difficult to redo. */ + BLI_assert_msg(win != nullptr, "The window should always be set for tool interactions!"); + const Scene *scene = win ? win->scene : nullptr; - ScrArea *area = handler->dynamic.user_data; - handler->keymap_tool = NULL; - bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL; + ScrArea *area = static_cast<ScrArea *>(handler->dynamic.user_data); + handler->keymap_tool = nullptr; + bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : nullptr; if (tref_rt && tref_rt->keymap[0]) { keymap_id_list[keymap_id_list_len++] = tref_rt->keymap; @@ -4302,18 +4311,18 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm, } if (with_gizmos && (tref_rt->gizmo_group[0] != '\0')) { - wmGizmoMap *gzmap = NULL; - wmGizmoGroup *gzgroup = NULL; + wmGizmoMap *gzmap = nullptr; + wmGizmoGroup *gzgroup = nullptr; LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->gizmo_map != NULL) { + if (region->gizmo_map != nullptr) { gzmap = region->gizmo_map; gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group); - if (gzgroup != NULL) { + if (gzgroup != nullptr) { break; } } } - if (gzgroup != NULL) { + if (gzgroup != nullptr) { if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) { /* If all are hidden, don't override. */ is_gizmo_visible = true; @@ -4344,7 +4353,7 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm, wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty( &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW); /* We shouldn't use key-maps from unrelated spaces. */ - if (km == NULL) { + if (km == nullptr) { printf("Key-map: '%s' not found for tool '%s'\n", keymap_id, area->runtime.tool->idname); continue; } @@ -4369,12 +4378,12 @@ void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, false); } -struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic( +wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic( ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data) { if (!keymap_fn) { - CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap_fn"); - return NULL; + CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr keymap_fn"); + return nullptr; } /* Only allow same key-map once. */ @@ -4389,7 +4398,7 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic( } } - wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__); + wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__); handler->head.type = WM_HANDLER_TYPE_KEYMAP; BLI_addtail(handlers, handler); handler->dynamic.keymap_fn = keymap_fn; @@ -4404,7 +4413,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers, { WM_event_remove_keymap_handler(handlers, keymap); - wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), "event key-map handler"); + wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>("event key-map handler"); handler->head.type = WM_HANDLER_TYPE_KEYMAP; BLI_addhead(handlers, handler); @@ -4436,8 +4445,8 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handlers, EventHandlerPoll poll) { wmEventHandler_Keymap *handler = WM_event_add_keymap_handler(handlers, keymap); - if (handler == NULL) { - return NULL; + if (handler == nullptr) { + return nullptr; } handler->head.poll = poll; @@ -4480,7 +4489,7 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C, void *user_data, const char flag) { - wmEventHandler_UI *handler = MEM_callocN(sizeof(*handler), __func__); + wmEventHandler_UI *handler = MEM_cnew<wmEventHandler_UI>(__func__); handler->head.type = WM_HANDLER_TYPE_UI; handler->handle_fn = handle_fn; handler->remove_fn = remove_fn; @@ -4491,9 +4500,9 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C, handler->context.menu = CTX_wm_menu(C); } else { - handler->context.area = NULL; - handler->context.region = NULL; - handler->context.menu = NULL; + handler->context.area = nullptr; + handler->context.region = nullptr; + handler->context.menu = nullptr; } BLI_assert((flag & WM_HANDLER_DO_FREE) == 0); @@ -4558,7 +4567,7 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas } } - wmEventHandler_Dropbox *handler = MEM_callocN(sizeof(*handler), __func__); + wmEventHandler_Dropbox *handler = MEM_cnew<wmEventHandler_Dropbox>(__func__); handler->head.type = WM_HANDLER_TYPE_DROPBOX; /* Dropbox stored static, no free or copy. */ @@ -4583,6 +4592,20 @@ void WM_event_remove_area_handler(ListBase *handlers, void *area) } } +wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot) +{ + LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) { + if (handler_base->type != WM_HANDLER_TYPE_OP) { + continue; + } + wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; + if (handler->op && handler->op->type == ot) { + return handler->op; + } + } + return nullptr; +} + #if 0 static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler) { @@ -4853,22 +4876,25 @@ static void wm_eventemulation(wmEvent *event, bool test_only) } } -static const wmTabletData wm_event_tablet_data_default = { - .active = EVT_TABLET_NONE, - .pressure = 1.0f, - .x_tilt = 0.0f, - .y_tilt = 0.0f, - .is_motion_absolute = false, -}; +constexpr wmTabletData wm_event_tablet_data_default() +{ + wmTabletData tablet_data{}; + tablet_data.active = EVT_TABLET_NONE; + tablet_data.pressure = 1.0f; + tablet_data.x_tilt = 0.0f; + tablet_data.y_tilt = 0.0f; + tablet_data.is_motion_absolute = false; + return tablet_data; +} void WM_event_tablet_data_default_set(wmTabletData *tablet_data) { - *tablet_data = wm_event_tablet_data_default; + *tablet_data = wm_event_tablet_data_default(); } void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab) { - if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) { + if ((tablet_data != nullptr) && tablet_data->Active != GHOST_kTabletModeNone) { wmtab->active = (int)tablet_data->Active; wmtab->pressure = wm_pressure_curve(tablet_data->Pressure); wmtab->x_tilt = tablet_data->Xtilt; @@ -4878,7 +4904,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure); } else { - *wmtab = wm_event_tablet_data_default; + *wmtab = wm_event_tablet_data_default(); // printf("%s: not using tablet\n", __func__); } } @@ -4887,7 +4913,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData /* Adds custom-data to event. */ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost) { - wmNDOFMotionData *data = MEM_mallocN(sizeof(wmNDOFMotionData), "Custom-data NDOF"); + wmNDOFMotionData *data = MEM_cnew<wmNDOFMotionData>("Custom-data NDOF"); const float ts = U.ndof_sensitivity; const float rs = U.ndof_orbit_sensitivity; @@ -4915,33 +4941,38 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g /* Imperfect but probably usable... draw/enable drags to other windows. */ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event) { - int mval[2] = {event->xy[0], event->xy[1]}; + /* If GHOST doesn't support window positioning, don't use this feature at all. */ + const static int8_t supports_window_position = GHOST_SupportsWindowPosition(); + if (!supports_window_position) { + return nullptr; + } if (wm->windows.first == wm->windows.last) { - return NULL; + return nullptr; } /* In order to use window size and mouse position (pixels), we have to use a WM function. */ /* Check if outside, include top window bar. */ - if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) || - mval[1] > WM_window_pixels_y(win) + 30) { + int event_xy[2] = {UNPACK2(event->xy)}; + if (event_xy[0] < 0 || event_xy[1] < 0 || event_xy[0] > WM_window_pixels_x(win) || + event_xy[1] > WM_window_pixels_y(win) + 30) { /* Let's skip windows having modal handlers now. */ /* Potential XXX ugly... I wouldn't have added a `modalhandlers` list * (introduced in rev 23331, ton). */ LISTBASE_FOREACH (wmEventHandler *, handler, &win->modalhandlers) { if (ELEM(handler->type, WM_HANDLER_TYPE_UI, WM_HANDLER_TYPE_OP)) { - return NULL; + return nullptr; } } - wmWindow *win_other = WM_window_find_under_cursor(win, mval, mval); + wmWindow *win_other = WM_window_find_under_cursor(win, event_xy, event_xy); if (win_other && win_other != win) { - copy_v2_v2_int(event->xy, mval); + copy_v2_v2_int(event->xy, event_xy); return win_other; } } - return NULL; + return nullptr; } static bool wm_event_is_double_click(const wmEvent *event) @@ -4982,18 +5013,18 @@ static void wm_event_prev_click_set(wmEvent *event_state) static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event) { - wmEvent *event_last = win->event_queue.last; + wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last); /* Some painting operators want accurate mouse events, they can * handle in between mouse move moves, others can happily ignore * them for better performance. */ if (event_last && event_last->type == MOUSEMOVE) { event_last->type = INBETWEEN_MOUSEMOVE; - event_last->flag = 0; + event_last->flag = (eWM_EventFlag)0; } wmEvent *event_new = wm_event_add(win, event); - if (event_last == NULL) { + if (event_last == nullptr) { event_last = win->eventstate; } @@ -5012,7 +5043,7 @@ static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win) if (event_last) { tevent = *event_last; - tevent.flag = 0; + tevent.flag = (eWM_EventFlag)0; tevent.ascii = '\0'; tevent.utf8_buf[0] = '\0'; @@ -5038,7 +5069,7 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d { /* Ignore in between track-pad events for performance, we only need high accuracy * for painting with mouse moves, for navigation using the accumulated value is ok. */ - wmEvent *event_last = win->event_queue.last; + wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last); if (event_last && event_last->type == event->type) { deltax += event_last->xy[0] - event_last->prev_xy[0]; deltay += event_last->xy[1] - event_last->prev_xy[1]; @@ -5127,7 +5158,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void /* Initialize and copy state (only mouse x y and modifiers). */ event = *event_state; - event.flag = 0; + event.flag = (eWM_EventFlag)0; /** * Always support accessing the last key press/release. This is set from `win->eventstate`, @@ -5164,7 +5195,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void switch (type) { /* Mouse move, also to inactive window (X11 does this). */ case GHOST_kEventCursorMove: { - GHOST_TEventCursorData *cd = customdata; + GHOST_TEventCursorData *cd = static_cast<GHOST_TEventCursorData *>(customdata); copy_v2_v2_int(event.xy, &cd->x); wm_stereo3d_mouse_offset_apply(win, event.xy); @@ -5201,7 +5232,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void break; } case GHOST_kEventTrackpad: { - GHOST_TEventTrackpadData *pd = customdata; + GHOST_TEventTrackpadData *pd = static_cast<GHOST_TEventTrackpadData *>(customdata); switch (pd->subtype) { case GHOST_kTrackpadEventMagnify: event.type = MOUSEZOOM; @@ -5235,7 +5266,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void /* Mouse button. */ case GHOST_kEventButtonDown: case GHOST_kEventButtonUp: { - GHOST_TEventButtonData *bd = customdata; + GHOST_TEventButtonData *bd = static_cast<GHOST_TEventButtonData *>(customdata); /* Get value and type from Ghost. */ event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE; @@ -5266,7 +5297,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void wm_tablet_data_from_ghost(&bd->tablet, &event.tablet); wm_eventemulation(&event, false); - wm_event_state_update_and_click_set(&event, event_state, type); + wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type); /* Add to other window if event is there (not to both!). */ wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event); @@ -5294,14 +5325,14 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void /* Keyboard. */ case GHOST_kEventKeyDown: case GHOST_kEventKeyUp: { - GHOST_TEventKeyData *kd = customdata; + GHOST_TEventKeyData *kd = static_cast<GHOST_TEventKeyData *>(customdata); event.type = convert_key(kd->key); if (UNLIKELY(event.type == EVENT_NONE)) { break; } event.ascii = kd->ascii; - /* Might be not NULL terminated. */ + /* Might be not nullptr terminated. */ memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); if (kd->is_repeat) { event.flag |= WM_EVENT_IS_REPEAT; @@ -5390,7 +5421,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void } /* It's important `event.modifier` has been initialized first. */ - wm_event_state_update_and_click_set(&event, event_state, type); + wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type); /* If test_break set, it catches this. Do not set with modifier presses. * Exclude modifiers because MS-Windows uses these to bring up the task manager. @@ -5409,7 +5440,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void } case GHOST_kEventWheel: { - GHOST_TEventWheelData *wheelData = customdata; + GHOST_TEventWheelData *wheelData = static_cast<GHOST_TEventWheelData *>(customdata); if (wheelData->z > 0) { event.type = WHEELUPMOUSE; @@ -5438,7 +5469,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case GHOST_kEventNDOFMotion: { event.type = NDOF_MOTION; event.val = KM_NOTHING; - attach_ndof_data(&event, customdata); + attach_ndof_data(&event, static_cast<const GHOST_TEventNDOFMotionData *>(customdata)); wm_event_add(win, &event); CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.xy[0], event.xy[1]); @@ -5446,7 +5477,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void } case GHOST_kEventNDOFButton: { - GHOST_TEventNDOFButtonData *e = customdata; + GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata); event.type = NDOF_BUTTON_NONE + e->button; @@ -5462,9 +5493,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void } event.custom = 0; - event.customdata = NULL; + event.customdata = nullptr; - wm_event_state_update_and_click_set(&event, event_state, type); + wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type); wm_event_add(win, &event); @@ -5486,7 +5517,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void #ifdef WITH_INPUT_IME case GHOST_kEventImeCompositionStart: { event.val = KM_PRESS; - win->ime_data = customdata; + win->ime_data = static_cast<wmIMEData *>(customdata); win->ime_data->is_ime_composing = true; event.type = WM_IME_COMPOSITE_START; wm_event_add(win, &event); @@ -5520,14 +5551,13 @@ void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val) { BLI_assert(ELEM(val, KM_PRESS, KM_RELEASE)); - wmEvent event = { - .type = EVT_XR_ACTION, - .val = val, - .flag = 0, - .custom = EVT_DATA_XR, - .customdata = actiondata, - .customdata_free = true, - }; + wmEvent event{}; + event.type = EVT_XR_ACTION; + event.val = val; + event.flag = (eWM_EventFlag)0; + event.custom = EVT_DATA_XR; + event.customdata = actiondata; + event.customdata_free = true; wm_event_add(win, &event); } @@ -5588,15 +5618,15 @@ void WM_event_get_keymaps_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result) { - if (handler->dynamic.keymap_fn != NULL) { + if (handler->dynamic.keymap_fn != nullptr) { handler->dynamic.keymap_fn(wm, win, handler, km_result); - BLI_assert(handler->keymap == NULL); + BLI_assert(handler->keymap == nullptr); } else { memset(km_result, 0x0, sizeof(*km_result)); wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap); - BLI_assert(keymap != NULL); - if (keymap != NULL) { + BLI_assert(keymap != nullptr); + if (keymap != nullptr) { km_result->keymaps[km_result->keymaps_len++] = keymap; } } @@ -5606,13 +5636,13 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm { LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if (wm_eventmatch(event, kmi)) { - wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); + wmOperatorType *ot = WM_operatortype_find(kmi->idname, false); if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) { return kmi; } } } - return NULL; + return nullptr; } wmKeyMapItem *WM_event_match_keymap_item_from_handlers( @@ -5623,7 +5653,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers( if (handler_base->flag & WM_HANDLER_DO_FREE) { /* Pass. */ } - else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) { + else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) { if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) { wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; wmEventHandler_KeymapResult km_result; @@ -5632,7 +5662,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers( wmKeyMap *keymap = km_result.keymaps[km_index]; if (WM_keymap_poll(C, keymap)) { wmKeyMapItem *kmi = WM_event_match_keymap_item(C, keymap, event); - if (kmi != NULL) { + if (kmi != nullptr) { return kmi; } } @@ -5640,7 +5670,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers( } } } - return NULL; + return nullptr; } /** \} */ @@ -5670,10 +5700,10 @@ struct CursorKeymapInfo { */ char text[3][2][128]; wmEvent state_event; - struct CursorKeymapInfo_State state; + CursorKeymapInfo_State state; }; -static void wm_event_cursor_store(struct CursorKeymapInfo_State *state, +static void wm_event_cursor_store(CursorKeymapInfo_State *state, const wmEvent *event, short space_type, short region_type, @@ -5682,29 +5712,29 @@ static void wm_event_cursor_store(struct CursorKeymapInfo_State *state, state->modifier = event->modifier; state->space_type = space_type; state->region_type = region_type; - state->tref = tref ? *tref : (bToolRef){0}; + state->tref = tref ? *tref : bToolRef{}; } const char *WM_window_cursor_keymap_status_get(const wmWindow *win, int button_index, int type_index) { - if (win->cursor_keymap_status != NULL) { - struct CursorKeymapInfo *cd = win->cursor_keymap_status; + if (win->cursor_keymap_status != nullptr) { + CursorKeymapInfo *cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status); const char *msg = cd->text[button_index][type_index]; if (*msg) { return msg; } } - return NULL; + return nullptr; } ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen) { if (screen->state == SCREENFULL) { - return NULL; + return nullptr; } - ScrArea *area_statusbar = NULL; + ScrArea *area_statusbar = nullptr; LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { if (area->spacetype == SPACE_STATUSBAR) { area_statusbar = area; @@ -5718,7 +5748,7 @@ void WM_window_status_area_tag_redraw(wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); ScrArea *area = WM_window_status_area_find(win, screen); - if (area != NULL) { + if (area != nullptr) { ED_area_tag_redraw(area); } } @@ -5727,16 +5757,16 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); ScrArea *area_statusbar = WM_window_status_area_find(win, screen); - if (area_statusbar == NULL) { + if (area_statusbar == nullptr) { MEM_SAFE_FREE(win->cursor_keymap_status); return; } - struct CursorKeymapInfo *cd; - if (UNLIKELY(win->cursor_keymap_status == NULL)) { - win->cursor_keymap_status = MEM_callocN(sizeof(struct CursorKeymapInfo), __func__); + CursorKeymapInfo *cd; + if (UNLIKELY(win->cursor_keymap_status == nullptr)) { + win->cursor_keymap_status = MEM_callocN(sizeof(CursorKeymapInfo), __func__); } - cd = win->cursor_keymap_status; + cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status); /* Detect unchanged state (early exit). */ if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) { @@ -5745,23 +5775,23 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) /* Now perform more comprehensive check, * still keep this fast since it happens on mouse-move. */ - struct CursorKeymapInfo cd_prev = *((struct CursorKeymapInfo *)win->cursor_keymap_status); + CursorKeymapInfo cd_prev = *((CursorKeymapInfo *)win->cursor_keymap_status); cd->state_event = *win->eventstate; /* Find active region and associated area. */ ARegion *region = screen->active_region; - if (region == NULL) { + if (region == nullptr) { return; } - ScrArea *area = NULL; + ScrArea *area = nullptr; ED_screen_areas_iter (win, screen, area_iter) { if (BLI_findindex(&area_iter->regionbase, region) != -1) { area = area_iter; break; } } - if (area == NULL) { + if (area == nullptr) { return; } @@ -5784,15 +5814,14 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) /* Detect changes to the state. */ { - bToolRef *tref = NULL; + bToolRef *tref = nullptr; if ((region->regiontype == RGN_TYPE_WINDOW) && ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) { ViewLayer *view_layer = WM_window_get_active_view_layer(win); WorkSpace *workspace = WM_window_get_active_workspace(win); - const bToolKey tkey = { - .space_type = area->spacetype, - .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype), - }; + bToolKey tkey{}; + tkey.space_type = area->spacetype; + tkey.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype); tref = WM_toolsystem_ref_find(workspace, &tkey); } wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref); @@ -5846,9 +5875,9 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) wmEvent test_event = *win->eventstate; test_event.type = event_data[data_index].event_type; test_event.val = event_data[data_index].event_value; - test_event.flag = 0; + test_event.flag = (eWM_EventFlag)0; wm_eventemulation(&test_event, true); - wmKeyMapItem *kmi = NULL; + wmKeyMapItem *kmi = nullptr; for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { kmi = WM_event_match_keymap_item_from_handlers( C, wm, win, handlers[handler_index], &test_event); @@ -5857,7 +5886,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) } } if (kmi) { - wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); + wmOperatorType *ot = WM_operatortype_find(kmi->idname, false); const char *name = (ot) ? WM_operatortype_name(ot, kmi->ptr) : kmi->idname; STRNCPY(cd->text[button_index][type_index], name); } @@ -5867,7 +5896,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) ED_area_tag_redraw(area_statusbar); } - CTX_wm_window_set(C, NULL); + CTX_wm_window_set(C, nullptr); } /** \} */ @@ -5879,12 +5908,12 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *layout) { wmWindowManager *wm = CTX_wm_manager(C); - wmKeyMap *keymap = NULL; - wmOperator *op = NULL; + wmKeyMap *keymap = nullptr; + wmOperator *op = nullptr; LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) { if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; - if (handler->op != NULL) { + if (handler->op != nullptr) { /* 'handler->keymap' could be checked too, seems not to be used. */ wmKeyMap *keymap_test = WM_keymap_active(wm, handler->op->type->modalkeymap); if (keymap_test && keymap_test->modal_items) { @@ -5895,17 +5924,17 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la } } } - if (keymap == NULL || keymap->modal_items == NULL) { + if (keymap == nullptr || keymap->modal_items == nullptr) { return false; } - const EnumPropertyItem *items = keymap->modal_items; + const EnumPropertyItem *items = static_cast<const EnumPropertyItem *>(keymap->modal_items); uiLayout *row = uiLayoutRow(layout, true); for (int i = 0; items[i].identifier; i++) { if (!items[i].identifier[0]) { continue; } - if ((keymap->poll_modal_item != NULL) && + if ((keymap->poll_modal_item != nullptr) && (keymap->poll_modal_item(op, items[i].value) == false)) { continue; } @@ -5914,13 +5943,13 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la { /* WARNING: O(n^2). */ - wmKeyMapItem *kmi = NULL; - for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + wmKeyMapItem *kmi = nullptr; + for (kmi = static_cast<wmKeyMapItem *>(keymap->items.first); kmi; kmi = kmi->next) { if (kmi->propvalue == items[i].value) { break; } } - if (kmi != NULL) { + if (kmi != nullptr) { if (kmi->val == KM_RELEASE) { /* Assume release events just disable something which was toggled on. */ continue; diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 06640fc9a20..011ad44853e 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1096,7 +1096,7 @@ void wm_homefile_read_ex(bContext *C, const bool reset_app_template = ((!app_template && U.app_template[0]) || (app_template && !STREQ(app_template, U.app_template))); - /* options exclude eachother */ + /* Options exclude each other. */ BLI_assert((use_factory_settings && filepath_startup_override) == 0); if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) { diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index b41ffb4cfc2..f2c41dada48 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -438,7 +438,7 @@ void WM_OT_link(wmOperatorType *ot) ot->exec = wm_link_append_exec; ot->poll = wm_link_append_poll; - ot->flag |= OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, @@ -462,7 +462,7 @@ void WM_OT_append(wmOperatorType *ot) ot->exec = wm_link_append_exec; ot->poll = wm_link_append_poll; - ot->flag |= OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, @@ -803,7 +803,7 @@ void WM_OT_lib_relocate(wmOperatorType *ot) ot->invoke = wm_lib_relocate_invoke; ot->exec = wm_lib_relocate_exec; - ot->flag |= OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate"); RNA_def_property_flag(prop, PROP_HIDDEN); @@ -833,7 +833,7 @@ void WM_OT_lib_reload(wmOperatorType *ot) ot->exec = wm_lib_reload_exec; - ot->flag |= OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload"); RNA_def_property_flag(prop, PROP_HIDDEN); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index dbce360cb61..f77aad24719 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -338,10 +338,10 @@ void WM_init(bContext *C, int argc, const char **argv) if (!G.background) { if (wm_start_with_console) { - setConsoleWindowState(GHOST_kConsoleWindowStateShow); + GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateShow); } else { - setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch); + GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch); } } @@ -380,7 +380,7 @@ static void free_openrecent(void) } #ifdef WIN32 -/* Read console events until there is a key event. Also returns on any error. */ +/* Read console events until there is a key event. Also returns on any error. */ static void wait_for_console_key(void) { HANDLE hConsoleInput = GetStdHandle(STD_INPUT_HANDLE); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index b44cf9e48b8..d5c4d07e9ed 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -87,6 +87,16 @@ struct wmJob { * Executed in main thread. */ void (*endjob)(void *); + /** + * Called when job is stopped normally, i.e. by simply completing the startjob function. + * Executed in main thread. + */ + void (*completed)(void *); + /** + * Called when job is stopped abnormally, i.e. when stop=true but ready=false. + * Executed in main thread. + */ + void (*canceled)(void *); /** Running jobs each have own timer */ double timestep; @@ -344,10 +354,23 @@ void WM_jobs_callbacks(wmJob *wm_job, void (*update)(void *), void (*endjob)(void *)) { + WM_jobs_callbacks_ex(wm_job, startjob, initjob, update, endjob, NULL, NULL); +} + +void WM_jobs_callbacks_ex(wmJob *wm_job, + wm_jobs_start_callback startjob, + void (*initjob)(void *), + void (*update)(void *), + void (*endjob)(void *), + void (*completed)(void *), + void (*canceled)(void *)) +{ wm_job->startjob = startjob; wm_job->initjob = initjob; wm_job->update = update; wm_job->endjob = endjob; + wm_job->completed = completed; + wm_job->canceled = canceled; } static void *do_job_thread(void *job_v) @@ -465,6 +488,24 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) } } +static void wm_job_end(wmJob *wm_job) +{ + BLI_assert_msg(BLI_thread_is_main(), "wm_job_end should only be called from the main thread"); + if (wm_job->endjob) { + wm_job->endjob(wm_job->run_customdata); + } + + /* Do the final callback based on whether the job was run to completion or not. + * Not all jobs have the same way of signaling cancellation (i.e. rendering stops when + * `G.is_break == true`, but doesn't set any wm_job properties to cancel the WM job). */ + const bool was_canceled = wm_job->stop || G.is_break; + void (*final_callback)(void *) = (wm_job->ready && !was_canceled) ? wm_job->completed : + wm_job->canceled; + if (final_callback) { + final_callback(wm_job->run_customdata); + } +} + static void wm_job_free(wmWindowManager *wm, wmJob *wm_job) { BLI_remlink(&wm->jobs, wm_job); @@ -485,10 +526,7 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job) WM_job_main_thread_lock_release(wm_job); BLI_threadpool_end(&wm_job->threads); WM_job_main_thread_lock_acquire(wm_job); - - if (wm_job->endjob) { - wm_job->endjob(wm_job->run_customdata); - } + wm_job_end(wm_job); } if (wm_job->wt) { @@ -600,9 +638,7 @@ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt) } if (wm_job->ready) { - if (wm_job->endjob) { - wm_job->endjob(wm_job->run_customdata); - } + wm_job_end(wm_job); /* free own data */ wm_job->run_free(wm_job->run_customdata); @@ -670,3 +706,13 @@ bool WM_jobs_has_running(const wmWindowManager *wm) return false; } + +bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type) +{ + LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { + if (wm_job->running && wm_job->job_type == job_type) { + return true; + } + } + return false; +} diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 1fa5e64093f..acacbd77f9e 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -445,7 +445,10 @@ bool WM_keymap_poll(bContext *C, wmKeyMap *keymap) * When developing a customized Blender though you may want empty keymaps. */ if (!U.app_template[0] && /* Fallback key-maps may be intentionally empty, don't flood the output. */ - !BLI_str_endswith(keymap->idname, " (fallback)")) { + !BLI_str_endswith(keymap->idname, " (fallback)") && + /* This is an exception which may be empty. + * Longer term we might want a flag to indicate an empty key-map is intended. */ + !STREQ(keymap->idname, "Node Tool: Tweak")) { CLOG_WARN(WM_LOG_KEYMAPS, "empty keymap '%s'", keymap->idname); } } diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c index 5a35570296a..0817b10f86e 100644 --- a/source/blender/windowmanager/intern/wm_keymap_utils.c +++ b/source/blender/windowmanager/intern/wm_keymap_utils.c @@ -270,6 +270,12 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) break; } } + else if (STRPREFIX(opname, "CURVES_OT")) { + km = WM_keymap_find_all(wm, "Curves", 0, 0); + } + else if (STRPREFIX(opname, "SCULPT_CURVES_OT")) { + km = WM_keymap_find_all(wm, "Sculpt Curves", 0, 0); + } else if (STRPREFIX(opname, "MBALL_OT")) { km = WM_keymap_find_all(wm, "Metaball", 0, 0); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 307d3282659..33c69a23558 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1308,6 +1308,10 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i return id; } + if (!WM_operator_properties_id_lookup_is_set(op->ptr)) { + return NULL; + } + /* Lookup an already existing ID. */ id = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, idcode); @@ -2068,7 +2072,7 @@ static void WM_OT_quit_blender(wmOperatorType *ot) static int wm_console_toggle_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) { - setConsoleWindowState(GHOST_kConsoleWindowStateToggle); + GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateToggle); return OPERATOR_FINISHED; } @@ -3898,7 +3902,7 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border"); WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border"); WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_box"); - /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */ + /* XXX TODO: zoom border should perhaps map right-mouse to zoom out instead of in+cancel. */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border"); WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border"); diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 95879829d42..baba64b2230 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -33,6 +33,7 @@ #include "BLI_path_util.h" #include "BLI_rect.h" #include "BLI_string.h" +#include "BLI_system.h" #include "BLI_utildefines.h" #include "IMB_colormanagement.h" @@ -211,7 +212,7 @@ static void playanim_gl_matrix(void) /* implementation */ static void playanim_event_qual_update(void) { - int val; + bool val; /* Shift */ GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftShift, &val); @@ -673,7 +674,7 @@ static void build_pict_list_ex( * * If set, all reads and writes on the resulting file descriptor will * be performed directly to or from the user program buffer, provided - * appropriate size and alignment restrictions are met. Refer to the + * appropriate size and alignment restrictions are met. Refer to the * F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for * information about how to determine the alignment constraints. * O_DIRECT is a Silicon Graphics extension and is only supported on @@ -870,7 +871,7 @@ static void change_frame(PlayState *ps) ps->need_frame_update = false; } -static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) +static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) { PlayState *ps = (PlayState *)ps_void; const GHOST_TEventType type = GHOST_GetEventType(evt); @@ -901,7 +902,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) default: break; } - return 1; + return true; } if (ps->wait2 && ps->stopped == false) { @@ -1334,7 +1335,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) break; } - return 1; + return true; } static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey) @@ -1536,6 +1537,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv) GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps); + GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); + g_WS.ghost_system = GHOST_CreateSystem(); GHOST_AddEventConsumer(g_WS.ghost_system, consumer); @@ -1552,6 +1555,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) /* initialize the font */ BLF_init(); + BLF_load_font_stack(); ps.fontid = BLF_load_mono_default(false); BLF_size(ps.fontid, 11.0f, 72); @@ -1852,7 +1856,7 @@ void WM_main_playanim(int argc, const char **argv) AUD_DeviceSpecs specs; specs.rate = AUD_RATE_48000; - specs.format = AUD_FORMAT_S16; + specs.format = AUD_FORMAT_FLOAT32; specs.channels = AUD_CHANNELS_STEREO; AUD_initOnce(); diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c index 88eacf9013b..6dd64b89eb6 100644 --- a/source/blender/windowmanager/intern/wm_uilist_type.c +++ b/source/blender/windowmanager/intern/wm_uilist_type.c @@ -20,7 +20,6 @@ #include "UI_interface.h" #include "BLI_ghash.h" -#include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_utildefines.h" diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index c0427f9be9a..91ec45da6d4 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -23,6 +23,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_system.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -982,7 +983,7 @@ static int query_qual(modifierKeyType qual) break; } - int val = 0; + bool val = false; GHOST_GetModifierKeyState(g_system, left, &val); if (!val) { GHOST_GetModifierKeyState(g_system, right, &val); @@ -1052,7 +1053,7 @@ void wm_window_reset_drawable(void) * * Mouse coordinate conversion happens here. */ -static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr) +static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr) { bContext *C = C_void_ptr; wmWindowManager *wm = CTX_wm_manager(C); @@ -1090,17 +1091,17 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr * but it should return if WM didn't initialize yet. * Can happen on file read (especially full size window). */ if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) { - return 1; + return true; } if (!ghostwin) { /* XXX: should be checked, why are we getting an event here, and what is it? */ puts("<!> event has no window"); - return 1; + return true; } if (!GHOST_ValidWindow(g_system, ghostwin)) { /* XXX: should be checked, why are we getting an event here, and what is it? */ puts("<!> event has invalid window"); - return 1; + return true; } wmWindow *win = GHOST_GetWindowUserData(ghostwin); @@ -1443,7 +1444,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr } } } - return 1; + return true; } /** @@ -1543,6 +1544,8 @@ void wm_ghost_init(bContext *C) consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); } + GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); + g_system = GHOST_CreateSystem(); GHOST_Debug debug = {0}; @@ -1869,11 +1872,10 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv return NULL; } - wmWindow *r_win = GHOST_GetWindowUserData(ghostwin); - wm_cursor_position_from_ghost(r_win, &tmp[0], &tmp[1]); + wmWindow *win_other = GHOST_GetWindowUserData(ghostwin); + wm_cursor_position_from_ghost(win_other, &tmp[0], &tmp[1]); copy_v2_v2_int(r_mval, tmp); - - return r_win; + return win_other; } void WM_window_pixel_sample_read(const wmWindowManager *wm, diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c index 3c090423c41..3f0c72a4a05 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c @@ -731,8 +731,9 @@ static void wm_xr_raycast(Scene *scene, sctx, depsgraph, NULL, - &(const struct SnapObjectParams){ - .snap_select = (selectable_only ? SNAP_SELECTABLE : SNAP_ALL)}, + &(const struct SnapObjectParams){.snap_target_select = (selectable_only ? + SCE_SNAP_TARGET_ONLY_SELECTABLE : + SCE_SNAP_TARGET_ALL)}, origin, direction, ray_dist, |