diff options
Diffstat (limited to 'source/blender')
643 files changed, 12229 insertions, 10383 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index c6112344208..1fcde431d2d 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -48,7 +48,7 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h - ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_hair_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_ipo_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_key_types.h diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index e2d278255ba..d64e942069d 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -65,6 +65,7 @@ else() ) add_executable(blender-thumbnailer ${SRC} ${SRC_CMD}) + setup_platform_linker_flags(blender-thumbnailer) target_link_libraries(blender-thumbnailer bf_blenlib) target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES}) endif() diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 169107b19cb..638c5b727a6 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -309,7 +309,7 @@ void BLF_thumb_preview(const char *filename, /* blf_default.c */ void BLF_default_dpi(int dpi); -void BLF_default_size(int size); +void BLF_default_size(float size); void BLF_default_set(int fontid); /** * Get default font ID so we can pass it to other functions. diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index dd22bc2e7e0..5d04823cd0a 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -63,10 +63,6 @@ if(WIN32) ) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) list(APPEND INC diff --git a/source/blender/blenfont/intern/blf_default.c b/source/blender/blenfont/intern/blf_default.c index 57eeaa6768d..d5a0d514b5f 100644 --- a/source/blender/blenfont/intern/blf_default.c +++ b/source/blender/blenfont/intern/blf_default.c @@ -37,15 +37,15 @@ /* Default size and dpi, for BLF_draw_default. */ static int global_font_default = -1; static int global_font_dpi = 72; -/* Keep in sync with `UI_style_get()->widgetlabel.points` */ -static int global_font_size = 11; +/* Keep in sync with `UI_DEFAULT_TEXT_POINTS` */ +static float global_font_size = 11.0f; void BLF_default_dpi(int dpi) { global_font_dpi = dpi; } -void BLF_default_size(int size) +void BLF_default_size(float size) { global_font_size = size; } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 14d3a208f69..3ac9fdc7f41 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -34,7 +34,6 @@ #include FT_FREETYPE_H #include FT_GLYPH_H -#include FT_ADVANCES_H /* For FT_Get_Advance */ #include "MEM_guardedalloc.h" @@ -826,7 +825,10 @@ float blf_font_height(FontBLF *font, float blf_font_fixed_width(FontBLF *font) { - return (float)font->fixed_width; + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + float width = (gc) ? (float)gc->fixed_width : font->size / 2.0f; + blf_glyph_cache_release(font); + return width; } static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, @@ -1236,6 +1238,12 @@ FontBLF *blf_font_new(const char *name, const char *filename) font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); err = FT_New_Face(ft_lib, filename, 0, &font->face); if (err) { + if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) { + printf("Format of this font file is not supported\n"); + } + else { + printf("Error encountered while opening font file\n"); + } MEM_freeN(font); return NULL; } @@ -1318,12 +1326,7 @@ FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int m void blf_font_free(FontBLF *font) { - BLI_spin_lock(&blf_glyph_cache_mutex); - GlyphCacheBLF *gc; - - while ((gc = BLI_pophead(&font->cache))) { - blf_glyph_cache_free(gc); - } + blf_glyph_cache_clear(font); if (font->kerning_cache) { MEM_freeN(font->kerning_cache); @@ -1337,8 +1340,6 @@ void blf_font_free(FontBLF *font) MEM_freeN(font->name); } MEM_freeN(font); - - BLI_spin_unlock(&blf_glyph_cache_mutex); } /** \} */ @@ -1347,51 +1348,25 @@ void blf_font_free(FontBLF *font) /** \name Font Configure * \{ */ -void blf_font_size(FontBLF *font, float size, unsigned int dpi) +bool blf_font_size(FontBLF *font, float size, unsigned int dpi) { - blf_glyph_cache_acquire(font); - /* FreeType uses fixed-point integers in 64ths. */ FT_F26Dot6 ft_size = lroundf(size * 64.0f); - /* Adjust our size to be on even 64ths. */ + /* Adjust our new size to be on even 64ths. */ size = (float)ft_size / 64.0f; - GlyphCacheBLF *gc = blf_glyph_cache_find(font, size, dpi); - if (gc && (font->size == size && font->dpi == dpi)) { - /* Optimization: do not call FT_Set_Char_Size if size did not change. */ - } - else { - const FT_Error err = FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi); - if (err) { - /* FIXME: here we can go through the fixed size and choice a close one */ - printf("The current font don't support the size, %f and dpi, %u\n", size, dpi); - } - else { + if (font->size != size || font->dpi != dpi) { + if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) == 0) { font->size = size; font->dpi = dpi; - if (gc == NULL) { - blf_glyph_cache_new(font); - } + } + else { + printf("The current font does not support the size, %f and dpi, %u\n", size, dpi); + return false; } } - blf_glyph_cache_release(font); - - /* Set fixed-width size for monospaced output. */ - FT_UInt gindex = FT_Get_Char_Index(font->face, U'0'); - if (gindex) { - FT_Fixed advance = 0; - FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance); - /* Use CSS 'ch unit' width, advance of zero character. */ - font->fixed_width = (int)(advance >> 16); - } - else { - /* Font does not contain "0" so use CSS fallback of 1/2 of em. */ - font->fixed_width = (int)((font->face->size->metrics.height / 2) >> 6); - } - if (font->fixed_width < 1) { - font->fixed_width = 1; - } + return true; } /** \} */ diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 4f25f99b65c..bcd9e1fb3a2 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -34,6 +34,7 @@ #include FT_GLYPH_H #include FT_OUTLINE_H #include FT_BITMAP_H +#include FT_ADVANCES_H /* For FT_Get_Advance. */ #include "MEM_guardedalloc.h" @@ -73,7 +74,7 @@ static FT_Fixed to_16dot16(double val) /** \name Glyph Cache * \{ */ -GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi) +static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi) { GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first; while (gc) { @@ -86,7 +87,7 @@ GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi) return NULL; } -GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) +static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) { GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); @@ -100,6 +101,22 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table)); memset(gc->bucket, 0, sizeof(gc->bucket)); + /* Determine ideal fixed-width size for monospaced output. */ + FT_UInt gindex = FT_Get_Char_Index(font->face, U'0'); + if (gindex) { + FT_Fixed advance = 0; + FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance); + /* Use CSS 'ch unit' width, advance of zero character. */ + gc->fixed_width = (int)(advance >> 16); + } + else { + /* Font does not contain "0" so use CSS fallback of 1/2 of em. */ + gc->fixed_width = (int)((font->face->size->metrics.height / 2) >> 6); + } + if (gc->fixed_width < 1) { + gc->fixed_width = 1; + } + BLI_addhead(&font->cache, gc); return gc; } @@ -122,20 +139,7 @@ void blf_glyph_cache_release(FontBLF *font) BLI_spin_unlock(font->glyph_cache_mutex); } -void blf_glyph_cache_clear(FontBLF *font) -{ - GlyphCacheBLF *gc; - - BLI_spin_lock(font->glyph_cache_mutex); - - while ((gc = BLI_pophead(&font->cache))) { - blf_glyph_cache_free(gc); - } - - BLI_spin_unlock(font->glyph_cache_mutex); -} - -void blf_glyph_cache_free(GlyphCacheBLF *gc) +static void blf_glyph_cache_free(GlyphCacheBLF *gc) { GlyphBLF *g; for (uint i = 0; i < ARRAY_SIZE(gc->bucket); i++) { @@ -152,6 +156,19 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) MEM_freeN(gc); } +void blf_glyph_cache_clear(FontBLF *font) +{ + GlyphCacheBLF *gc; + + BLI_spin_lock(font->glyph_cache_mutex); + + while ((gc = BLI_pophead(&font->cache))) { + blf_glyph_cache_free(gc); + } + + BLI_spin_unlock(font->glyph_cache_mutex); +} + /** * Try to find a glyph in cache. * diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 4e36f522981..d0bb3385e2c 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -56,7 +56,11 @@ struct FontBLF *blf_font_new(const char *name, const char *filename); struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size); void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); -void blf_font_size(struct FontBLF *font, float size, unsigned int dpi); +/** + * Change font's output size. Returns true if successful in changing the size. + */ +bool blf_font_size(struct FontBLF *font, float size, unsigned int dpi); + void blf_font_draw(struct FontBLF *font, const char *str, size_t str_len, @@ -65,10 +69,7 @@ void blf_font_draw__wrap(struct FontBLF *font, const char *str, size_t str_len, struct ResultBLF *r_info); -void blf_font_draw_ascii(struct FontBLF *font, - const char *str, - size_t str_len, - struct ResultBLF *r_info); + /** * Use fixed column width, but an utf8 character may occupy multiple columns. */ @@ -137,18 +138,9 @@ int blf_font_count_missing_chars(struct FontBLF *font, void blf_font_free(struct FontBLF *font); -/** - * Find a glyph cache that matches a size, DPI & styles. - */ -struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, float size, unsigned int dpi); -/** - * Create a new glyph cache for the current size, DPI & styles. - */ -struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font); struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font); void blf_glyph_cache_release(struct FontBLF *font); void blf_glyph_cache_clear(struct FontBLF *font); -void blf_glyph_cache_free(struct GlyphCacheBLF *gc); /** * Create (or load from cache) a fully-rendered bitmap glyph. diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 46156edbb1f..c96febd71ae 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -73,6 +73,9 @@ typedef struct GlyphCacheBLF { bool bold; bool italic; + /* Column width when printing monospaced. */ + int fixed_width; + /* and the glyphs. */ ListBase bucket[257]; @@ -207,9 +210,6 @@ typedef struct FontBLF { /* font size. */ float size; - /* Column width when printing monospaced. */ - int fixed_width; - /* max texture size. */ int tex_size_max; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 06bbd0cf521..f666976547e 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -61,7 +61,6 @@ void BLF_thumb_preview(const char *filename, int font_shrink = 4; FontBLF *font; - GlyphCacheBLF *gc; /* Create a new blender font obj and fill it with default values */ font = blf_font_new("thumb_font", filename); @@ -90,10 +89,8 @@ void BLF_thumb_preview(const char *filename, const size_t draw_str_i18n_len = strlen(draw_str_i18n); int draw_str_i18n_nbr = 0; - blf_font_size(font, (float)MAX2(font_size_min, font_size_curr), dpi); - gc = blf_glyph_cache_find(font, font->size, font->dpi); - /* There will be no matching glyph cache if blf_font_size() failed to set font size. */ - if (!gc) { + CLAMP_MIN(font_size_curr, font_size_min); + if (!blf_font_size(font, (float)font_size_curr, dpi)) { break; } diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 1801c1ee1c9..4526bc38a70 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -104,14 +104,6 @@ typedef enum DerivedMeshType { DM_TYPE_CCGDM, } DerivedMeshType; -typedef enum DMDirtyFlag { - /* dm has valid tessellated faces, but tessellated CDDATA need to be updated. */ - DM_DIRTY_TESS_CDLAYERS = 1 << 0, - - /* check this with modifier dependsOnNormals callback to see if normals need recalculation */ - DM_DIRTY_NORMALS = 1 << 1, -} DMDirtyFlag; - typedef struct DerivedMesh DerivedMesh; struct DerivedMesh { /** Private DerivedMesh data, only for internal DerivedMesh use */ @@ -120,7 +112,6 @@ struct DerivedMesh { int needsFree; /* checked on ->release, is set to 0 for cached results */ int deformedOnly; /* set by modifier stack if only deformed from original */ DerivedMeshType type; - DMDirtyFlag dirty; /** * \warning Typical access is done via #getLoopTriArray, #getNumLoopTri. @@ -139,9 +130,6 @@ struct DerivedMesh { short tangent_mask; /* which tangent layers are calculated */ - /** Calculate vert and face normals */ - void (*calcNormals)(DerivedMesh *dm); - /** Loop tessellation cache (WARNING! Only call inside threading-protected code!) */ void (*recalcLoopTri)(DerivedMesh *dm); /** accessor functions */ @@ -164,7 +152,6 @@ struct DerivedMesh { */ struct MVert *(*getVertArray)(DerivedMesh *dm); struct MEdge *(*getEdgeArray)(DerivedMesh *dm); - struct MFace *(*getTessFaceArray)(DerivedMesh *dm); struct MLoop *(*getLoopArray)(DerivedMesh *dm); struct MPoly *(*getPolyArray)(DerivedMesh *dm); @@ -173,7 +160,6 @@ struct DerivedMesh { */ void (*copyVertArray)(DerivedMesh *dm, struct MVert *r_vert); void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *r_edge); - void (*copyTessFaceArray)(DerivedMesh *dm, struct MFace *r_face); void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *r_loop); void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *r_poly); @@ -182,37 +168,18 @@ struct DerivedMesh { */ struct MVert *(*dupVertArray)(DerivedMesh *dm); struct MEdge *(*dupEdgeArray)(DerivedMesh *dm); - struct MFace *(*dupTessFaceArray)(DerivedMesh *dm); struct MLoop *(*dupLoopArray)(DerivedMesh *dm); struct MPoly *(*dupPolyArray)(DerivedMesh *dm); - /** Return a pointer to a single element of vert/edge/face custom data - * from the derived mesh (this gives a pointer to the actual data, not - * a copy) - */ - void *(*getVertData)(DerivedMesh *dm, int index, int type); - void *(*getEdgeData)(DerivedMesh *dm, int index, int type); - void *(*getTessFaceData)(DerivedMesh *dm, int index, int type); - void *(*getPolyData)(DerivedMesh *dm, int index, int type); - /** Return a pointer to the entire array of vert/edge/face custom data * from the derived mesh (this gives a pointer to the actual data, not * a copy) */ void *(*getVertDataArray)(DerivedMesh *dm, int type); void *(*getEdgeDataArray)(DerivedMesh *dm, int type); - void *(*getTessFaceDataArray)(DerivedMesh *dm, int type); void *(*getLoopDataArray)(DerivedMesh *dm, int type); void *(*getPolyDataArray)(DerivedMesh *dm, int type); - /** Retrieves the base CustomData structures for - * verts/edges/tessfaces/loops/faces. */ - CustomData *(*getVertDataLayout)(DerivedMesh *dm); - CustomData *(*getEdgeDataLayout)(DerivedMesh *dm); - CustomData *(*getTessFaceDataLayout)(DerivedMesh *dm); - CustomData *(*getLoopDataLayout)(DerivedMesh *dm); - CustomData *(*getPolyDataLayout)(DerivedMesh *dm); - /** Optional grid access for subsurf */ int (*getNumGrids)(DerivedMesh *dm); int (*getGridSize)(DerivedMesh *dm); @@ -231,11 +198,6 @@ struct DerivedMesh { /** Get smooth vertex normal, undefined if index is not valid */ void (*getVertNo)(DerivedMesh *dm, int index, float r_no[3]); - void (*getPolyNo)(DerivedMesh *dm, int index, float r_no[3]); - - /** Get a map of vertices to faces - */ - const struct MeshElemMap *(*getPolyMap)(struct Object *ob, DerivedMesh *dm); /** Release reference to the DerivedMesh. This function decides internally * if the DerivedMesh will be freed, or cached for later use. */ @@ -265,15 +227,6 @@ void DM_init(DerivedMesh *dm, * Utility function to initialize a DerivedMesh for the desired number * of vertices, edges and faces, with a layer setup copied from source */ -void DM_from_template_ex(DerivedMesh *dm, - DerivedMesh *source, - DerivedMeshType type, - int numVerts, - int numEdges, - int numTessFaces, - int numLoops, - int numPolys, - const struct CustomData_MeshMasks *mask); void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type, @@ -303,26 +256,9 @@ void DM_set_only_copy(DerivedMesh *dm, const struct CustomData_MeshMasks *mask); void DM_add_vert_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); void DM_add_edge_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); -void DM_add_tessface_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); -void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); void DM_add_poly_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); /* -------------------------------------------------------------------- */ -/** \name Custom Data Access Functions - * - * \return pointer to data from first layer which matches type - * if they return NULL for valid indices, data doesn't exist. - * \note these return pointers - any change modifies the internals of the mesh. - * \{ */ - -void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type); -void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type); -void *DM_get_tessface_data(struct DerivedMesh *dm, int index, int type); -void *DM_get_poly_data(struct DerivedMesh *dm, int index, int type); - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Custom Data Layer Access Functions * * \return pointer to first data layer which matches type (a flat array) @@ -332,7 +268,6 @@ void *DM_get_poly_data(struct DerivedMesh *dm, int index, int type); void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type); void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type); -void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type); void *DM_get_poly_data_layer(struct DerivedMesh *dm, int type); void *DM_get_loop_data_layer(struct DerivedMesh *dm, int type); @@ -354,8 +289,6 @@ void DM_copy_vert_data(struct DerivedMesh *source, */ void DM_DupPolys(DerivedMesh *source, DerivedMesh *target); -void DM_ensure_normals(DerivedMesh *dm); - /** * Ensure the array is large enough. * @@ -401,11 +334,6 @@ void makeDerivedMesh(struct Depsgraph *depsgraph, struct Object *ob, const struct CustomData_MeshMasks *dataMask); -void DM_calc_loop_tangents(DerivedMesh *dm, - bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], - int tangent_names_len); - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 0b09bfd8730..5d1b4baedfd 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -365,7 +365,6 @@ void what_does_obaction(struct Object *ob, char groupname[], const struct AnimationEvalContext *anim_eval_context); -/* for proxy */ void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto, const struct bPoseChannel *pchanfrom); /** diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 8584ce6f508..ede300b19dd 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -163,6 +163,30 @@ void BKE_armature_transform(struct bArmature *arm, const float mat[4][4], bool d /* Bounding box. */ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob); +/** + * Calculate the axis-aligned bounds of `pchan` in world-space, + * taking into account custom transform when set. + * + * `r_min` and `r_max` are expanded to fit `pchan` so the caller must initialize them + * (typically using #INIT_MINMAX). + * + * \note The bounds are calculated based on the head & tail of the bone + * or the custom object's bounds (if the bone uses a custom object). + * Visual elements such as the envelopes radius & bendy-bone spline segments are *not* included, + * making this not so useful for viewport culling. + */ +void BKE_pchan_minmax(const struct Object *ob, + const struct bPoseChannel *pchan, + float r_min[3], + float r_max[3]); +/** + * Calculate the axis aligned bounds of the pose of `ob` in world-space. + + * `r_min` and `r_max` are expanded to fit `ob->pose` so the caller must initialize them + * (typically using #INIT_MINMAX). + * + * \note This uses #BKE_pchan_minmax, see its documentation for details on bounds calculation. + */ bool BKE_pose_minmax( struct Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select); @@ -619,14 +643,6 @@ void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *object); -void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, struct Object *object); -void BKE_pose_eval_proxy_done(struct Depsgraph *depsgraph, struct Object *object); -void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, struct Object *object); - -void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, - struct Object *object, - int pchan_index); - /* -------------------------------------------------------------------- */ /** \name Deform 3D Coordinates by Armature (armature_deform.c) * \{ */ diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 6020da08f51..ff207997e79 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -40,11 +40,11 @@ struct ReportList; /* Attribute.domain */ typedef enum AttributeDomain { ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ - ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ + ATTR_DOMAIN_POINT = 0, /* Mesh, Curve or Point Cloud Point */ ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ ATTR_DOMAIN_FACE = 2, /* Mesh Face */ ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ - ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ + ATTR_DOMAIN_CURVE = 4, /* A single curve in a larger curve data-block */ ATTR_DOMAIN_INSTANCE = 5, /* Instance */ ATTR_DOMAIN_NUM diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 90f349125c9..bf773cd6d75 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -50,6 +50,9 @@ inline void convert_to_static_type(const CustomDataType data_type, const Func &f case CD_PROP_BOOL: func(bool()); break; + case CD_PROP_INT8: + func(int8_t()); + break; case CD_PROP_COLOR: func(ColorGeometry4f()); break; @@ -77,6 +80,9 @@ inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func else if (cpp_type.is<bool>()) { func(bool()); } + else if (cpp_type.is<int8_t>()) { + func(int8_t()); + } else if (cpp_type.is<ColorGeometry4f>()) { func(ColorGeometry4f()); } @@ -93,6 +99,12 @@ inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func template<typename T> T mix3(const float3 &weights, const T &v0, const T &v1, const T &v2); +template<> +inline int8_t mix3(const float3 &weights, const int8_t &v0, const int8_t &v1, const int8_t &v2) +{ + return static_cast<int8_t>(weights.x * v0 + weights.y * v1 + weights.z * v2); +} + template<> inline bool mix3(const float3 &weights, const bool &v0, const bool &v1, const bool &v2) { return (weights.x * v0 + weights.y * v1 + weights.z * v2) >= 0.5f; @@ -147,6 +159,11 @@ template<> inline bool mix2(const float factor, const bool &a, const bool &b) return ((1.0f - factor) * a + factor * b) >= 0.5f; } +template<> inline int8_t mix2(const float factor, const int8_t &a, const int8_t &b) +{ + return static_cast<int8_t>((1.0f - factor) * a + factor * b); +} + template<> inline int mix2(const float factor, const int &a, const int &b) { return static_cast<int>((1.0f - factor) * a + factor * b); @@ -364,6 +381,15 @@ template<> struct DefaultMixerStruct<bool> { using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>; }; +template<> struct DefaultMixerStruct<int8_t> { + static int8_t float_to_int8_t(const float &value) + { + return static_cast<int8_t>(value); + } + /* Store interpolated 8 bit integers in a float temporarily to increase accuracy. */ + using type = SimpleMixerWithAccumulationType<int8_t, float, float_to_int8_t>; +}; + template<typename T> struct DefaultPropatationMixerStruct { /* Use void by default. This can be checked for in `if constexpr` statements. */ using type = typename DefaultMixerStruct<T>::type; diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index d1f31e0d2f5..1ba887903c8 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -31,15 +31,15 @@ extern "C" { */ /* Blender major and minor version. */ -#define BLENDER_VERSION 301 +#define BLENDER_VERSION 302 /* Blender patch version for bugfix releases. */ #define BLENDER_VERSION_PATCH 0 /** Blender release cycle stage: alpha/beta/rc/release. */ -#define BLENDER_VERSION_CYCLE beta +#define BLENDER_VERSION_CYCLE alpha /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 6 +#define BLENDER_FILE_SUBVERSION 3 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index bce15349880..467d74b17da 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -130,9 +130,9 @@ bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob); /** - * Same as #BKE_collection_object_add, but uncondionnaly adds the object to the given collection. + * Same as #BKE_collection_object_add, but unconditionally adds the object to the given collection. * - * NOTE: required in certain cases, like do-versionning or complex ID management tasks. + * NOTE: required in certain cases, like do-versioning or complex ID management tasks. */ bool BKE_collection_object_add_notest(struct Main *bmain, struct Collection *collection, diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 55e5cd0a149..2da79e27576 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -278,18 +278,6 @@ bool BKE_constraint_apply_and_remove_for_pose(struct Depsgraph *depsgraph, void BKE_constraint_panel_expand(struct bConstraint *con); -/* Constraints + Proxies function prototypes */ - -/** - * Rescue all constraints tagged as being #CONSTRAINT_PROXY_LOCAL - * (i.e. added to bone that's proxy-synced in this file). - */ -void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *src); -/** - * Returns if the owner of the constraint is proxy-protected. - */ -bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan); - /* Constraint Evaluation function prototypes */ /** diff --git a/source/blender/blenkernel/BKE_curves.h b/source/blender/blenkernel/BKE_curves.h new file mode 100644 index 00000000000..99839b20121 --- /dev/null +++ b/source/blender/blenkernel/BKE_curves.h @@ -0,0 +1,68 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +/** \file + * \ingroup bke + * \brief Low-level operations for curves. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct BoundBox; +struct CustomDataLayer; +struct Depsgraph; +struct Curves; +struct Main; +struct Object; +struct Scene; + +void *BKE_curves_add(struct Main *bmain, const char *name); + +struct BoundBox *BKE_curves_boundbox_get(struct Object *ob); + +void BKE_curves_update_customdata_pointers(struct Curves *curves); +bool BKE_curves_customdata_required(struct Curves *curves, struct CustomDataLayer *layer); + +/* Depsgraph */ + +struct Curves *BKE_curves_new_for_eval(const struct Curves *curves_src, + int totpoint, + int totcurve); +struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src, bool reference); + +void BKE_curves_data_update(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *object); + +/* Draw Cache */ + +enum { + BKE_CURVES_BATCH_DIRTY_ALL = 0, +}; + +void BKE_curves_batch_cache_dirty_tag(struct Curves *curves, int mode); +void BKE_curves_batch_cache_free(struct Curves *curves); + +extern void (*BKE_curves_batch_cache_dirty_tag_cb)(struct Curves *curves, int mode); +extern void (*BKE_curves_batch_cache_free_cb)(struct Curves *curves); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 885d0c2fd90..fd8996993c0 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -48,6 +48,7 @@ struct bGPDlayer; struct bGPDlayer_Mask; struct bGPDstroke; struct bGPdata; +struct GPencilUpdateCache; #define GPENCIL_SIMPLIFY(scene) (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE) #define GPENCIL_SIMPLIFY_ONPLAY(playing) \ @@ -175,10 +176,28 @@ struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src, b struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src, bool dup_frames, bool dup_strokes); + +/** + * Make a copy of a given gpencil data settings. + */ +void BKE_gpencil_data_copy_settings(const struct bGPdata *gpd_src, struct bGPdata *gpd_dst); + /** * Make a copy of a given gpencil layer settings. */ void BKE_gpencil_layer_copy_settings(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst); + +/** + * Make a copy of a given gpencil frame settings. + */ +void BKE_gpencil_frame_copy_settings(const struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst); + +/** + * Make a copy of a given gpencil stroke settings. + */ +void BKE_gpencil_stroke_copy_settings(const struct bGPDstroke *gpf_src, + struct bGPDstroke *gpf_dst); + /** * Make a copy of strokes between gpencil frames. * \param gpf_src: Source grease pencil frame @@ -675,6 +694,9 @@ extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd); */ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig, const struct bGPDframe *gpf_eval); + +void BKE_gpencil_layer_original_pointers_update(const struct bGPDlayer *gpl_orig, + const struct bGPDlayer *gpl_eval); /** * Update pointers of eval data to original data to keep references. * \param ob_orig: Original grease pencil object @@ -683,6 +705,14 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig void BKE_gpencil_update_orig_pointers(const struct Object *ob_orig, const struct Object *ob_eval); /** + * Update pointers of eval data to original data to keep references. + * \param gpd_orig: Original grease pencil data + * \param gpd_eval: Evaluated grease pencil data + */ +void BKE_gpencil_data_update_orig_pointers(const struct bGPdata *gpd_orig, + const struct bGPdata *gpd_eval); + +/** * Get parent matrix, including layer parenting. * \param depsgraph: Depsgraph * \param obact: Grease pencil object @@ -711,6 +741,10 @@ int BKE_gpencil_material_find_index_by_name_prefix(struct Object *ob, const char void BKE_gpencil_blend_read_data(struct BlendDataReader *reader, struct bGPdata *gpd); +bool BKE_gpencil_can_avoid_full_copy_on_write(const struct Depsgraph *depsgraph, struct bGPdata *gpd); + +void BKE_gpencil_update_on_write(struct bGPdata *gpd_orig, struct bGPdata *gpd_eval); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_gpencil_update_cache.h b/source/blender/blenkernel/BKE_gpencil_update_cache.h new file mode 100644 index 00000000000..3ac78267922 --- /dev/null +++ b/source/blender/blenkernel/BKE_gpencil_update_cache.h @@ -0,0 +1,152 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2022, Blender Foundation + * This is a new part of Blender + */ + +#pragma once + +/** \file + * \ingroup bke + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_sys_types.h" /* for bool */ + +struct DLRBT_Tree; +struct bGPdata; +struct bGPDlayer; +struct bGPDframe; +struct bGPDstroke; +struct GPencilUpdateCache; + +/* GPencilUpdateCache.flag */ +typedef enum eGPUpdateCacheNodeFlag { + /* Node is a placeholder (e.g. when only an index is needed). */ + GP_UPDATE_NODE_NO_COPY = 0, + /* Copy only element, not the content. */ + GP_UPDATE_NODE_LIGHT_COPY = 1, + /* Copy the element as well as all of its content. */ + GP_UPDATE_NODE_FULL_COPY = 2, +} eGPUpdateCacheNodeFlag; + +/** + * Cache for what needs to be updated after bGPdata was modified. + * + * Every node holds information about one element that was changed: + * - the index of where that element is in the linked-list + * - the pointer to the original element in bGPdata + * Additionally, nodes also hold other nodes that are one "level" below them. + * E.g. a node that represents a change on a bGPDframe could contain a set of + * nodes that represent a change on bGPDstrokes. + * These nodes are stored in a red-black tree so that they are sorted by their + * index to make sure they can be processed in the correct order. + */ +typedef struct GPencilUpdateCache { + /* Mapping from index to a GPencilUpdateCache struct. */ + struct DLRBT_Tree *children; + /* eGPUpdateCacheNodeFlag */ + int flag; + /* Index of the element in the linked-list. */ + int index; + /* Pointer to one of bGPdata, bGPDLayer, bGPDFrame, bGPDStroke. */ + void *data; +} GPencilUpdateCache; + +/* Node structure in the DLRBT_Tree for GPencilUpdateCache mapping. */ +typedef struct GPencilUpdateCacheNode { + /* DLRB tree capabilities. */ + struct GPencilUpdateCacheNode *next, *prev; + struct GPencilUpdateCacheNode *left, *right; + struct GPencilUpdateCacheNode *parent; + char tree_col; + + char _pad[7]; + /* Content of DLRB tree node. */ + GPencilUpdateCache *cache; +} GPencilUpdateCacheNode; + +/** + * Callback that is called in BKE_gpencil_traverse_update_cache at each level. If the callback + * returns true, then the children will not be iterated over and instead continue. + * \param cache: The cache at this level. + * \param user_data: Pointer to the user_data passed to BKE_gpencil_traverse_update_cache. + * \returns true, if iterating over the children of \a cache should be skipped, false if not. + */ +typedef bool (*GPencilUpdateCacheIter_Cb)(GPencilUpdateCache *cache, void *user_data); + +typedef struct GPencilUpdateCacheTraverseSettings { + /* Callbacks for the update cache traversal. Callback with index 0 is for layers, 1 for frames + * and 2 for strokes. */ + GPencilUpdateCacheIter_Cb update_cache_cb[3]; +} GPencilUpdateCacheTraverseSettings; + +/** + * Allocates a new GPencilUpdateCache and populates it. + * \param data: A data pointer to populate the initial cache with. + * \param full_copy: If true, will mark this update cache as a full copy + * (GP_UPDATE_NODE_FULL_COPY). If false, it will be marked as a struct copy + * (GP_UPDATE_NODE_LIGHT_COPY). + */ +GPencilUpdateCache *BKE_gpencil_create_update_cache(void *data, bool full_copy); + +/** + * Traverses an update cache and executes callbacks at each level. + * \param cache: The update cache to traverse. + * \param ts: The traversal settings. This stores the callbacks that are called at each level. + * \param user_data: Custom data passed to each callback. + */ +void BKE_gpencil_traverse_update_cache(GPencilUpdateCache *cache, + GPencilUpdateCacheTraverseSettings *ts, + void *user_data); + +/** + * Tags an element (bGPdata, bGPDlayer, bGPDframe, or bGPDstroke) and all of its containing data to + * be updated in the next update-on-write operation. + * + * The function assumes that when a parameter is NULL all of the following parameters are NULL too. + * E.g. in order to tag a layer (gpl), the parameters would *have* to be (gpd, gpl, NULL, NULL). + */ +void BKE_gpencil_tag_full_update(struct bGPdata *gpd, + struct bGPDlayer *gpl, + struct bGPDframe *gpf, + struct bGPDstroke *gps); + +/** + * Tags an element (bGPdata, bGPDlayer, bGPDframe, or bGPDstroke) to be updated in the next + * update-on-write operation. This function will not update any of the containing data, only the + * struct itself. + * + * The function assumes that when a parameter is NULL all of the following parameters are NULL too. + * E.g. in order to tag a layer (gpl), the parameters would *have* to be (gpd, gpl, NULL, NULL). + */ +void BKE_gpencil_tag_light_update(struct bGPdata *gpd, + struct bGPDlayer *gpl, + struct bGPDframe *gpf, + struct bGPDstroke *gps); + +/** + * Frees the GPencilUpdateCache on the gpd->runtime. This will not free the data that the cache + * node might point to. It assumes that the cache does not own the data. + */ +void BKE_gpencil_free_update_cache(struct bGPdata *gpd); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_hair.h b/source/blender/blenkernel/BKE_hair.h deleted file mode 100644 index 403e461a9dc..00000000000 --- a/source/blender/blenkernel/BKE_hair.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -/** \file - * \ingroup bke - * \brief General operations for hairs. - */ -#ifdef __cplusplus -extern "C" { -#endif - -struct BoundBox; -struct CustomDataLayer; -struct Depsgraph; -struct Hair; -struct Main; -struct Object; -struct Scene; - -void *BKE_hair_add(struct Main *bmain, const char *name); - -struct BoundBox *BKE_hair_boundbox_get(struct Object *ob); - -void BKE_hair_update_customdata_pointers(struct Hair *hair); -bool BKE_hair_customdata_required(struct Hair *hair, struct CustomDataLayer *layer); - -/* Depsgraph */ - -struct Hair *BKE_hair_new_for_eval(const struct Hair *hair_src, int totpoint, int totcurve); -struct Hair *BKE_hair_copy_for_eval(struct Hair *hair_src, bool reference); - -void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *object); - -/* Draw Cache */ - -enum { - BKE_HAIR_BATCH_DIRTY_ALL = 0, -}; - -void BKE_hair_batch_cache_dirty_tag(struct Hair *hair, int mode); -void BKE_hair_batch_cache_free(struct Hair *hair); - -extern void (*BKE_hair_batch_cache_dirty_tag_cb)(struct Hair *hair, int mode); -extern void (*BKE_hair_batch_cache_free_cb)(struct Hair *hair); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h index df50f773a46..e9e5b183e4a 100644 --- a/source/blender/blenkernel/BKE_idtype.h +++ b/source/blender/blenkernel/BKE_idtype.h @@ -278,7 +278,7 @@ extern IDTypeInfo IDType_ID_PC; extern IDTypeInfo IDType_ID_CF; extern IDTypeInfo IDType_ID_WS; extern IDTypeInfo IDType_ID_LP; -extern IDTypeInfo IDType_ID_HA; +extern IDTypeInfo IDType_ID_CV; extern IDTypeInfo IDType_ID_PT; extern IDTypeInfo IDType_ID_VO; extern IDTypeInfo IDType_ID_SIM; diff --git a/source/blender/blenkernel/BKE_image_partial_update.hh b/source/blender/blenkernel/BKE_image_partial_update.hh index ca7c4f40593..0fc05809bbd 100644 --- a/source/blender/blenkernel/BKE_image_partial_update.hh +++ b/source/blender/blenkernel/BKE_image_partial_update.hh @@ -23,8 +23,8 @@ * image that are changed. These areas are organized in chunks. Changes that happen over time are * organized in changesets. * - * A common usecase is to update GPUTexture for drawing where only that part is uploaded that only - * changed. + * A common use case is to update #GPUTexture for drawing where only that part is uploaded that + * only changed. */ #pragma once diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index ebd35cad965..daf13590ca2 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -376,10 +376,6 @@ enum { /** Clear asset data (in case the ID can actually be made local, in copy case asset data is never * copied over). */ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR = 1 << 3, - - /* Special type-specific options. */ - /** For Objects, do not clear the proxy pointers while making the data-block local. */ - LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16, }; /** diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 30e75259967..e24f8dd8927 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -100,6 +100,9 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain, * main. You can add more local IDs to be remapped to use new overriding ones by setting their * LIB_TAG_DOIT tag. * + * \param owner_library: the library in which the overrides should be created. Besides versioning + * and resync code path, this should always be NULL (i.e. the local .blend file). + * * \param reference_library: the library from which the linked data being overridden come from * (i.e. the library of the linked reference ID). * @@ -109,7 +112,8 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain, * \return \a true on success, \a false otherwise. */ bool BKE_lib_override_library_create_from_tag(struct Main *bmain, - const struct Library *reference_library, + struct Library *owner_library, + const struct ID *id_root_reference, bool do_no_main); /** * Advanced 'smart' function to create fully functional overrides. @@ -122,16 +126,24 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain, * * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in * which case \a scene's master collection children hierarchy is used instead). + * + * \param owner_library: the library in which the overrides should be created. Besides versioning + * and resync code path, this should always be NULL (i.e. the local .blend file). + * * \param id_root: The root ID to create an override from. + * * \param id_reference: Some reference ID used to do some post-processing after overrides have been * created, may be NULL. Typically, the Empty object instantiating the linked collection we * override, currently. + * * \param r_id_root_override: if not NULL, the override generated for the given \a id_root. + * * \return true if override was successfully created. */ bool BKE_lib_override_library_create(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, + struct Library *owner_library, struct ID *id_root, struct ID *id_reference, struct ID **r_id_root_override); @@ -160,6 +172,15 @@ bool BKE_lib_override_library_proxy_convert(struct Main *bmain, */ void BKE_lib_override_library_main_proxy_convert(struct Main *bmain, struct BlendFileReadReport *reports); + +/** + * Find and set the 'hierarchy root' ID pointer of all library overrides in given `bmain`. + * + * NOTE: Cannot be called from `do_versions_after_linking` as this code needs a single complete + * Main database, not a split-by-libraries one. + */ +void BKE_lib_override_library_main_hierarchy_root_ensure(struct Main *bmain); + /** * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked * data, from an existing override hierarchy. diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index d853cb16b13..dd2e2a2f8e5 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -63,7 +63,7 @@ enum { /** * That ID is not really used by its owner, it's just an internal hint/helper. - * This addresses Their Highest Ugliness the 'from' pointers: Object->from_proxy and Key->from. + * This marks the 'from' pointers issue, like Key->from. * How to handle that kind of cases totally depends on what caller code is doing... */ IDWALK_CB_LOOPBACK = (1 << 4), @@ -135,7 +135,6 @@ enum { /** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */ IDWALK_IGNORE_EMBEDDED_ID = (1 << 3), - IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */ /** Also process internal ID pointers like `ID.newid` or `ID.orig_id`. * WARNING: Dangerous, use with caution. */ IDWALK_DO_INTERNAL_RUNTIME_POINTERS = (1 << 9), diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index cc970342fbb..f14cd75c5c6 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -68,15 +68,6 @@ enum { * and can cause crashes very easily! */ ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3, - /** - * Do not consider proxy/_group pointers of local objects as indirect usages... - * Our oh-so-beloved proxies again... - * Do not consider data used by local proxy object as indirect usage. - * This is needed e.g. in reload scenario, - * since we have to ensure remapping of Armature data of local proxy - * is also performed. Usual nightmare... - */ - ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4, /** Do not remap library override pointers. */ ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5, /** Don't touch the user count (use for low level actions such as swapping pointers). */ diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 4c6eb31db4b..e4f94110eb1 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -182,7 +182,11 @@ typedef struct Main { ListBase linestyles; ListBase cachefiles; ListBase workspaces; - ListBase hairs; + /** + * \note The name `hair_curves` is chosen to be different than `curves`, + * but they are generic curve data-blocks, not just for hair. + */ + ListBase hair_curves; ListBase pointclouds; ListBase volumes; ListBase simulations; diff --git a/source/blender/blenkernel/BKE_mesh_fair.h b/source/blender/blenkernel/BKE_mesh_fair.h index c4c1af054f0..2884de6d5c1 100644 --- a/source/blender/blenkernel/BKE_mesh_fair.h +++ b/source/blender/blenkernel/BKE_mesh_fair.h @@ -12,15 +12,14 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": - * https://github.com/fedackb/mesh-fairing. */ #pragma once /** \file * \ingroup bke + * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": + * https://github.com/fedackb/mesh-fairing. */ #include "BLI_utildefines.h" diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 910b13b9b95..a05ed67063a 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -245,10 +245,6 @@ typedef struct ModifierTypeInfo { const struct ModifierEvalContext *ctx, struct Mesh *mesh); - struct Hair *(*modifyHair)(struct ModifierData *md, - const struct ModifierEvalContext *ctx, - struct Hair *hair); - /** * The modifier has to change the geometry set in-place. The geometry set can contain zero or * more geometry components. This callback can be used by modifiers that don't work on any diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 16d8ba2e6dd..359a5662a13 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -274,6 +274,9 @@ typedef struct bNodeType { char *label, int maxlen); + /** Optional override for node class, used for drawing node header. */ + int (*ui_class)(const struct bNode *node); + /** Called when the node is updated in the editor. */ void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node); /** Check and update if internal ID data has changed. */ @@ -1291,6 +1294,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define CMP_NODE_POSTERIZE 327 #define CMP_NODE_CONVERT_COLOR_SPACE 328 #define CMP_NODE_SCENE_TIME 329 +#define CMP_NODE_SEPARATE_XYZ 330 +#define CMP_NODE_COMBINE_XYZ 331 /* channel toggles */ #define CMP_CHAN_RGB 1 @@ -1298,12 +1303,13 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i /* filter types */ #define CMP_FILT_SOFT 0 -#define CMP_FILT_SHARP 1 +#define CMP_FILT_SHARP_BOX 1 #define CMP_FILT_LAPLACE 2 #define CMP_FILT_SOBEL 3 #define CMP_FILT_PREWITT 4 #define CMP_FILT_KIRSCH 5 #define CMP_FILT_SHADOW 6 +#define CMP_FILT_SHARP_DIAMOND 7 /* scale node type, in custom1 */ #define CMP_SCALE_RELATIVE 0 diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 99758f4ad78..e8ff0903b04 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -144,18 +144,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr void BKE_object_free_modifiers(struct Object *ob, int flag); void BKE_object_free_shaderfx(struct Object *ob, int flag); -/** - * Proxy rule: - * - `lib_object->proxy_from` == the one we borrow from, set temporally while object_update. - * - `local_object->proxy` == pointer to library object, saved in files and read. - * - `local_object->proxy_group` == pointer to collection dupli-object, saved in files and read. - */ -void BKE_object_make_proxy(struct Main *bmain, - struct Object *ob, - struct Object *target, - struct Object *cob); -void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); - bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest); /** * Actual check for internal data, not context or flags. @@ -444,8 +432,7 @@ void BKE_object_eval_constraints(struct Depsgraph *depsgraph, struct Object *ob); void BKE_object_eval_transform_final(struct Depsgraph *depsgraph, struct Object *ob); -bool BKE_object_eval_proxy_copy(struct Depsgraph *depsgraph, struct Object *object); -void BKE_object_eval_uber_transform(struct Depsgraph *depsgraph, struct Object *ob); +void BKE_object_eval_uber_transform(struct Depsgraph *depsgraph, struct Object *object); void BKE_object_eval_uber_data(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); @@ -486,12 +473,6 @@ void BKE_object_handle_data_update(struct Depsgraph *depsgraph, */ void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); /** - * Proxy rule: - * - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here. - * - local_object->proxy == pointer to library object, saved in files and read. - * - * Function below is polluted with proxy exceptions, cleanup will follow! - * * The main object update call, for object matrix, constraints, keys and #DispList (modifiers) * requires flags to be set! * @@ -501,8 +482,7 @@ void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, void BKE_object_handle_update_ex(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, - struct RigidBodyWorld *rbw, - bool do_proxy_update); + struct RigidBodyWorld *rbw); void BKE_object_sculpt_data_create(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 804331a3412..b5e60da540e 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -13,11 +13,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2007 by Janne Karhu. - * All rights reserved. - * Adaptive time step - * Classical SPH - * Copyright 2011-2012 AutoCRC + * Copyright 2007 Janne Karhu. All rights reserved. + * 2011-2012 AutoCRC (adaptive time step, Classical SPH). */ #pragma once diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 220d4673075..1483466061f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -119,6 +119,7 @@ set(SRC intern/crazyspace.c intern/cryptomatte.cc intern/curve.cc + intern/curves.cc intern/curve_bevel.c intern/curve_convert.c intern/curve_decimate.c @@ -156,7 +157,7 @@ set(SRC intern/gpencil_curve.c intern/gpencil_geom.cc intern/gpencil_modifier.c - intern/hair.cc + intern/gpencil_update_cache.c intern/icons.cc intern/icons_rasterize.c intern/idprop.c @@ -182,6 +183,7 @@ set(SRC intern/lib_id_eval.c intern/lib_id_remapper.cc intern/lib_override.c + intern/lib_override_proxy_conversion.c intern/lib_query.c intern/lib_remap.c intern/library.c @@ -355,6 +357,7 @@ set(SRC BKE_cryptomatte.h BKE_cryptomatte.hh BKE_curve.h + BKE_curves.h BKE_curve_to_mesh.hh BKE_curveprofile.h BKE_customdata.h @@ -383,7 +386,7 @@ set(SRC BKE_gpencil_curve.h BKE_gpencil_geom.h BKE_gpencil_modifier.h - BKE_hair.h + BKE_gpencil_update_cache.h BKE_icons.h BKE_idprop.h BKE_idprop.hh @@ -719,10 +722,6 @@ if(WITH_FFTW3) add_definitions(-DFFTW3=1) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index b9372ceed08..2e779d6fad7 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -127,30 +127,6 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm) return medge; } -static MFace *dm_getTessFaceArray(DerivedMesh *dm) -{ - MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE); - - if (!mface) { - int numTessFaces = dm->getNumTessFaces(dm); - - if (!numTessFaces) { - /* Do not add layer if there's no elements in it, this leads to issues later when - * this layer is needed with non-zero size, but currently CD stuff does not check - * for requested layer size on creation and just returns layer which was previously - * added (sergey) */ - return nullptr; - } - - mface = (MFace *)CustomData_add_layer( - &dm->faceData, CD_MFACE, CD_CALLOC, nullptr, numTessFaces); - CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY); - dm->copyTessFaceArray(dm, mface); - } - - return mface; -} - static MLoop *dm_getLoopArray(DerivedMesh *dm) { MLoop *mloop = (MLoop *)CustomData_get_layer(&dm->loopData, CD_MLOOP); @@ -203,18 +179,6 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm) return tmp; } -static MFace *dm_dupFaceArray(DerivedMesh *dm) -{ - MFace *tmp = (MFace *)MEM_malloc_arrayN( - dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp"); - - if (tmp) { - dm->copyTessFaceArray(dm, tmp); - } - - return tmp; -} - static MLoop *dm_dupLoopArray(DerivedMesh *dm) { MLoop *tmp = (MLoop *)MEM_malloc_arrayN( @@ -270,42 +234,15 @@ static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm) return looptri; } -static CustomData *dm_getVertCData(DerivedMesh *dm) -{ - return &dm->vertData; -} - -static CustomData *dm_getEdgeCData(DerivedMesh *dm) -{ - return &dm->edgeData; -} - -static CustomData *dm_getTessFaceCData(DerivedMesh *dm) -{ - return &dm->faceData; -} - -static CustomData *dm_getLoopCData(DerivedMesh *dm) -{ - return &dm->loopData; -} - -static CustomData *dm_getPolyCData(DerivedMesh *dm) -{ - return &dm->polyData; -} - void DM_init_funcs(DerivedMesh *dm) { /* default function implementations */ dm->getVertArray = dm_getVertArray; dm->getEdgeArray = dm_getEdgeArray; - dm->getTessFaceArray = dm_getTessFaceArray; dm->getLoopArray = dm_getLoopArray; dm->getPolyArray = dm_getPolyArray; dm->dupVertArray = dm_dupVertArray; dm->dupEdgeArray = dm_dupEdgeArray; - dm->dupTessFaceArray = dm_dupFaceArray; dm->dupLoopArray = dm_dupLoopArray; dm->dupPolyArray = dm_dupPolyArray; @@ -314,19 +251,8 @@ void DM_init_funcs(DerivedMesh *dm) /* subtypes handle getting actual data */ dm->getNumLoopTri = dm_getNumLoopTri; - dm->getVertDataLayout = dm_getVertCData; - dm->getEdgeDataLayout = dm_getEdgeCData; - dm->getTessFaceDataLayout = dm_getTessFaceCData; - dm->getLoopDataLayout = dm_getLoopCData; - dm->getPolyDataLayout = dm_getPolyCData; - - dm->getVertData = DM_get_vert_data; - dm->getEdgeData = DM_get_edge_data; - dm->getTessFaceData = DM_get_tessface_data; - dm->getPolyData = DM_get_poly_data; dm->getVertDataArray = DM_get_vert_data_layer; dm->getEdgeDataArray = DM_get_edge_data_layer; - dm->getTessFaceDataArray = DM_get_tessface_data_layer; dm->getPolyDataArray = DM_get_poly_data_layer; dm->getLoopDataArray = DM_get_loop_data_layer; } @@ -349,7 +275,6 @@ void DM_init(DerivedMesh *dm, DM_init_funcs(dm); dm->needsFree = 1; - dm->dirty = (DMDirtyFlag)0; /* Don't use #CustomData_reset because we don't want to touch custom-data. */ copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); @@ -359,16 +284,16 @@ void DM_init(DerivedMesh *dm, copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1); } -void DM_from_template_ex(DerivedMesh *dm, - DerivedMesh *source, - DerivedMeshType type, - int numVerts, - int numEdges, - int numTessFaces, - int numLoops, - int numPolys, - const CustomData_MeshMasks *mask) +void DM_from_template(DerivedMesh *dm, + DerivedMesh *source, + DerivedMeshType type, + int numVerts, + int numEdges, + int numTessFaces, + int numLoops, + int numPolys) { + const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_CALLOC, numVerts); CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_CALLOC, numEdges); CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_CALLOC, numTessFaces); @@ -387,26 +312,6 @@ void DM_from_template_ex(DerivedMesh *dm, DM_init_funcs(dm); dm->needsFree = 1; - dm->dirty = (DMDirtyFlag)0; -} -void DM_from_template(DerivedMesh *dm, - DerivedMesh *source, - DerivedMeshType type, - int numVerts, - int numEdges, - int numTessFaces, - int numLoops, - int numPolys) -{ - DM_from_template_ex(dm, - source, - type, - numVerts, - numEdges, - numTessFaces, - numLoops, - numPolys, - &CD_MASK_DERIVEDMESH); } bool DM_release(DerivedMesh *dm) @@ -464,14 +369,6 @@ void DM_DupPolys(DerivedMesh *source, DerivedMesh *target) } } -void DM_ensure_normals(DerivedMesh *dm) -{ - if (dm->dirty & DM_DIRTY_NORMALS) { - dm->calcNormals(dm); - } - BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0); -} - void DM_ensure_looptri_data(DerivedMesh *dm) { const unsigned int totpoly = dm->numPolyData; @@ -524,7 +421,7 @@ void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask) * see replies to r50969, Campbell */ #if 0 CustomData_set_only_copy(&dm->loopData, mask->lmask); - CustomData_set_only_copy(&dm->polyData, mask->pmask); + Custom(&dm->polyData, mask->pmask); #endif } @@ -552,45 +449,11 @@ void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void * CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData); } -void DM_add_tessface_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) -{ - CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData); -} - -void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) -{ - CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData); -} - void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) { CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData); } -void *DM_get_vert_data(DerivedMesh *dm, int index, int type) -{ - BLI_assert(index >= 0 && index < dm->getNumVerts(dm)); - return CustomData_get(&dm->vertData, index, type); -} - -void *DM_get_edge_data(DerivedMesh *dm, int index, int type) -{ - BLI_assert(index >= 0 && index < dm->getNumEdges(dm)); - return CustomData_get(&dm->edgeData, index, type); -} - -void *DM_get_tessface_data(DerivedMesh *dm, int index, int type) -{ - BLI_assert(index >= 0 && index < dm->getNumTessFaces(dm)); - return CustomData_get(&dm->faceData, index, type); -} - -void *DM_get_poly_data(DerivedMesh *dm, int index, int type) -{ - BLI_assert(index >= 0 && index < dm->getNumPolys(dm)); - return CustomData_get(&dm->polyData, index, type); -} - void *DM_get_vert_data_layer(DerivedMesh *dm, int type) { if (type == CD_MVERT) { @@ -609,15 +472,6 @@ void *DM_get_edge_data_layer(DerivedMesh *dm, int type) return CustomData_get_layer(&dm->edgeData, type); } -void *DM_get_tessface_data_layer(DerivedMesh *dm, int type) -{ - if (type == CD_MFACE) { - return dm->getTessFaceArray(dm); - } - - return CustomData_get_layer(&dm->faceData, type); -} - void *DM_get_poly_data_layer(DerivedMesh *dm, int type) { return CustomData_get_layer(&dm->polyData, type); @@ -2137,32 +1991,6 @@ void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int to } } -void DM_calc_loop_tangents(DerivedMesh *dm, - bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], - int tangent_names_len) -{ - BKE_mesh_calc_loop_tangent_ex( - dm->getVertArray(dm), - dm->getPolyArray(dm), - dm->getNumPolys(dm), - dm->getLoopArray(dm), - dm->getLoopTriArray(dm), - dm->getNumLoopTri(dm), - &dm->loopData, - calc_active_tangent, - tangent_names, - tangent_names_len, - (const float(*)[3])CustomData_get_layer(&dm->vertData, CD_NORMAL), - (const float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL), - (const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL), - (const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */ - /* result */ - &dm->loopData, - dm->getNumLoops(dm), - &dm->tangent_mask); -} - static void mesh_init_origspace(Mesh *mesh) { const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index fde42304185..8426f6f4676 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1956,30 +1956,15 @@ void BKE_pose_blend_read_lib(BlendLibReader *reader, Object *ob, bPose *pose) return; } - /* always rebuild to match proxy or lib changes, but on Undo */ + /* Always rebuild to match library changes, except on Undo. */ bool rebuild = false; if (!BLO_read_lib_is_undo(reader)) { - if (ob->proxy || ob->id.lib != arm->id.lib) { + if (ob->id.lib != arm->id.lib) { rebuild = true; } } - if (ob->proxy) { - /* sync proxy layer */ - if (pose->proxy_layer) { - arm->layer = pose->proxy_layer; - } - - /* sync proxy active bone */ - if (pose->proxy_act_bone[0]) { - Bone *bone = BKE_armature_find_bone_name(arm, pose->proxy_act_bone); - if (bone) { - arm->act_bone = bone; - } - } - } - LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { BKE_constraint_blend_read_lib(reader, (ID *)ob, &pchan->constraints); diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 42b72a7cd66..1c0b465d202 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -1284,8 +1284,8 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use /* cache files */ ANIMDATA_IDS_CB(bmain->cachefiles.first); - /* hairs */ - ANIMDATA_IDS_CB(bmain->hairs.first); + /* Hair Curves. */ + ANIMDATA_IDS_CB(bmain->hair_curves.first); /* pointclouds */ ANIMDATA_IDS_CB(bmain->pointclouds.first); @@ -1413,8 +1413,8 @@ void BKE_animdata_fix_paths_rename_all_ex(Main *bmain, /* cache files */ RENAMEFIX_ANIM_IDS(bmain->cachefiles.first); - /* hairs */ - RENAMEFIX_ANIM_IDS(bmain->hairs.first); + /* Hair Curves. */ + RENAMEFIX_ANIM_IDS(bmain->hair_curves.first); /* pointclouds */ RENAMEFIX_ANIM_IDS(bmain->pointclouds.first); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index b5ea68aaadc..c45856adbda 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -3382,8 +3382,8 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float /* cache files */ EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM); - /* hairs */ - EVAL_ANIM_IDS(main->hairs.first, ADT_RECALC_ANIM); + /* Hair Curves. */ + EVAL_ANIM_IDS(main->hair_curves.first, ADT_RECALC_ANIM); /* pointclouds */ EVAL_ANIM_IDS(main->pointclouds.first, ADT_RECALC_ANIM); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 5704ef6e42f..1a9f0a9130d 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -69,8 +69,6 @@ #include "CLG_log.h" -static CLG_LogRef LOG = {"bke.armature"}; - /* -------------------------------------------------------------------- */ /** \name Prototypes * \{ */ @@ -2296,161 +2294,6 @@ void BKE_armature_where_is(bArmature *arm) /** \name Pose Rebuild * \{ */ -/* if bone layer is protected, copy the data from from->pose - * when used with linked libraries this copies from the linked pose into the local pose */ -static void pose_proxy_sync(Object *ob, Object *from, int layer_protected) -{ - bPose *pose = ob->pose, *frompose = from->pose; - bPoseChannel *pchan, *pchanp; - bConstraint *con; - int error = 0; - - if (frompose == NULL) { - return; - } - - /* in some cases when rigs change, we can't synchronize - * to avoid crashing check for possible errors here */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->layer & layer_protected) { - if (BKE_pose_channel_find_name(frompose, pchan->name) == NULL) { - CLOG_ERROR(&LOG, - "failed to sync proxy armature because '%s' is missing pose channel '%s'", - from->id.name, - pchan->name); - error = 1; - } - } - } - - if (error) { - return; - } - - /* clear all transformation values from library */ - BKE_pose_rest(frompose, false); - - /* copy over all of the proxy's bone groups */ - /* TODO: for later - * - implement 'local' bone groups as for constraints - * NOTE: this isn't trivial, as bones reference groups by index not by pointer, - * so syncing things correctly needs careful attention */ - BLI_freelistN(&pose->agroups); - BLI_duplicatelist(&pose->agroups, &frompose->agroups); - pose->active_group = frompose->active_group; - - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - pchanp = BKE_pose_channel_find_name(frompose, pchan->name); - - if (UNLIKELY(pchanp == NULL)) { - /* happens for proxies that become invalid because of a missing link - * for regular cases it shouldn't happen at all */ - } - else if (pchan->bone->layer & layer_protected) { - ListBase proxylocal_constraints = {NULL, NULL}; - bPoseChannel pchanw; - - /* copy posechannel to temp, but restore important pointers */ - pchanw = *pchanp; - pchanw.bone = pchan->bone; - pchanw.prev = pchan->prev; - pchanw.next = pchan->next; - pchanw.parent = pchan->parent; - pchanw.child = pchan->child; - pchanw.custom_tx = pchan->custom_tx; - pchanw.bbone_prev = pchan->bbone_prev; - pchanw.bbone_next = pchan->bbone_next; - - pchanw.mpath = pchan->mpath; - pchan->mpath = NULL; - - /* Reset runtime data, we don't want to share that with the proxy. */ - BKE_pose_channel_runtime_reset_on_copy(&pchanw.runtime); - - /* this is freed so copy a copy, else undo crashes */ - if (pchanw.prop) { - pchanw.prop = IDP_CopyProperty(pchanw.prop); - - /* use the values from the existing props */ - if (pchan->prop) { - IDP_SyncGroupValues(pchanw.prop, pchan->prop); - } - } - - /* Constraints - proxy constraints are flushed... local ones are added after - * 1: extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints. - * 2: copy proxy-pchan's constraints on-to new. - * 3: add extracted local constraints back on top. - * - * Note for BKE_constraints_copy: - * When copying constraints, disable 'do_extern' otherwise - * we get the libs direct linked in this blend. - */ - BKE_constraints_proxylocal_extract(&proxylocal_constraints, &pchan->constraints); - BKE_constraints_copy(&pchanw.constraints, &pchanp->constraints, false); - BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints); - - /* constraints - set target ob pointer to own object */ - for (con = pchanw.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); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == from) { - ct->tar = ob; - } - } - - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - - /* free stuff from current channel */ - BKE_pose_channel_free(pchan); - - /* copy data in temp back over to the cleaned-out (but still allocated) original channel */ - *pchan = pchanw; - if (pchan->custom) { - id_us_plus(&pchan->custom->id); - } - } - else { - /* always copy custom shape */ - pchan->custom = pchanp->custom; - if (pchan->custom) { - id_us_plus(&pchan->custom->id); - } - if (pchanp->custom_tx) { - pchan->custom_tx = BKE_pose_channel_find_name(pose, pchanp->custom_tx->name); - } - - /* ID-Property Syncing */ - { - IDProperty *prop_orig = pchan->prop; - if (pchanp->prop) { - pchan->prop = IDP_CopyProperty(pchanp->prop); - if (prop_orig) { - /* copy existing values across when types match */ - IDP_SyncGroupValues(pchan->prop, prop_orig); - } - } - else { - pchan->prop = NULL; - } - if (prop_orig) { - IDP_FreeProperty(prop_orig); - } - } - } - } -} - /** * \param r_last_visited_bone_p: The last bone handled by the last call to this function. */ @@ -2579,16 +2422,6 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_ // printf("rebuild pose %s, %d bones\n", ob->id.name, counter); - /* synchronize protected layers with proxy */ - /* HACK! To preserve 2.7x behavior that you always can pose even locked bones, - * do not do any restoration if this is a COW temp copy! */ - /* Switched back to just NO_MAIN tag, for some reasons (c) - * using COW tag was working this morning, but not anymore... */ - if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) { - BKE_object_copy_proxy_drivers(ob, ob->proxy); - pose_proxy_sync(ob, ob->proxy, arm->layer_protected); - } - BKE_pose_update_constraint_flags(pose); /* for IK detection for example */ pose->flag &= ~POSE_RECALC; @@ -2846,6 +2679,35 @@ BoundBox *BKE_armature_boundbox_get(Object *ob) return ob->runtime.bb; } +void BKE_pchan_minmax(const Object *ob, const bPoseChannel *pchan, float r_min[3], float r_max[3]) +{ + const bArmature *arm = ob->data; + const bPoseChannel *pchan_tx = (pchan->custom && pchan->custom_tx) ? pchan->custom_tx : pchan; + const BoundBox *bb_custom = ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) ? + BKE_object_boundbox_get(pchan->custom) : + NULL; + if (bb_custom) { + float mat[4][4], smat[4][4], rmat[4][4], tmp[4][4]; + scale_m4_fl(smat, PCHAN_CUSTOM_BONE_LENGTH(pchan)); + rescale_m4(smat, pchan->custom_scale_xyz); + eulO_to_mat4(rmat, pchan->custom_rotation_euler, ROT_MODE_XYZ); + copy_m4_m4(tmp, pchan_tx->pose_mat); + translate_m4(tmp, + pchan->custom_translation[0], + pchan->custom_translation[1], + pchan->custom_translation[2]); + mul_m4_series(mat, ob->obmat, tmp, rmat, smat); + BKE_boundbox_minmax(bb_custom, mat, r_min, r_max); + } + else { + float vec[3]; + mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head); + minmax_v3v3_v3(r_min, r_max, vec); + mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail); + minmax_v3v3_v3(r_min, r_max, vec); + } +} + bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select) { bool changed = false; @@ -2859,31 +2721,8 @@ bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden * (editarmature.c:2592)... Skip in this case too! */ if (pchan->bone && (!((use_hidden == false) && (PBONE_VISIBLE(arm, pchan->bone) == false)) && !((use_select == true) && ((pchan->bone->flag & BONE_SELECTED) == 0)))) { - bPoseChannel *pchan_tx = (pchan->custom && pchan->custom_tx) ? pchan->custom_tx : pchan; - BoundBox *bb_custom = ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) ? - BKE_object_boundbox_get(pchan->custom) : - NULL; - if (bb_custom) { - float mat[4][4], smat[4][4], rmat[4][4], tmp[4][4]; - scale_m4_fl(smat, PCHAN_CUSTOM_BONE_LENGTH(pchan)); - rescale_m4(smat, pchan->custom_scale_xyz); - eulO_to_mat4(rmat, pchan->custom_rotation_euler, ROT_MODE_XYZ); - copy_m4_m4(tmp, pchan_tx->pose_mat); - translate_m4(tmp, - pchan->custom_translation[0], - pchan->custom_translation[1], - pchan->custom_translation[2]); - mul_m4_series(mat, ob->obmat, tmp, rmat, smat); - BKE_boundbox_minmax(bb_custom, mat, r_min, r_max); - } - else { - float vec[3]; - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head); - minmax_v3v3_v3(r_min, r_max, vec); - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail); - minmax_v3v3_v3(r_min, r_max, vec); - } + BKE_pchan_minmax(ob, pchan, r_min, r_max); changed = true; } } diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc index a62a32d9633..de26b997e76 100644 --- a/source/blender/blenkernel/intern/armature_pose.cc +++ b/source/blender/blenkernel/intern/armature_pose.cc @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2015 Blender Foundation. * All rights reserved. - * - * Defines and code for core node types */ /** \file diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 05c318663e9..f19065f039b 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2015 Blender Foundation. * All rights reserved. - * - * Defines and code for core node types */ /** \file @@ -850,10 +848,6 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec } BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase)); - - if (object->proxy != NULL) { - object->proxy->proxy_from = object; - } } void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *object) @@ -1070,57 +1064,3 @@ void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, Scene *scene, Object *ob BIK_release_tree(scene, object, ctime); pose_eval_cleanup_common(object); } - -void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, Object *object) -{ - BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); - DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); - - BLI_assert(object->pose->chan_array != NULL || BLI_listbase_is_empty(&object->pose->chanbase)); -} - -void BKE_pose_eval_proxy_done(struct Depsgraph *depsgraph, Object *object) -{ - BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); - DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); -} - -void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, Object *object) -{ - BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); - DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); - pose_eval_cleanup_common(object); -} - -void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, Object *object, int pchan_index) -{ - const bArmature *armature = (bArmature *)object->data; - if (armature->edbo != NULL) { - return; - } - BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); - bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index); - BLI_assert(pchan != NULL); - DEG_debug_print_eval_subdata( - depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan); - /* TODO(sergey): Use indexed lookup, once it's guaranteed to be kept - * around for the time while proxies are evaluating. - */ -#if 0 - bPoseChannel *pchan_from = pose_pchan_get_indexed(object->proxy_from, pchan_index); -#else - bPoseChannel *pchan_from = BKE_pose_channel_find_name(object->proxy_from->pose, pchan->name); -#endif - if (pchan_from == NULL) { - printf( - "WARNING: Could not find bone %s in linked ID anymore... " - "You should delete and re-generate your proxy.\n", - pchan->name); - return; - } - BKE_pose_copy_pchan_result(pchan, pchan_from); - copy_dq_dq(&pchan->runtime.deform_dual_quat, &pchan_from->runtime.deform_dual_quat); - BKE_pchan_bbone_segments_cache_copy(pchan, pchan_from); - - pose_channel_flush_to_orig_if_needed(depsgraph, object, pchan); -} diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c index ee8ef5e97f7..fdd84f3dfd4 100644 --- a/source/blender/blenkernel/intern/attribute.c +++ b/source/blender/blenkernel/intern/attribute.c @@ -15,13 +15,12 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * - * Implementation of generic geometry attributes management. This is built - * on top of CustomData, which manages individual domains. */ /** \file * \ingroup bke + * Implementation of generic geometry attributes management. This is built + * on top of CustomData, which manages individual domains. */ #include <string.h> @@ -29,8 +28,8 @@ #include "MEM_guardedalloc.h" #include "DNA_ID.h" +#include "DNA_curves_types.h" #include "DNA_customdata_types.h" -#include "DNA_hair_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_pointcloud_types.h" @@ -38,9 +37,9 @@ #include "BLI_string_utf8.h" #include "BKE_attribute.h" +#include "BKE_curves.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "BKE_hair.h" #include "BKE_pointcloud.h" #include "BKE_report.h" @@ -88,12 +87,12 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM]) } break; } - case ID_HA: { - Hair *hair = (Hair *)id; - info[ATTR_DOMAIN_POINT].customdata = &hair->pdata; - info[ATTR_DOMAIN_POINT].length = hair->totpoint; - info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata; - info[ATTR_DOMAIN_CURVE].length = hair->totcurve; + case ID_CV: { + Curves *curves = (Curves *)id; + info[ATTR_DOMAIN_POINT].customdata = &curves->geometry.point_data; + info[ATTR_DOMAIN_POINT].length = curves->geometry.point_size; + info[ATTR_DOMAIN_CURVE].customdata = &curves->geometry.curve_data; + info[ATTR_DOMAIN_CURVE].length = curves->geometry.curve_size; break; } default: @@ -301,8 +300,8 @@ bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer) case ID_PT: { return BKE_pointcloud_customdata_required((PointCloud *)id, layer); } - case ID_HA: { - return BKE_hair_customdata_required((Hair *)id, layer); + case ID_CV: { + return BKE_curves_customdata_required((Curves *)id, layer); } default: return false; @@ -372,8 +371,8 @@ int *BKE_id_attributes_active_index_p(ID *id) case ID_ME: { return &((Mesh *)id)->attributes_active_index; } - case ID_HA: { - return &((Hair *)id)->attributes_active_index; + case ID_CV: { + return &((Curves *)id)->attributes_active_index; } default: return NULL; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index cc43a3e26a8..68ab11a013b 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -83,6 +83,8 @@ const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType ty return &CPPType::get<ColorGeometry4f>(); case CD_PROP_BOOL: return &CPPType::get<bool>(); + case CD_PROP_INT8: + return &CPPType::get<int8_t>(); default: return nullptr; } @@ -109,6 +111,9 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type) if (type.is<bool>()) { return CD_PROP_BOOL; } + if (type.is<int8_t>()) { + return CD_PROP_INT8; + } return static_cast<CustomDataType>(-1); } @@ -117,16 +122,18 @@ static int attribute_data_type_complexity(const CustomDataType data_type) switch (data_type) { case CD_PROP_BOOL: return 0; - case CD_PROP_INT32: + case CD_PROP_INT8: return 1; - case CD_PROP_FLOAT: + case CD_PROP_INT32: return 2; - case CD_PROP_FLOAT2: + case CD_PROP_FLOAT: return 3; - case CD_PROP_FLOAT3: + case CD_PROP_FLOAT2: return 4; - case CD_PROP_COLOR: + case CD_PROP_FLOAT3: return 5; + case CD_PROP_COLOR: + return 6; #if 0 /* These attribute types are not supported yet. */ case CD_MLOOPCOL: return 3; diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index 2cd128081eb..5341266e182 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -140,7 +140,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { private: static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | - CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL; + CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL | + CD_MASK_PROP_INT8; const AttributeDomain domain_; const CustomDataAccessInfo custom_data_access_; diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 53c9fe49fb7..07fd859765a 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -78,6 +78,23 @@ /** \name High Level `.blend` file read/write. * \{ */ +static bool blendfile_or_libraries_versions_atleast(Main *bmain, + const short versionfile, + const short subversionfile) +{ + if (!MAIN_VERSION_ATLEAST(bmain, versionfile, subversionfile)) { + return false; + } + + LISTBASE_FOREACH (Library *, library, &bmain->libraries) { + if (!MAIN_VERSION_ATLEAST(library, versionfile, subversionfile)) { + return false; + } + } + + return true; +} + static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data), char *path_dst, const char *path_src) @@ -349,13 +366,18 @@ static void setup_app_data(bContext *C, do_versions_ipos_to_animato(bmain); } - /* FIXME: Same as above, readfile's `do_version` do not allow to create new IDs. */ - /* TODO: Once this is definitively validated for 3.0 and option to not do it is removed, add a - * version bump and check here. */ - if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_proxy_to_override_conversion)) { + /* NOTE: readfile's `do_version` does not allow to create new IDs, and only operates on a single + * library at a time. This code needs to operate on the whole Main at once. */ + /* NOTE: Check bmain version (i.e. current blend file version), AND the versions of all the + * linked libraries. */ + if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 1)) { BKE_lib_override_library_main_proxy_convert(bmain, reports); } + if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 3)) { + BKE_lib_override_library_main_hierarchy_root_ensure(bmain); + } + bmain->recovered = 0; /* startup.blend or recovered startup */ diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 9b3f4c2fae8..025d16007d8 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -993,6 +993,27 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d /** \name Library link/append code. * \{ */ +static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *reports) +{ + /* NOTE: Do not bother checking file versions here, if there are no proxies to convert this code + * is quite fast anyway. */ + + BlendFileReadReport bf_reports = {.reports = reports}; + BKE_lib_override_library_main_proxy_convert(bmain, &bf_reports); + + if (bf_reports.count.proxies_to_lib_overrides_success != 0 || + bf_reports.count.proxies_to_lib_overrides_failures != 0) { + BKE_reportf( + bf_reports.reports, + RPT_WARNING, + "Proxies have been removed from Blender (%d proxies were automatically converted " + "to library overrides, %d proxies could not be converted and were cleared). " + "Please consider re-saving any library .blend file with the newest Blender version.", + bf_reports.count.proxies_to_lib_overrides_success, + bf_reports.count.proxies_to_lib_overrides_failures); + } +} + void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports) { if (lapp_context->num_items == 0) { @@ -1040,10 +1061,6 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList * if (item->action != LINK_APPEND_ACT_UNSET) { /* Already set, pass. */ } - if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); - item->action = LINK_APPEND_ACT_KEEP_LINKED; - } else if (do_reuse_local_id && existing_local_id != NULL) { CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); item->action = LINK_APPEND_ACT_REUSE_LOCAL; @@ -1098,10 +1115,7 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList * local_appended_new_id = id->newid; break; case LINK_APPEND_ACT_MAKE_LOCAL: - BKE_lib_id_make_local(bmain, - id, - make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL | - LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); + BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL); BLI_assert(id->newid == NULL); local_appended_new_id = id; break; @@ -1210,55 +1224,11 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList * continue; } BLI_assert(ID_IS_LINKED(id)); - - /* Attempt to re-link copied proxy objects. This allows appending of an entire scene - * from another blend file into this one, even when that blend file contains proxified - * armatures that have local references. Since the proxified object needs to be linked - * (not local), this will only work when the "Localize all" checkbox is disabled. - * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ - if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { - Object *ob = (Object *)id; - Object *ob_new = (Object *)id->newid; - bool is_local = false, is_lib = false; - - /* Proxies only work when the proxified object is linked-in from a library. */ - if (!ID_IS_LINKED(ob->proxy)) { - CLOG_WARN(&LOG, - "Proxy object %s will lose its link to %s, because the " - "proxified object is local", - id->newid->name, - ob->proxy->id.name); - continue; - } - - BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); - - /* We can only switch the proxy'ing to a made-local proxy if it is no longer - * referred to from a library. Not checking for local use; if new local proxy - * was not used locally would be a nasty bug! */ - if (is_local || is_lib) { - CLOG_WARN(&LOG, - "Made-local proxy object %s will lose its link to %s, " - "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)", - id->newid->name, - ob->proxy->id.name, - is_local, - is_lib); - } - else { - /* we can switch the proxy'ing from the linked-in to the made-local proxy. - * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that - * was already allocated by object_make_local() (which called BKE_object_copy). */ - ob_new->proxy = ob->proxy; - ob_new->proxy_group = ob->proxy_group; - ob_new->proxy_from = ob->proxy_from; - ob_new->proxy->proxy_from = ob_new; - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; - } - } } BKE_main_id_newptr_and_tag_clear(bmain); + + blendfile_link_append_proxies_convert(bmain, reports); } void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports) @@ -1361,6 +1331,10 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re .active_collection = NULL}; loose_data_instantiate(&instantiate_context); } + + if ((lapp_context->params->flag & FILE_LINK) != 0) { + blendfile_link_append_proxies_convert(lapp_context->params->bmain, reports); + } } /** \} */ @@ -1541,7 +1515,6 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, /* Note that in reload case, we also want to replace indirect usages. */ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | - ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; item_idx++, itemlink = itemlink->next) { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index a4f3e84a2bf..d8ad4dd89e4 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -15,13 +15,12 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Implementation of CDDerivedMesh. - * - * BKE_cdderivedmesh.h contains the function prototypes for this file. */ /** \file * \ingroup bke + * Implementation of #CDDerivedMesh. + * BKE_cdderivedmesh.h contains the function prototypes for this file. */ #include "atomic_ops.h" @@ -116,12 +115,6 @@ static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *r_edge) memcpy(r_edge, cddm->medge, sizeof(*r_edge) * dm->numEdgeData); } -static void cdDM_copyTessFaceArray(DerivedMesh *dm, MFace *r_face) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - memcpy(r_face, cddm->mface, sizeof(*r_face) * dm->numTessFaceData); -} - static void cdDM_copyLoopArray(DerivedMesh *dm, MLoop *r_loop) { CDDerivedMesh *cddm = (CDDerivedMesh *)dm; @@ -147,20 +140,6 @@ static void cdDM_getVertNo(DerivedMesh *dm, int index, float r_no[3]) copy_v3_v3(r_no, cddm->vert_normals[index]); } -static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - - if (!cddm->pmap && ob->type == OB_MESH) { - Mesh *me = ob->data; - - BKE_mesh_vert_poly_map_create( - &cddm->pmap, &cddm->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop); - } - - return cddm->pmap; -} - static void cdDM_recalc_looptri(DerivedMesh *dm) { CDDerivedMesh *cddm = (CDDerivedMesh *)dm; @@ -216,24 +195,17 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->copyVertArray = cdDM_copyVertArray; dm->copyEdgeArray = cdDM_copyEdgeArray; - dm->copyTessFaceArray = cdDM_copyTessFaceArray; dm->copyLoopArray = cdDM_copyLoopArray; dm->copyPolyArray = cdDM_copyPolyArray; - dm->getVertData = DM_get_vert_data; - dm->getEdgeData = DM_get_edge_data; - dm->getTessFaceData = DM_get_tessface_data; dm->getVertDataArray = DM_get_vert_data_layer; dm->getEdgeDataArray = DM_get_edge_data_layer; - dm->getTessFaceDataArray = DM_get_tessface_data_layer; dm->recalcLoopTri = cdDM_recalc_looptri; dm->getVertCo = cdDM_getVertCo; dm->getVertNo = cdDM_getVertNo; - dm->getPolyMap = cdDM_getPolyMap; - dm->release = cdDM_release; return cddm; @@ -265,12 +237,6 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, dm->deformedOnly = 1; dm->cd_flag = mesh->cd_flag; - if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { - dm->dirty |= DM_DIRTY_NORMALS; - } - /* TODO: DM_DIRTY_TESS_CDLAYERS ? Maybe not though, - * since we probably want to switch to looptris? */ - CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert); CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge); CustomData_merge(&mesh->fdata, @@ -282,7 +248,9 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly); cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); - cddm->vert_normals = CustomData_get_layer(&dm->vertData, CD_NORMAL); + /* Though this may be an unnecessary calculation, simply retrieving the layer may return nothing + * or dirty normals. */ + cddm->vert_normals = BKE_mesh_vertex_normals_ensure(mesh); cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); @@ -327,12 +295,6 @@ DerivedMesh *CDDM_copy(DerivedMesh *source) DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys); dm->deformedOnly = source->deformedOnly; dm->cd_flag = source->cd_flag; - dm->dirty = source->dirty; - - /* Tessellation data is never copied, so tag it here. - * Only tag dirty layers if we really ignored tessellation faces. - */ - dm->dirty |= DM_DIRTY_TESS_CDLAYERS; CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts); CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges); diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index f013ef99dde..3b7f91b93c0 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -5850,14 +5850,6 @@ static void add_new_constraint_to_list(Object *ob, bPoseChannel *pchan, bConstra BLI_addtail(list, con); BKE_constraint_unique_name(con, list); - /* if the target list is a list on some PoseChannel belonging to a proxy-protected - * Armature layer, we must tag newly added constraints with a flag which allows them - * to persist after proxy syncing has been done - */ - if (BKE_constraints_proxylocked_owner(ob, pchan)) { - con->flag |= CONSTRAINT_PROXY_LOCAL; - } - /* make this constraint the active one */ BKE_constraints_active_set(list, con); } @@ -6213,45 +6205,6 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai (con == NULL || (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) == 0)); } -/* -------- Constraints and Proxies ------- */ - -void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src) -{ - bConstraint *con, *next; - - /* for each tagged constraint, remove from src and move to dst */ - for (con = src->first; con; con = next) { - next = con->next; - - /* check if tagged */ - if (con->flag & CONSTRAINT_PROXY_LOCAL) { - BLI_remlink(src, con); - BLI_addtail(dst, con); - } - } -} - -bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan) -{ - /* Currently, constraints can only be on object or bone level */ - if (ob && ob->proxy) { - if (ob->pose && pchan) { - bArmature *arm = ob->data; - - /* On bone-level, check if bone is on proxy-protected layer */ - if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected)) { - return true; - } - } - else { - /* FIXME: constraints on object-level are not handled well yet */ - return true; - } - } - - return false; -} - /* -------- Target-Matrix Stuff ------- */ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 573595b6f90..0bf83ed5036 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -194,13 +194,10 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, float (*mappedcos)[3], float (*quats)[4]) { - MVert *mvert = me->mvert; - for (int i = 0; i < me->totvert; i++, mvert++) { - mvert->flag &= ~ME_VERT_TMP_TAG; - } + BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__); /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */ - mvert = me->mvert; + MVert *mvert = me->mvert; MPoly *mp = me->mpoly; MLoop *mloop = me->mloop; @@ -210,7 +207,7 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, MLoop *ml_prev = &ml_next[mp->totloop - 2]; for (int j = 0; j < mp->totloop; j++) { - if ((mvert[ml_curr->v].flag & ME_VERT_TMP_TAG) == 0) { + if (!BLI_BITMAP_TEST(vert_tag, ml_curr->v)) { const float *co_prev, *co_curr, *co_next; /* orig */ const float *vd_prev, *vd_curr, *vd_next; /* deform */ @@ -233,7 +230,7 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, set_crazy_vertex_quat( quats[ml_curr->v], co_curr, co_next, co_prev, vd_curr, vd_next, vd_prev); - mvert[ml_curr->v].flag |= ME_VERT_TMP_TAG; + BLI_BITMAP_ENABLE(vert_tag, ml_curr->v); } ml_prev = ml_curr; @@ -241,6 +238,8 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, ml_next++; } } + + MEM_freeN(vert_tag); } int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc new file mode 100644 index 00000000000..f5672e9b288 --- /dev/null +++ b/source/blender/blenkernel/intern/curves.cc @@ -0,0 +1,473 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + */ + +#include <cmath> +#include <cstring> + +#include "MEM_guardedalloc.h" + +#include "DNA_curves_types.h" +#include "DNA_defaults.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" + +#include "BLI_index_range.hh" +#include "BLI_listbase.h" +#include "BLI_math_base.h" +#include "BLI_math_vec_types.hh" +#include "BLI_rand.hh" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_anim_data.h" +#include "BKE_curves.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_idtype.h" +#include "BKE_lib_id.h" +#include "BKE_lib_query.h" +#include "BKE_lib_remap.h" +#include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLT_translation.h" + +#include "DEG_depsgraph_query.h" + +#include "BLO_read_write.h" + +using blender::float3; +using blender::IndexRange; +using blender::MutableSpan; +using blender::RandomNumberGenerator; + +static const char *ATTR_POSITION = "position"; +static const char *ATTR_RADIUS = "radius"; + +static void curves_random(Curves *curves); + +static void curves_init_data(ID *id) +{ + Curves *curves = (Curves *)id; + BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(curves, id)); + + MEMCPY_STRUCT_AFTER(curves, DNA_struct_default_get(Curves), id); + + CustomData_reset(&curves->geometry.point_data); + CustomData_reset(&curves->geometry.curve_data); + + CustomData_add_layer_named(&curves->geometry.point_data, + CD_PROP_FLOAT3, + CD_CALLOC, + nullptr, + curves->geometry.point_size, + ATTR_POSITION); + CustomData_add_layer_named(&curves->geometry.point_data, + CD_PROP_FLOAT, + CD_CALLOC, + nullptr, + curves->geometry.point_size, + ATTR_RADIUS); + + BKE_curves_update_customdata_pointers(curves); + + curves_random(curves); +} + +static void curves_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) +{ + Curves *curves_dst = (Curves *)id_dst; + const Curves *curves_src = (const Curves *)id_src; + curves_dst->mat = static_cast<Material **>(MEM_dupallocN(curves_src->mat)); + + curves_dst->geometry.point_size = curves_src->geometry.point_size; + curves_dst->geometry.curve_size = curves_src->geometry.curve_size; + + const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; + CustomData_copy(&curves_src->geometry.point_data, + &curves_dst->geometry.point_data, + CD_MASK_ALL, + alloc_type, + curves_dst->geometry.point_size); + CustomData_copy(&curves_src->geometry.curve_data, + &curves_dst->geometry.curve_data, + CD_MASK_ALL, + alloc_type, + curves_dst->geometry.curve_size); + BKE_curves_update_customdata_pointers(curves_dst); + + curves_dst->geometry.offsets = static_cast<int *>(MEM_dupallocN(curves_src->geometry.offsets)); + + curves_dst->batch_cache = nullptr; +} + +static void curves_free_data(ID *id) +{ + Curves *curves = (Curves *)id; + BKE_animdata_free(&curves->id, false); + + BKE_curves_batch_cache_free(curves); + + CustomData_free(&curves->geometry.point_data, curves->geometry.point_size); + CustomData_free(&curves->geometry.curve_data, curves->geometry.curve_size); + + MEM_SAFE_FREE(curves->geometry.offsets); + + MEM_SAFE_FREE(curves->mat); +} + +static void curves_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Curves *curves = (Curves *)id; + for (int i = 0; i < curves->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curves->mat[i], IDWALK_CB_USER); + } +} + +static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_address) +{ + Curves *curves = (Curves *)id; + + CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomData_blend_write_prepare( + &curves->geometry.point_data, &players, players_buff, ARRAY_SIZE(players_buff)); + CustomData_blend_write_prepare( + &curves->geometry.curve_data, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff)); + + /* Write LibData */ + BLO_write_id_struct(writer, Curves, id_address, &curves->id); + BKE_id_blend_write(writer, &curves->id); + + /* Direct data */ + CustomData_blend_write(writer, + &curves->geometry.point_data, + players, + curves->geometry.point_size, + CD_MASK_ALL, + &curves->id); + CustomData_blend_write(writer, + &curves->geometry.curve_data, + clayers, + curves->geometry.curve_size, + CD_MASK_ALL, + &curves->id); + + BLO_write_int32_array(writer, curves->geometry.curve_size + 1, curves->geometry.offsets); + + BLO_write_pointer_array(writer, curves->totcol, curves->mat); + if (curves->adt) { + BKE_animdata_blend_write(writer, curves->adt); + } + + /* Remove temporary data. */ + if (players && players != players_buff) { + MEM_freeN(players); + } + if (clayers && clayers != clayers_buff) { + MEM_freeN(clayers); + } +} + +static void curves_blend_read_data(BlendDataReader *reader, ID *id) +{ + Curves *curves = (Curves *)id; + BLO_read_data_address(reader, &curves->adt); + BKE_animdata_blend_read_data(reader, curves->adt); + + /* Geometry */ + CustomData_blend_read(reader, &curves->geometry.point_data, curves->geometry.point_size); + CustomData_blend_read(reader, &curves->geometry.curve_data, curves->geometry.point_size); + BKE_curves_update_customdata_pointers(curves); + + BLO_read_int32_array(reader, curves->geometry.curve_size + 1, &curves->geometry.offsets); + + /* Materials */ + BLO_read_pointer_array(reader, (void **)&curves->mat); +} + +static void curves_blend_read_lib(BlendLibReader *reader, ID *id) +{ + Curves *curves = (Curves *)id; + for (int a = 0; a < curves->totcol; a++) { + BLO_read_id_address(reader, curves->id.lib, &curves->mat[a]); + } +} + +static void curves_blend_read_expand(BlendExpander *expander, ID *id) +{ + Curves *curves = (Curves *)id; + for (int a = 0; a < curves->totcol; a++) { + BLO_expand(expander, curves->mat[a]); + } +} + +IDTypeInfo IDType_ID_CV = { + /*id_code */ ID_CV, + /*id_filter */ FILTER_ID_CV, + /*main_listbase_index */ INDEX_ID_CV, + /*struct_size */ sizeof(Curves), + /*name */ "Hair Curves", + /*name_plural */ "Hair Curves", + /*translation_context */ BLT_I18NCONTEXT_ID_CURVES, + /*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /*asset_type_info */ nullptr, + + /*init_data */ curves_init_data, + /*copy_data */ curves_copy_data, + /*free_data */ curves_free_data, + /*make_local */ nullptr, + /*foreach_id */ curves_foreach_id, + /*foreach_cache */ nullptr, + /*foreach_path */ nullptr, + /*owner_get */ nullptr, + + /*blend_write */ curves_blend_write, + /*blend_read_data */ curves_blend_read_data, + /*blend_read_lib */ curves_blend_read_lib, + /*blend_read_expand */ curves_blend_read_expand, + + /*blend_read_undo_preserve */ nullptr, + + /*lib_override_apply_post */ nullptr, +}; + +static void curves_random(Curves *curves) +{ + CurvesGeometry &geometry = curves->geometry; + const int numpoints = 8; + + geometry.curve_size = 500; + + geometry.curve_size = 500; + geometry.point_size = geometry.curve_size * numpoints; + + curves->geometry.offsets = (int *)MEM_calloc_arrayN( + curves->geometry.curve_size + 1, sizeof(int), __func__); + CustomData_realloc(&geometry.point_data, geometry.point_size); + CustomData_realloc(&geometry.curve_data, geometry.curve_size); + BKE_curves_update_customdata_pointers(curves); + + MutableSpan<int> offsets{geometry.offsets, geometry.curve_size + 1}; + MutableSpan<float3> positions{(float3 *)geometry.position, geometry.point_size}; + MutableSpan<float> radii{geometry.radius, geometry.point_size}; + + for (const int i : offsets.index_range()) { + geometry.offsets[i] = numpoints * i; + } + + RandomNumberGenerator rng; + + for (int i = 0; i < geometry.curve_size; i++) { + const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]); + MutableSpan<float3> curve_positions = positions.slice(curve_range); + MutableSpan<float> curve_radii = radii.slice(curve_range); + + const float theta = 2.0f * M_PI * rng.get_float(); + const float phi = saacosf(2.0f * rng.get_float() - 1.0f); + + float3 no = {std::sin(theta) * std::sin(phi), std::cos(theta) * std::sin(phi), std::cos(phi)}; + no = blender::math::normalize(no); + + float3 co = no; + for (int key = 0; key < numpoints; key++) { + float t = key / (float)(numpoints - 1); + curve_positions[key] = co; + curve_radii[key] = 0.02f * (1.0f - t); + + float3 offset = float3(rng.get_float(), rng.get_float(), rng.get_float()) * 2.0f - 1.0f; + co += (offset + no) / numpoints; + } + } +} + +void *BKE_curves_add(Main *bmain, const char *name) +{ + Curves *curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, name)); + + return curves; +} + +BoundBox *BKE_curves_boundbox_get(Object *ob) +{ + BLI_assert(ob->type == OB_CURVES); + Curves *curves = static_cast<Curves *>(ob->data); + + if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { + return ob->runtime.bb; + } + + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); + + float min[3], max[3]; + INIT_MINMAX(min, max); + + float(*curves_co)[3] = curves->geometry.position; + float *curves_radius = curves->geometry.radius; + for (int a = 0; a < curves->geometry.point_size; a++) { + float *co = curves_co[a]; + float radius = (curves_radius) ? curves_radius[a] : 0.0f; + const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius}; + const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius}; + DO_MIN(co_min, min); + DO_MAX(co_max, max); + } + + BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); + } + + return ob->runtime.bb; +} + +void BKE_curves_update_customdata_pointers(Curves *curves) +{ + curves->geometry.position = (float(*)[3])CustomData_get_layer_named( + &curves->geometry.point_data, CD_PROP_FLOAT3, ATTR_POSITION); + curves->geometry.radius = (float *)CustomData_get_layer_named( + &curves->geometry.point_data, CD_PROP_FLOAT, ATTR_RADIUS); +} + +bool BKE_curves_customdata_required(Curves *UNUSED(curves), CustomDataLayer *layer) +{ + return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, ATTR_POSITION); +} + +/* Dependency Graph */ + +Curves *BKE_curves_new_for_eval(const Curves *curves_src, int totpoint, int totcurve) +{ + Curves *curves_dst = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr)); + + STRNCPY(curves_dst->id.name, curves_src->id.name); + curves_dst->mat = static_cast<Material **>(MEM_dupallocN(curves_src->mat)); + curves_dst->totcol = curves_src->totcol; + + curves_dst->geometry.point_size = totpoint; + curves_dst->geometry.curve_size = totcurve; + CustomData_copy(&curves_src->geometry.point_data, + &curves_dst->geometry.point_data, + CD_MASK_ALL, + CD_CALLOC, + totpoint); + CustomData_copy(&curves_src->geometry.curve_data, + &curves_dst->geometry.curve_data, + CD_MASK_ALL, + CD_CALLOC, + totcurve); + BKE_curves_update_customdata_pointers(curves_dst); + + return curves_dst; +} + +Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference) +{ + int flags = LIB_ID_COPY_LOCALIZE; + + if (reference) { + flags |= LIB_ID_COPY_CD_REFERENCE; + } + + Curves *result = (Curves *)BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, flags); + return result; +} + +static Curves *curves_evaluate_modifiers(struct Depsgraph *depsgraph, + struct Scene *scene, + Object *object, + Curves *curves_input) +{ + Curves *curves = curves_input; + + /* Modifier evaluation modes. */ + const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; + const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; + + /* Get effective list of modifiers to execute. Some effects like shape keys + * are added as virtual modifiers before the user created modifiers. */ + VirtualModifierData virtualModifierData; + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); + + /* Evaluate modifiers. */ + for (; md; md = md->next) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type)); + + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { + continue; + } + + if ((mti->type == eModifierTypeType_OnlyDeform) && + (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) { + /* Ensure we are not modifying the input. */ + if (curves == curves_input) { + curves = BKE_curves_copy_for_eval(curves, true); + } + + /* Ensure we are not overwriting referenced data. */ + CustomData_duplicate_referenced_layer_named(&curves->geometry.point_data, + CD_PROP_FLOAT3, + ATTR_POSITION, + curves->geometry.point_size); + BKE_curves_update_customdata_pointers(curves); + + /* Created deformed coordinates array on demand. */ + mti->deformVerts( + md, &mectx, nullptr, curves->geometry.position, curves->geometry.point_size); + } + } + + return curves; +} + +void BKE_curves_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object) +{ + /* Free any evaluated data and restore original data. */ + BKE_object_free_derived_caches(object); + + /* Evaluate modifiers. */ + Curves *curves = static_cast<Curves *>(object->data); + Curves *curves_eval = curves_evaluate_modifiers(depsgraph, scene, object, curves); + + /* Assign evaluated object. */ + const bool is_owned = (curves != curves_eval); + BKE_object_eval_assign_data(object, &curves_eval->id, is_owned); +} + +/* Draw Cache */ + +void (*BKE_curves_batch_cache_dirty_tag_cb)(Curves *curves, int mode) = nullptr; +void (*BKE_curves_batch_cache_free_cb)(Curves *curves) = nullptr; + +void BKE_curves_batch_cache_dirty_tag(Curves *curves, int mode) +{ + if (curves->batch_cache) { + BKE_curves_batch_cache_dirty_tag_cb(curves, mode); + } +} + +void BKE_curves_batch_cache_free(Curves *curves) +{ + if (curves->batch_cache) { + BKE_curves_batch_cache_free_cb(curves); + } +} diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index e4c18325d76..6db5ae7567f 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -15,13 +15,13 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Implementation of CustomData. - * - * BKE_customdata.h contains the function prototypes for this file. */ /** \file * \ingroup bke + * Implementation of CustomData. + * + * BKE_customdata.h contains the function prototypes for this file. */ #include "MEM_guardedalloc.h" @@ -31,7 +31,6 @@ #include "DNA_ID.h" #include "DNA_customdata_types.h" -#include "DNA_hair_types.h" #include "DNA_meshdata_types.h" #include "BLI_bitmap.h" @@ -1793,10 +1792,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 44: CD_RADIUS */ {sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, - /* 45: CD_HAIRCURVE */ - {sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, - /* 46: CD_HAIRMAPPING */ - {sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, + /* 45: CD_PROP_INT8 */ + {sizeof(int8_t), "MInt8Property", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, + /* 46: CD_HAIRMAPPING */ /* UNUSED */ + {-1, "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 47: CD_PROP_COLOR */ {sizeof(MPropCol), "MPropCol", @@ -1914,7 +1913,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDCustomLoopNormal", "CDSculptFaceGroups", /* 43-46 */ "CDHairPoint", - "CDHairCurve", + "CDPropInt8", "CDHairMapping", "CDPoint", "CDPropCol", @@ -2431,7 +2430,7 @@ const char *CustomData_get_active_layer_name(const struct CustomData *data, cons { /* Get the layer index of the active layer of this type. */ const int layer_index = CustomData_get_active_layer_index(data, type); - return layer_index < 0 ? NULL : data->layers[layer_index].name; + return layer_index < 0 ? nullptr : data->layers[layer_index].name; } void CustomData_set_layer_active(CustomData *data, int type, int n) @@ -2786,7 +2785,7 @@ void CustomData_free_layers_anonymous(struct CustomData *data, int totelem) bool found_anonymous_layer = false; for (int i = 0; i < data->totlayer; i++) { const CustomDataLayer *layer = &data->layers[i]; - if (layer->anonymous_id != NULL) { + if (layer->anonymous_id != nullptr) { CustomData_free_layer(data, layer->type, totelem, i); found_anonymous_layer = true; break; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index ef789d3e39b..bc5a0ed1538 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1985,9 +1985,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * } MEM_freeN(fcolor); - - /* Mark tessellated CD layers as dirty. */ - // result->dirty |= DM_DIRTY_TESS_CDLAYERS; } /* vertex group paint */ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index ce30f80ba65..e71217fea9e 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -88,14 +88,6 @@ typedef struct DriverVarTypeInfo { /** \name Driver Target Utilities * \{ */ -static ID *dtar_id_ensure_proxy_from(ID *id) -{ - if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) { - return (ID *)(((Object *)id)->proxy_from); - } - return id; -} - /** * Helper function to obtain a value using RNA from the specified source * (for evaluating drivers). @@ -113,7 +105,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar) return 0.0f; } - id = dtar_id_ensure_proxy_from(dtar->id); + id = dtar->id; /* Error check for missing pointer. */ if (id == NULL) { @@ -217,7 +209,7 @@ bool driver_get_variable_property(ChannelDriver *driver, return false; } - id = dtar_id_ensure_proxy_from(dtar->id); + id = dtar->id; /* Error check for missing pointer. */ if (id == NULL) { @@ -273,7 +265,7 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar) short valid_targets = 0; DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + Object *ob = (Object *)dtar->id; /* Check if this target has valid data. */ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { @@ -328,7 +320,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) for (int i = 0; i < 2; i++) { /* Get pointer to loc values to store in. */ DriverTarget *dtar = &dvar->targets[i]; - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + Object *ob = (Object *)dtar->id; bPoseChannel *pchan; /* After the checks above, the targets should be valid here. */ @@ -389,7 +381,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* NOTE: for now, these are all just world-space */ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { /* Get pointer to loc values to store in. */ - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + Object *ob = (Object *)dtar->id; bPoseChannel *pchan; float tmp_loc[3]; @@ -472,7 +464,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) { DriverTarget *dtar = &dvar->targets[0]; - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + Object *ob = (Object *)dtar->id; bPoseChannel *pchan; float mat[4][4]; float oldEul[3] = {0.0f, 0.0f, 0.0f}; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 13338f33bd6..6e39125b252 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -55,6 +55,7 @@ #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" +#include "BKE_gpencil_update_cache.h" #include "BKE_icons.h" #include "BKE_idtype.h" #include "BKE_image.h" @@ -158,6 +159,7 @@ static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id gpd->runtime.sbuffer_used = 0; gpd->runtime.sbuffer_size = 0; gpd->runtime.tot_cp_points = 0; + gpd->runtime.update_cache = NULL; /* write gpd data block to file */ BLO_write_id_struct(writer, bGPdata, id_address, &gpd->id); @@ -221,6 +223,7 @@ void BKE_gpencil_blend_read_data(BlendDataReader *reader, bGPdata *gpd) gpd->runtime.sbuffer_used = 0; gpd->runtime.sbuffer_size = 0; gpd->runtime.tot_cp_points = 0; + gpd->runtime.update_cache = NULL; /* Relink palettes (old palettes deprecated, only to convert old files). */ BLO_read_list(reader, &gpd->palettes); @@ -501,6 +504,8 @@ void BKE_gpencil_free_data(bGPdata *gpd, bool free_all) BLI_freelistN(&gpd->vertex_group_names); + BKE_gpencil_free_update_cache(gpd); + /* free all data */ if (free_all) { /* clear cache */ @@ -985,6 +990,43 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src, return gpl_dst; } +void BKE_gpencil_data_copy_settings(const bGPdata *gpd_src, bGPdata *gpd_dst) +{ + gpd_dst->flag = gpd_src->flag; + gpd_dst->curve_edit_resolution = gpd_src->curve_edit_resolution; + gpd_dst->curve_edit_threshold = gpd_src->curve_edit_threshold; + gpd_dst->curve_edit_corner_angle = gpd_src->curve_edit_corner_angle; + gpd_dst->pixfactor = gpd_src->pixfactor; + copy_v4_v4(gpd_dst->line_color, gpd_src->line_color); + + gpd_dst->onion_factor = gpd_src->onion_factor; + gpd_dst->onion_mode = gpd_src->onion_mode; + gpd_dst->onion_flag = gpd_src->onion_flag; + gpd_dst->gstep = gpd_src->gstep; + gpd_dst->gstep_next = gpd_src->gstep_next; + + copy_v3_v3(gpd_dst->gcolor_prev, gpd_src->gcolor_prev); + copy_v3_v3(gpd_dst->gcolor_next, gpd_src->gcolor_next); + + gpd_dst->zdepth_offset = gpd_src->zdepth_offset; + + gpd_dst->totlayer = gpd_src->totlayer; + gpd_dst->totframe = gpd_src->totframe; + gpd_dst->totstroke = gpd_src->totstroke; + gpd_dst->totpoint = gpd_src->totpoint; + + gpd_dst->draw_mode = gpd_src->draw_mode; + gpd_dst->onion_keytype = gpd_src->onion_keytype; + + gpd_dst->select_last_index = gpd_src->select_last_index; + gpd_dst->vertex_group_active_index = gpd_src->vertex_group_active_index; + + copy_v3_v3(gpd_dst->grid.color, gpd_src->grid.color); + copy_v2_v2(gpd_dst->grid.scale, gpd_src->grid.scale); + copy_v2_v2(gpd_dst->grid.offset, gpd_src->grid.offset); + gpd_dst->grid.lines = gpd_src->grid.lines; +} + void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst) { gpl_dst->line_change = gpl_src->line_change; @@ -1004,6 +1046,33 @@ void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_ds copy_m4_m4(gpl_dst->layer_invmat, gpl_src->layer_invmat); gpl_dst->blend_mode = gpl_src->blend_mode; gpl_dst->flag = gpl_src->flag; + gpl_dst->onion_flag = gpl_src->onion_flag; +} + +void BKE_gpencil_frame_copy_settings(const bGPDframe *gpf_src, bGPDframe *gpf_dst) +{ + gpf_dst->flag = gpf_src->flag; + gpf_dst->key_type = gpf_src->key_type; + gpf_dst->framenum = gpf_src->framenum; +} + +void BKE_gpencil_stroke_copy_settings(const bGPDstroke *gps_src, bGPDstroke *gps_dst) +{ + gps_dst->thickness = gps_src->thickness; + gps_dst->flag = gps_src->flag; + gps_dst->inittime = gps_src->inittime; + gps_dst->mat_nr = gps_src->mat_nr; + copy_v2_v2_short(gps_dst->caps, gps_src->caps); + gps_dst->hardeness = gps_src->hardeness; + copy_v2_v2(gps_dst->aspect_ratio, gps_src->aspect_ratio); + gps_dst->fill_opacity_fac = gps_dst->fill_opacity_fac; + copy_v3_v3(gps_dst->boundbox_min, gps_src->boundbox_min); + copy_v3_v3(gps_dst->boundbox_max, gps_src->boundbox_max); + gps_dst->uv_rotation = gps_src->uv_rotation; + copy_v2_v2(gps_dst->uv_translation, gps_src->uv_translation); + gps_dst->uv_scale = gps_src->uv_scale; + gps_dst->select_index = gps_src->select_index; + copy_v4_v4(gps_dst->vert_color_fill, gps_src->vert_color_fill); } bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) @@ -2579,36 +2648,53 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig } } -void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_eval) +/** + * Update original pointers in evaluated layer. + * \param gpl_orig: Original grease-pencil layer. + * \param gpl_eval: Evaluated grease pencil layer. + */ +void BKE_gpencil_layer_original_pointers_update(const struct bGPDlayer *gpl_orig, + const struct bGPDlayer *gpl_eval) { - bGPdata *gpd_eval = (bGPdata *)ob_eval->data; - bGPdata *gpd_orig = (bGPdata *)ob_orig->data; + bGPDframe *gpf_eval = gpl_eval->frames.first; + LISTBASE_FOREACH (bGPDframe *, gpf_orig, &gpl_orig->frames) { + if (gpf_eval != NULL) { + /* Update frame reference pointers. */ + gpf_eval->runtime.gpf_orig = (bGPDframe *)gpf_orig; + BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval); + gpf_eval = gpf_eval->next; + } + } +} +void BKE_gpencil_data_update_orig_pointers(const bGPdata *gpd_orig, const bGPdata *gpd_eval) +{ /* Assign pointers to the original stroke and points to the evaluated data. This must * be done before applying any modifier because at this moment the structure is equals, * so we can assume the layer index is the same in both data-blocks. * This data will be used by operators. */ bGPDlayer *gpl_eval = gpd_eval->layers.first; - LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { + LISTBASE_FOREACH (bGPDlayer *, gpl_orig, &gpd_orig->layers) { if (gpl_eval != NULL) { /* Update layer reference pointers. */ - gpl_eval->runtime.gpl_orig = (bGPDlayer *)gpl; - - bGPDframe *gpf_eval = gpl_eval->frames.first; - LISTBASE_FOREACH (bGPDframe *, gpf_orig, &gpl->frames) { - if (gpf_eval != NULL) { - /* Update frame reference pointers. */ - gpf_eval->runtime.gpf_orig = (bGPDframe *)gpf_orig; - BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval); - gpf_eval = gpf_eval->next; - } - } + gpl_eval->runtime.gpl_orig = gpl_orig; + BKE_gpencil_layer_original_pointers_update(gpl_orig, gpl_eval); gpl_eval = gpl_eval->next; } } } +/** + * Update pointers of eval data to original data to keep references. + * \param ob_orig: Original grease pencil object + * \param ob_eval: Evaluated grease pencil object + */ +void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_eval) +{ + BKE_gpencil_data_update_orig_pointers((bGPdata *)ob_orig->data, (bGPdata *)ob_eval->data); +} + void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, @@ -2751,4 +2837,180 @@ void BKE_gpencil_frame_selected_hash(bGPdata *gpd, struct GHash *r_list) } } +bool BKE_gpencil_can_avoid_full_copy_on_write(const Depsgraph *depsgraph, bGPdata *gpd) +{ + /* For now, we only use the update cache in the active depsgraph. Othwerwise we might access the + * cache while another depsgraph frees it. */ + if (!DEG_is_active(depsgraph)) { + return false; + } + + GPencilUpdateCache *update_cache = gpd->runtime.update_cache; + return update_cache != NULL && update_cache->flag != GP_UPDATE_NODE_FULL_COPY; +} + +typedef struct tGPencilUpdateOnWriteTraverseData { + bGPdata *gpd_eval; + bGPDlayer *gpl_eval; + bGPDframe *gpf_eval; + bGPDstroke *gps_eval; + int gpl_index; + int gpf_index; + int gps_index; +} tGPencilUpdateOnWriteTraverseData; + +static bool gpencil_update_on_write_layer_cb(GPencilUpdateCache *gpl_cache, void *user_data) +{ + tGPencilUpdateOnWriteTraverseData *td = (tGPencilUpdateOnWriteTraverseData *)user_data; + td->gpl_eval = BLI_findlinkfrom((Link *)td->gpl_eval, gpl_cache->index - td->gpl_index); + td->gpl_index = gpl_cache->index; + bGPDlayer *gpl = (bGPDlayer *)gpl_cache->data; + + if (gpl_cache->flag == GP_UPDATE_NODE_FULL_COPY) { + bGPDlayer *gpl_eval_next = td->gpl_eval->next; + BLI_assert(gpl != NULL); + + BKE_gpencil_layer_delete(td->gpd_eval, td->gpl_eval); + + td->gpl_eval = BKE_gpencil_layer_duplicate(gpl, true, true); + BLI_insertlinkbefore(&td->gpd_eval->layers, gpl_eval_next, td->gpl_eval); + + BKE_gpencil_layer_original_pointers_update(gpl, td->gpl_eval); + td->gpl_eval->runtime.gpl_orig = gpl; + return true; + } + else if (gpl_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) { + BLI_assert(gpl != NULL); + BKE_gpencil_layer_copy_settings(gpl, td->gpl_eval); + td->gpl_eval->runtime.gpl_orig = gpl; + } + + td->gpf_eval = td->gpl_eval->frames.first; + td->gpf_index = 0; + return false; +} + +static bool gpencil_update_on_write_frame_cb(GPencilUpdateCache *gpf_cache, void *user_data) +{ + tGPencilUpdateOnWriteTraverseData *td = (tGPencilUpdateOnWriteTraverseData *)user_data; + td->gpf_eval = BLI_findlinkfrom((Link *)td->gpf_eval, gpf_cache->index - td->gpf_index); + td->gpf_index = gpf_cache->index; + + bGPDframe *gpf = (bGPDframe *)gpf_cache->data; + + if (gpf_cache->flag == GP_UPDATE_NODE_FULL_COPY) { + /* Do a full copy of the frame. */ + bGPDframe *gpf_eval_next = td->gpf_eval->next; + BLI_assert(gpf != NULL); + + bool update_actframe = (td->gpl_eval->actframe == td->gpf_eval) ? true : false; + BKE_gpencil_free_strokes(td->gpf_eval); + BLI_freelinkN(&td->gpl_eval->frames, td->gpf_eval); + + td->gpf_eval = BKE_gpencil_frame_duplicate(gpf, true); + BLI_insertlinkbefore(&td->gpl_eval->frames, gpf_eval_next, td->gpf_eval); + + BKE_gpencil_frame_original_pointers_update(gpf, td->gpf_eval); + td->gpf_eval->runtime.gpf_orig = gpf; + + if (update_actframe) { + td->gpl_eval->actframe = td->gpf_eval; + } + + return true; + } + else if (gpf_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) { + BLI_assert(gpf != NULL); + BKE_gpencil_frame_copy_settings(gpf, td->gpf_eval); + td->gpf_eval->runtime.gpf_orig = gpf; + } + + td->gps_eval = td->gpf_eval->strokes.first; + td->gps_index = 0; + return false; +} + +static bool gpencil_update_on_write_stroke_cb(GPencilUpdateCache *gps_cache, void *user_data) +{ + tGPencilUpdateOnWriteTraverseData *td = (tGPencilUpdateOnWriteTraverseData *)user_data; + td->gps_eval = BLI_findlinkfrom((Link *)td->gps_eval, gps_cache->index - td->gps_index); + td->gps_index = gps_cache->index; + + bGPDstroke *gps = (bGPDstroke *)gps_cache->data; + + if (gps_cache->flag == GP_UPDATE_NODE_FULL_COPY) { + /* Do a full copy of the stroke. */ + bGPDstroke *gps_eval_next = td->gps_eval->next; + BLI_assert(gps != NULL); + + BLI_remlink(&td->gpf_eval->strokes, td->gps_eval); + BKE_gpencil_free_stroke(td->gps_eval); + + td->gps_eval = BKE_gpencil_stroke_duplicate(gps, true, true); + BLI_insertlinkbefore(&td->gpf_eval->strokes, gps_eval_next, td->gps_eval); + + td->gps_eval->runtime.gps_orig = gps; + + /* Assign original pt pointers. */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt_orig = &gps->points[i]; + bGPDspoint *pt_eval = &td->gps_eval->points[i]; + pt_orig->runtime.pt_orig = NULL; + pt_orig->runtime.idx_orig = i; + pt_eval->runtime.pt_orig = pt_orig; + pt_eval->runtime.idx_orig = i; + } + } + else if (gps_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) { + BLI_assert(gps != NULL); + BKE_gpencil_stroke_copy_settings(gps, td->gps_eval); + td->gps_eval->runtime.gps_orig = gps; + } + + return false; +} + +/** + * Update the geometry of the evaluated bGPdata. + * This function will: + * 1) Copy the original data over to the evaluated object. + * 2) Update the original pointers in the runtime structs. + */ +void BKE_gpencil_update_on_write(bGPdata *gpd_orig, bGPdata *gpd_eval) +{ + GPencilUpdateCache *update_cache = gpd_orig->runtime.update_cache; + + /* We assume that a full copy is not needed and the update cache is populated. */ + if (update_cache == NULL || update_cache->flag == GP_UPDATE_NODE_FULL_COPY) { + return; + } + + if (update_cache->flag == GP_UPDATE_NODE_LIGHT_COPY) { + BKE_gpencil_data_copy_settings(gpd_orig, gpd_eval); + } + + GPencilUpdateCacheTraverseSettings ts = {{ + gpencil_update_on_write_layer_cb, + gpencil_update_on_write_frame_cb, + gpencil_update_on_write_stroke_cb, + }}; + + tGPencilUpdateOnWriteTraverseData data = { + .gpd_eval = gpd_eval, + .gpl_eval = gpd_eval->layers.first, + .gpf_eval = NULL, + .gps_eval = NULL, + .gpl_index = 0, + .gpf_index = 0, + .gps_index = 0, + }; + + BKE_gpencil_traverse_update_cache(update_cache, &ts, &data); + + gpd_eval->flag |= GP_DATA_CACHE_IS_DIRTY; + + /* TODO: This might cause issues when we have multiple depsgraphs? */ + BKE_gpencil_free_update_cache(gpd_orig); +} + /** \} */ diff --git a/source/blender/blenkernel/intern/gpencil_update_cache.c b/source/blender/blenkernel/intern/gpencil_update_cache.c new file mode 100644 index 00000000000..323c3a9f2a2 --- /dev/null +++ b/source/blender/blenkernel/intern/gpencil_update_cache.c @@ -0,0 +1,274 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2022, Blender Foundation + * This is a new part of Blender + */ + +/** \file + * \ingroup bke + */ + +#include <stdio.h> + +#include "BKE_gpencil_update_cache.h" + +#include "BLI_dlrbTree.h" +#include "BLI_listbase.h" + +#include "BKE_gpencil.h" + +#include "DNA_gpencil_types.h" +#include "DNA_userdef_types.h" + +#include "MEM_guardedalloc.h" + +static GPencilUpdateCache *update_cache_alloc(int index, int flag, void *data) +{ + GPencilUpdateCache *new_cache = MEM_callocN(sizeof(GPencilUpdateCache), __func__); + new_cache->children = BLI_dlrbTree_new(); + new_cache->flag = flag; + new_cache->index = index; + new_cache->data = data; + + return new_cache; +} + +static short cache_node_compare(void *node, void *data) +{ + int index_a = ((GPencilUpdateCacheNode *)node)->cache->index; + int index_b = ((GPencilUpdateCache *)data)->index; + if (index_a == index_b) { + return 0; + } + return index_a < index_b ? 1 : -1; +} + +static DLRBT_Node *cache_node_alloc(void *data) +{ + GPencilUpdateCacheNode *new_node = MEM_callocN(sizeof(GPencilUpdateCacheNode), __func__); + new_node->cache = ((GPencilUpdateCache *)data); + return (DLRBT_Node *)new_node; +} + +static void cache_node_free(void *node); + +static void update_cache_free(GPencilUpdateCache *cache) +{ + if (cache->children != NULL) { + BLI_dlrbTree_free(cache->children, cache_node_free); + MEM_freeN(cache->children); + } + MEM_freeN(cache); +} + +static void cache_node_free(void *node) +{ + GPencilUpdateCache *cache = ((GPencilUpdateCacheNode *)node)->cache; + if (cache != NULL) { + update_cache_free(cache); + } + MEM_freeN(node); +} + +static void cache_node_update(void *node, void *data) +{ + GPencilUpdateCache *update_cache = ((GPencilUpdateCacheNode *)node)->cache; + GPencilUpdateCache *new_update_cache = (GPencilUpdateCache *)data; + + /* If the new cache is already "covered" by the current cache, just free it and return. */ + if (new_update_cache->flag <= update_cache->flag) { + update_cache_free(new_update_cache); + return; + } + + update_cache->data = new_update_cache->data; + update_cache->flag = new_update_cache->flag; + + /* In case the new cache does a full update, remove its children since they will be all + * updated by this cache. */ + if (new_update_cache->flag == GP_UPDATE_NODE_FULL_COPY && update_cache->children != NULL) { + BLI_dlrbTree_free(update_cache->children, cache_node_free); + MEM_freeN(update_cache->children); + } + + update_cache_free(new_update_cache); +} + +static void update_cache_node_create_ex(GPencilUpdateCache *root_cache, + void *data, + int gpl_index, + int gpf_index, + int gps_index, + bool full_copy) +{ + if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) { + /* Entire data-block has to be recaculated, e.g. nothing else needs to be added to the cache. + */ + return; + } + + const int node_flag = full_copy ? GP_UPDATE_NODE_FULL_COPY : GP_UPDATE_NODE_LIGHT_COPY; + + if (gpl_index == -1) { + root_cache->data = (bGPdata *)data; + root_cache->flag = node_flag; + if (full_copy) { + /* Entire data-block has to be recaculated, remove all caches of "lower" elements. */ + BLI_dlrbTree_free(root_cache->children, cache_node_free); + } + return; + } + + const bool is_layer_update_node = (gpf_index == -1); + /* If the data pointer in GPencilUpdateCache is NULL, this element is not actually cached + * and does not need to be updated, but we do need the index to find elements that are in + * levels below. E.g. if a stroke needs to be updated, the frame it is in would not hold a + * pointer to it's data. */ + GPencilUpdateCache *gpl_cache = update_cache_alloc( + gpl_index, + is_layer_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY, + is_layer_update_node ? (bGPDlayer *)data : NULL); + GPencilUpdateCacheNode *gpl_node = (GPencilUpdateCacheNode *)BLI_dlrbTree_add( + root_cache->children, cache_node_compare, cache_node_alloc, cache_node_update, gpl_cache); + + BLI_dlrbTree_linkedlist_sync(root_cache->children); + if (gpl_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_layer_update_node) { + return; + } + + const bool is_frame_update_node = (gps_index == -1); + GPencilUpdateCache *gpf_cache = update_cache_alloc( + gpf_index, + is_frame_update_node ? node_flag : GP_UPDATE_NODE_NO_COPY, + is_frame_update_node ? (bGPDframe *)data : NULL); + GPencilUpdateCacheNode *gpf_node = (GPencilUpdateCacheNode *)BLI_dlrbTree_add( + gpl_node->cache->children, + cache_node_compare, + cache_node_alloc, + cache_node_update, + gpf_cache); + + BLI_dlrbTree_linkedlist_sync(gpl_node->cache->children); + if (gpf_node->cache->flag == GP_UPDATE_NODE_FULL_COPY || is_frame_update_node) { + return; + } + + GPencilUpdateCache *gps_cache = update_cache_alloc(gps_index, node_flag, (bGPDstroke *)data); + BLI_dlrbTree_add( + gpf_node->cache->children, cache_node_compare, cache_node_alloc, cache_node_update, gps_cache); + + BLI_dlrbTree_linkedlist_sync(gpf_node->cache->children); +} + +static void update_cache_node_create( + bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, bool full_copy) +{ + if (gpd == NULL) { + return; + } + + GPencilUpdateCache *root_cache = gpd->runtime.update_cache; + if (root_cache == NULL) { + gpd->runtime.update_cache = update_cache_alloc(0, GP_UPDATE_NODE_NO_COPY, NULL); + root_cache = gpd->runtime.update_cache; + } + + if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) { + /* Entire data-block has to be recaculated, e.g. nothing else needs to be added to the cache. + */ + return; + } + + const int gpl_index = (gpl != NULL) ? BLI_findindex(&gpd->layers, gpl) : -1; + const int gpf_index = (gpl != NULL && gpf != NULL) ? BLI_findindex(&gpl->frames, gpf) : -1; + const int gps_index = (gpf != NULL && gps != NULL) ? BLI_findindex(&gpf->strokes, gps) : -1; + + void *data = gps; + if (!data) { + data = gpf; + } + if (!data) { + data = gpl; + } + if (!data) { + data = gpd; + } + + update_cache_node_create_ex(root_cache, data, gpl_index, gpf_index, gps_index, full_copy); +} + +static void gpencil_traverse_update_cache_ex(GPencilUpdateCache *parent_cache, + GPencilUpdateCacheTraverseSettings *ts, + int depth, + void *user_data) +{ + if (BLI_listbase_is_empty((ListBase *)parent_cache->children)) { + return; + } + + LISTBASE_FOREACH (GPencilUpdateCacheNode *, cache_node, parent_cache->children) { + GPencilUpdateCache *cache = cache_node->cache; + + GPencilUpdateCacheIter_Cb cb = ts->update_cache_cb[depth]; + if (cb != NULL) { + bool skip = cb(cache, user_data); + if (skip) { + continue; + } + } + + gpencil_traverse_update_cache_ex(cache, ts, depth + 1, user_data); + } +} + +/* -------------------------------------------------------------------- */ +/** \name Update Cache API + * + * \{ */ + +GPencilUpdateCache *BKE_gpencil_create_update_cache(void *data, bool full_copy) +{ + return update_cache_alloc( + 0, full_copy ? GP_UPDATE_NODE_FULL_COPY : GP_UPDATE_NODE_LIGHT_COPY, data); +} + +void BKE_gpencil_traverse_update_cache(GPencilUpdateCache *cache, + GPencilUpdateCacheTraverseSettings *ts, + void *user_data) +{ + gpencil_traverse_update_cache_ex(cache, ts, 0, user_data); +} + +void BKE_gpencil_tag_full_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps) +{ + update_cache_node_create(gpd, gpl, gpf, gps, true); +} + +void BKE_gpencil_tag_light_update(bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps) +{ + update_cache_node_create(gpd, gpl, gpf, gps, false); +} + +void BKE_gpencil_free_update_cache(bGPdata *gpd) +{ + GPencilUpdateCache *gpd_cache = gpd->runtime.update_cache; + if (gpd_cache) { + update_cache_free(gpd_cache); + gpd->runtime.update_cache = NULL; + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/hair.cc b/source/blender/blenkernel/intern/hair.cc deleted file mode 100644 index b7ba159f631..00000000000 --- a/source/blender/blenkernel/intern/hair.cc +++ /dev/null @@ -1,435 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup bke - */ - -#include <cmath> -#include <cstring> - -#include "MEM_guardedalloc.h" - -#include "DNA_defaults.h" -#include "DNA_hair_types.h" -#include "DNA_material_types.h" -#include "DNA_object_types.h" - -#include "BLI_listbase.h" -#include "BLI_math_base.h" -#include "BLI_math_vec_types.hh" -#include "BLI_rand.h" -#include "BLI_string.h" -#include "BLI_utildefines.h" - -#include "BKE_anim_data.h" -#include "BKE_customdata.h" -#include "BKE_global.h" -#include "BKE_hair.h" -#include "BKE_idtype.h" -#include "BKE_lib_id.h" -#include "BKE_lib_query.h" -#include "BKE_lib_remap.h" -#include "BKE_main.h" -#include "BKE_modifier.h" -#include "BKE_object.h" - -#include "BLT_translation.h" - -#include "DEG_depsgraph_query.h" - -#include "BLO_read_write.h" - -using blender::float3; - -static const char *HAIR_ATTR_POSITION = "position"; -static const char *HAIR_ATTR_RADIUS = "radius"; - -/* Hair datablock */ - -static void hair_random(Hair *hair); - -static void hair_init_data(ID *id) -{ - Hair *hair = (Hair *)id; - BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(hair, id)); - - MEMCPY_STRUCT_AFTER(hair, DNA_struct_default_get(Hair), id); - - CustomData_reset(&hair->pdata); - CustomData_reset(&hair->cdata); - - CustomData_add_layer_named( - &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_POSITION); - CustomData_add_layer_named( - &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_RADIUS); - CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, nullptr, hair->totcurve); - BKE_hair_update_customdata_pointers(hair); - - hair_random(hair); -} - -static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) -{ - Hair *hair_dst = (Hair *)id_dst; - const Hair *hair_src = (const Hair *)id_src; - hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat)); - - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint); - CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve); - BKE_hair_update_customdata_pointers(hair_dst); - - hair_dst->batch_cache = nullptr; -} - -static void hair_free_data(ID *id) -{ - Hair *hair = (Hair *)id; - BKE_animdata_free(&hair->id, false); - - BKE_hair_batch_cache_free(hair); - - CustomData_free(&hair->pdata, hair->totpoint); - CustomData_free(&hair->cdata, hair->totcurve); - - MEM_SAFE_FREE(hair->mat); -} - -static void hair_foreach_id(ID *id, LibraryForeachIDData *data) -{ - Hair *hair = (Hair *)id; - for (int i = 0; i < hair->totcol; i++) { - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, hair->mat[i], IDWALK_CB_USER); - } -} - -static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address) -{ - Hair *hair = (Hair *)id; - - CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff)); - - /* Write LibData */ - BLO_write_id_struct(writer, Hair, id_address, &hair->id); - BKE_id_blend_write(writer, &hair->id); - - /* Direct data */ - CustomData_blend_write(writer, &hair->pdata, players, hair->totpoint, CD_MASK_ALL, &hair->id); - CustomData_blend_write(writer, &hair->cdata, clayers, hair->totcurve, CD_MASK_ALL, &hair->id); - - BLO_write_pointer_array(writer, hair->totcol, hair->mat); - if (hair->adt) { - BKE_animdata_blend_write(writer, hair->adt); - } - - /* Remove temporary data. */ - if (players && players != players_buff) { - MEM_freeN(players); - } - if (clayers && clayers != clayers_buff) { - MEM_freeN(clayers); - } -} - -static void hair_blend_read_data(BlendDataReader *reader, ID *id) -{ - Hair *hair = (Hair *)id; - BLO_read_data_address(reader, &hair->adt); - BKE_animdata_blend_read_data(reader, hair->adt); - - /* Geometry */ - CustomData_blend_read(reader, &hair->pdata, hair->totpoint); - CustomData_blend_read(reader, &hair->cdata, hair->totcurve); - BKE_hair_update_customdata_pointers(hair); - - /* Materials */ - BLO_read_pointer_array(reader, (void **)&hair->mat); -} - -static void hair_blend_read_lib(BlendLibReader *reader, ID *id) -{ - Hair *hair = (Hair *)id; - for (int a = 0; a < hair->totcol; a++) { - BLO_read_id_address(reader, hair->id.lib, &hair->mat[a]); - } -} - -static void hair_blend_read_expand(BlendExpander *expander, ID *id) -{ - Hair *hair = (Hair *)id; - for (int a = 0; a < hair->totcol; a++) { - BLO_expand(expander, hair->mat[a]); - } -} - -IDTypeInfo IDType_ID_HA = { - /*id_code */ ID_HA, - /*id_filter */ FILTER_ID_HA, - /*main_listbase_index */ INDEX_ID_HA, - /*struct_size */ sizeof(Hair), - /*name */ "Hair", - /*name_plural */ "hairs", - /*translation_context */ BLT_I18NCONTEXT_ID_HAIR, - /*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, - /*asset_type_info */ nullptr, - - /*init_data */ hair_init_data, - /*copy_data */ hair_copy_data, - /*free_data */ hair_free_data, - /*make_local */ nullptr, - /*foreach_id */ hair_foreach_id, - /*foreach_cache */ nullptr, - /*foreach_path */ nullptr, - /*owner_get */ nullptr, - - /*blend_write */ hair_blend_write, - /*blend_read_data */ hair_blend_read_data, - /*blend_read_lib */ hair_blend_read_lib, - /*blend_read_expand */ hair_blend_read_expand, - - /*blend_read_undo_preserve */ nullptr, - - /*lib_override_apply_post */ nullptr, -}; - -static void hair_random(Hair *hair) -{ - const int numpoints = 8; - - hair->totcurve = 500; - hair->totpoint = hair->totcurve * numpoints; - - CustomData_realloc(&hair->pdata, hair->totpoint); - CustomData_realloc(&hair->cdata, hair->totcurve); - BKE_hair_update_customdata_pointers(hair); - - RNG *rng = BLI_rng_new(0); - - for (int i = 0; i < hair->totcurve; i++) { - HairCurve *curve = &hair->curves[i]; - curve->firstpoint = i * numpoints; - curve->numpoints = numpoints; - - float theta = 2.0f * M_PI * BLI_rng_get_float(rng); - float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f); - - float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)}; - normalize_v3(no); - - float co[3]; - copy_v3_v3(co, no); - - float(*curve_co)[3] = hair->co + curve->firstpoint; - float *curve_radius = hair->radius + curve->firstpoint; - for (int key = 0; key < numpoints; key++) { - float t = key / (float)(numpoints - 1); - copy_v3_v3(curve_co[key], co); - curve_radius[key] = 0.02f * (1.0f - t); - - float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f, - 2.0f * BLI_rng_get_float(rng) - 1.0f, - 2.0f * BLI_rng_get_float(rng) - 1.0f}; - add_v3_v3(offset, no); - madd_v3_v3fl(co, offset, 1.0f / numpoints); - } - } - - BLI_rng_free(rng); -} - -void *BKE_hair_add(Main *bmain, const char *name) -{ - Hair *hair = static_cast<Hair *>(BKE_id_new(bmain, ID_HA, name)); - - return hair; -} - -BoundBox *BKE_hair_boundbox_get(Object *ob) -{ - BLI_assert(ob->type == OB_HAIR); - Hair *hair = static_cast<Hair *>(ob->data); - - if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { - return ob->runtime.bb; - } - - if (ob->runtime.bb == nullptr) { - ob->runtime.bb = MEM_cnew<BoundBox>(__func__); - - float min[3], max[3]; - INIT_MINMAX(min, max); - - float(*hair_co)[3] = hair->co; - float *hair_radius = hair->radius; - for (int a = 0; a < hair->totpoint; a++) { - float *co = hair_co[a]; - float radius = (hair_radius) ? hair_radius[a] : 0.0f; - const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius}; - const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius}; - DO_MIN(co_min, min); - DO_MAX(co_max, max); - } - - BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); - } - - return ob->runtime.bb; -} - -void BKE_hair_update_customdata_pointers(Hair *hair) -{ - hair->co = (float(*)[3])CustomData_get_layer_named( - &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION); - hair->radius = (float *)CustomData_get_layer_named( - &hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS); - hair->curves = (HairCurve *)CustomData_get_layer(&hair->cdata, CD_HAIRCURVE); - hair->mapping = (HairMaping *)CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING); -} - -bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer) -{ - return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, HAIR_ATTR_POSITION); -} - -/* Dependency Graph */ - -Hair *BKE_hair_new_for_eval(const Hair *hair_src, int totpoint, int totcurve) -{ - Hair *hair_dst = static_cast<Hair *>(BKE_id_new_nomain(ID_HA, nullptr)); - - STRNCPY(hair_dst->id.name, hair_src->id.name); - hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat)); - hair_dst->totcol = hair_src->totcol; - - hair_dst->totpoint = totpoint; - hair_dst->totcurve = totcurve; - CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint); - CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, CD_CALLOC, totcurve); - BKE_hair_update_customdata_pointers(hair_dst); - - return hair_dst; -} - -Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference) -{ - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - Hair *result = (Hair *)BKE_id_copy_ex(nullptr, &hair_src->id, nullptr, flags); - return result; -} - -static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph, - struct Scene *scene, - Object *object, - Hair *hair_input) -{ - Hair *hair = hair_input; - - /* Modifier evaluation modes. */ - const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; - ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; - const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; - - /* Get effective list of modifiers to execute. Some effects like shape keys - * are added as virtual modifiers before the user created modifiers. */ - VirtualModifierData virtualModifierData; - ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); - - /* Evaluate modifiers. */ - for (; md; md = md->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type)); - - if (!BKE_modifier_is_enabled(scene, md, required_mode)) { - continue; - } - - if ((mti->type == eModifierTypeType_OnlyDeform) && - (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) { - /* Ensure we are not modifying the input. */ - if (hair == hair_input) { - hair = BKE_hair_copy_for_eval(hair, true); - } - - /* Ensure we are not overwriting referenced data. */ - CustomData_duplicate_referenced_layer_named( - &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION, hair->totpoint); - BKE_hair_update_customdata_pointers(hair); - - /* Created deformed coordinates array on demand. */ - mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint); - } - else if (mti->modifyHair) { - /* Ensure we are not modifying the input. */ - if (hair == hair_input) { - hair = BKE_hair_copy_for_eval(hair, true); - } - - Hair *hair_next = mti->modifyHair(md, &mectx, hair); - - if (hair_next && hair_next != hair) { - /* If the modifier returned a new hair, release the old one. */ - if (hair != hair_input) { - BKE_id_free(nullptr, hair); - } - hair = hair_next; - } - } - } - - return hair; -} - -void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object) -{ - /* Free any evaluated data and restore original data. */ - BKE_object_free_derived_caches(object); - - /* Evaluate modifiers. */ - Hair *hair = static_cast<Hair *>(object->data); - Hair *hair_eval = hair_evaluate_modifiers(depsgraph, scene, object, hair); - - /* Assign evaluated object. */ - const bool is_owned = (hair != hair_eval); - BKE_object_eval_assign_data(object, &hair_eval->id, is_owned); -} - -/* Draw Cache */ - -void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = nullptr; -void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = nullptr; - -void BKE_hair_batch_cache_dirty_tag(Hair *hair, int mode) -{ - if (hair->batch_cache) { - BKE_hair_batch_cache_dirty_tag_cb(hair, mode); - } -} - -void BKE_hair_batch_cache_free(Hair *hair) -{ - if (hair->batch_cache) { - BKE_hair_batch_cache_free_cb(hair); - } -} diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c index e6fd6c14d42..98bbd920615 100644 --- a/source/blender/blenkernel/intern/idtype.c +++ b/source/blender/blenkernel/intern/idtype.c @@ -15,9 +15,6 @@ * * The Original Code is Copyright (C) 2005 by the Blender Foundation. * All rights reserved. - * Modifier stack implementation. - * - * BKE_modifier.h contains the function prototypes for this file. */ /** \file @@ -110,7 +107,7 @@ static void id_type_init(void) INIT_TYPE(ID_CF); INIT_TYPE(ID_WS); INIT_TYPE(ID_LP); - INIT_TYPE(ID_HA); + INIT_TYPE(ID_CV); INIT_TYPE(ID_PT); INIT_TYPE(ID_VO); INIT_TYPE(ID_SIM); @@ -237,7 +234,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode) CASE_IDFILTER(CU); CASE_IDFILTER(GD); CASE_IDFILTER(GR); - CASE_IDFILTER(HA); + CASE_IDFILTER(CV); CASE_IDFILTER(IM); CASE_IDFILTER(LA); CASE_IDFILTER(LS); @@ -286,7 +283,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter) CASE_IDFILTER(CU); CASE_IDFILTER(GD); CASE_IDFILTER(GR); - CASE_IDFILTER(HA); + CASE_IDFILTER(CV); CASE_IDFILTER(IM); CASE_IDFILTER(LA); CASE_IDFILTER(LS); @@ -334,7 +331,7 @@ int BKE_idtype_idcode_to_index(const short idcode) CASE_IDINDEX(CU); CASE_IDINDEX(GD); CASE_IDINDEX(GR); - CASE_IDINDEX(HA); + CASE_IDINDEX(CV); CASE_IDINDEX(IM); CASE_IDINDEX(IP); CASE_IDINDEX(KE); @@ -393,7 +390,7 @@ short BKE_idtype_idcode_from_index(const int index) CASE_IDCODE(CU); CASE_IDCODE(GD); CASE_IDCODE(GR); - CASE_IDCODE(HA); + CASE_IDCODE(CV); CASE_IDCODE(IM); CASE_IDCODE(IP); CASE_IDCODE(KE); diff --git a/source/blender/blenkernel/intern/image_partial_update.cc b/source/blender/blenkernel/intern/image_partial_update.cc index 7e187c2014e..876e5276e5a 100644 --- a/source/blender/blenkernel/intern/image_partial_update.cc +++ b/source/blender/blenkernel/intern/image_partial_update.cc @@ -23,8 +23,8 @@ * image that are changed. These areas are organized in chunks. Changes that happen over time are * organized in changesets. * - * A common usecase is to update GPUTexture for drawing where only that part is uploaded that only - * changed. + * A common use case is to update #GPUTexture for drawing where only that part is uploaded that + * only changed. * * Usage: * @@ -273,7 +273,8 @@ struct TileChangeset { const int previous_chunk_len = chunk_dirty_flags_.size(); chunk_dirty_flags_.resize(chunk_len); - /* Fast exit. When the changeset was already empty no need to re-init the chunk_validity. */ + /* Fast exit. When the changeset was already empty no need to + * re-initialize the chunk_validity. */ if (!has_dirty_chunks()) { return; } diff --git a/source/blender/blenkernel/intern/image_partial_update_test.cc b/source/blender/blenkernel/intern/image_partial_update_test.cc index 70aa51f7c98..bf12c27241e 100644 --- a/source/blender/blenkernel/intern/image_partial_update_test.cc +++ b/source/blender/blenkernel/intern/image_partial_update_test.cc @@ -70,7 +70,7 @@ class ImagePartialUpdateTest : public testing::Test { IMB_init(); bmain = BKE_main_new(); - /* Creating an image generates a mem-leak during tests. */ + /* Creating an image generates a memory-leak during tests. */ image = create_test_image(1024, 1024); image_tile = BKE_image_get_tile(image, 0); image_buffer = BKE_image_acquire_ibuf(image, nullptr, nullptr); diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 49a518607f1..6c19c7a328b 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -1918,7 +1918,6 @@ void BKE_library_make_local(Main *bmain, * but complicates slightly the pre-processing of relations between IDs at step 2... */ else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && ELEM(lib, NULL, id->lib) && - !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) && ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) { BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem); id->tag |= LIB_TAG_DOIT; @@ -1982,12 +1981,8 @@ void BKE_library_make_local(Main *bmain, } } else { - /* In this specific case, we do want to make ID local even if it has no local usage yet... - * Note that for objects, we don't want proxy pointers to be cleared yet. This will happen - * down the road in this function. - */ - BKE_lib_id_make_local( - bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); + /* In this specific case, we do want to make ID local even if it has no local usage yet... */ + BKE_lib_id_make_local(bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY); if (id->newid) { if (GS(id->newid->name) == ID_OB) { @@ -2049,62 +2044,6 @@ void BKE_library_make_local(Main *bmain, TIMEIT_VALUE_PRINT(make_local); #endif - /* Step 5: proxy 'remapping' hack. */ - for (LinkNode *it = copied_ids; it; it = it->next) { - ID *id = it->link; - - /* Attempt to re-link copied proxy objects. This allows appending of an entire scene - * from another blend file into this one, even when that blend file contains proxified - * armatures that have local references. Since the proxified object needs to be linked - * (not local), this will only work when the "Localize all" checkbox is disabled. - * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ - if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { - Object *ob = (Object *)id; - Object *ob_new = (Object *)id->newid; - bool is_local = false, is_lib = false; - - /* Proxies only work when the proxified object is linked-in from a library. */ - if (!ID_IS_LINKED(ob->proxy)) { - CLOG_WARN(&LOG, - "proxy object %s will lose its link to %s, because the " - "proxified object is local.", - id->newid->name, - ob->proxy->id.name); - continue; - } - - BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); - - /* We can only switch the proxy'ing to a made-local proxy if it is no longer - * referred to from a library. Not checking for local use; if new local proxy - * was not used locally would be a nasty bug! */ - if (is_local || is_lib) { - CLOG_WARN(&LOG, - "made-local proxy object %s will lose its link to %s, " - "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).", - id->newid->name, - ob->proxy->id.name, - is_local, - is_lib); - } - else { - /* we can switch the proxy'ing from the linked-in to the made-local proxy. - * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that - * was already allocated by object_make_local() (which called BKE_object_copy). */ - ob_new->proxy = ob->proxy; - ob_new->proxy_group = ob->proxy_group; - ob_new->proxy_from = ob->proxy_from; - ob_new->proxy->proxy_from = ob_new; - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; - } - } - } - -#ifdef DEBUG_TIME - printf("Step 5: Proxy 'remapping' hack: Done.\n"); - TIMEIT_VALUE_PRINT(make_local); -#endif - /* This is probably more of a hack than something we should do here, but... * Issue is, the whole copying + remapping done in complex cases above may leave pose-channels * of armatures in complete invalid state (more precisely, the bone pointers of the diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index f4dd67cac28..5db70d85e71 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -265,8 +265,8 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) } for (id = last_remapped_id->next; id; id = id->next) { /* Will tag 'never NULL' users of this ID too. - * Note that we cannot use BKE_libblock_unlink() here, - * since it would ignore indirect (and proxy!) + * + * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect * links, this can lead to nasty crashing here in second, actual deleting loop. * Also, this will also flag users of deleted data that cannot be unlinked * (object using deleted obdata, etc.), so that they also get deleted. */ @@ -315,9 +315,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) } /* Will tag 'never NULL' users of this ID too. - * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect - * (and proxy!) links, this can lead to nasty crashing here in second, - * actual deleting loop. + * + * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect + * links, this can lead to nasty crashing here in second, actual deleting loop. * Also, this will also flag users of deleted data that cannot be unlinked * (object using deleted obdata, etc.), so that they also get deleted. */ BKE_libblock_remap_multiple_locked(bmain, diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 649e7dab5d1..fd8b4721500 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -161,6 +161,8 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f (ID *)src_id; id_us_plus(dst_id->override_library->reference); + dst_id->override_library->hierarchy_root = src_id->override_library->hierarchy_root; + if (do_full_copy) { BLI_duplicatelist(&dst_id->override_library->properties, &src_id->override_library->properties); @@ -211,6 +213,7 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bo } static ID *lib_override_library_create_from(Main *bmain, + Library *owner_library, ID *reference_id, const int lib_id_copy_flags) { @@ -227,6 +230,12 @@ static ID *lib_override_library_create_from(Main *bmain, } id_us_min(local_id); + /* TODO: Handle this properly in LIB_NO_MAIN case as well (i.e. resync case). Or offload to + * generic ID copy code? */ + if ((lib_id_copy_flags & LIB_ID_CREATE_NO_MAIN) == 0) { + local_id->lib = owner_library; + } + BKE_lib_override_library_init(local_id, reference_id); /* NOTE: From liboverride perspective (and RNA one), shape keys are considered as local embedded @@ -281,11 +290,12 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, BLI_assert(reference_id != NULL); BLI_assert(ID_IS_LINKED(reference_id)); - ID *local_id = lib_override_library_create_from(bmain, reference_id, 0); + ID *local_id = lib_override_library_create_from(bmain, NULL, 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. */ local_id->override_library->flag |= IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY; + local_id->override_library->hierarchy_root = local_id; if (do_tagged_remap) { Key *reference_key, *local_key = NULL; @@ -320,9 +330,12 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain, } bool BKE_lib_override_library_create_from_tag(Main *bmain, - const Library *reference_library, + Library *owner_library, + const ID *id_root_reference, const bool do_no_main) { + const Library *reference_library = id_root_reference->lib; + ID *reference_id; bool success = true; @@ -351,7 +364,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, * This requires extra care further down the resync process, * see: #BKE_lib_override_library_resync. */ reference_id->newid = lib_override_library_create_from( - bmain, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0); + bmain, owner_library, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0); if (reference_id->newid == NULL) { success = false; break; @@ -375,6 +388,8 @@ 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) { + ID *hierarchy_root_id = id_root_reference->newid; + for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) { reference_id = todo_id_iter->data; ID *local_id = reference_id->newid; @@ -383,6 +398,8 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain, continue; } + local_id->override_library->hierarchy_root = hierarchy_root_id; + Key *reference_key, *local_key = NULL; if ((reference_key = BKE_key_from_id(reference_id)) != NULL) { local_key = BKE_key_from_id(reference_id->newid); @@ -451,6 +468,7 @@ typedef struct LibOverrideGroupTagData { Main *bmain; Scene *scene; ID *id_root; + ID *hierarchy_root_id; uint tag; uint missing_tag; /* Whether we are looping on override data, or their references (linked) one. */ @@ -761,6 +779,8 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData * BLI_assert(ID_IS_OVERRIDE_LIBRARY(id_owner)); BLI_assert(data->is_override); + ID *id_hierarchy_root = data->hierarchy_root_id; + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_owner) && (id_owner->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) != 0) { return; @@ -792,9 +812,15 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData * if (ELEM(to_id, NULL, id_owner)) { continue; } + /* Different libraries or different hierarchy roots are break points in override hierarchies. + */ if (!ID_IS_OVERRIDE_LIBRARY(to_id) || (to_id->lib != id_owner->lib)) { continue; } + if (ID_IS_OVERRIDE_LIBRARY_REAL(to_id) && + to_id->override_library->hierarchy_root != id_hierarchy_root) { + continue; + } Library *reference_lib = lib_override_get(bmain, id_owner)->reference->lib; ID *to_id_reference = lib_override_get(bmain, to_id)->reference; @@ -824,6 +850,11 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data) BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root)); BLI_assert(data->is_override); + ID *id_hierarchy_root = data->hierarchy_root_id; + BLI_assert(id_hierarchy_root != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root)); + UNUSED_VARS_NDEBUG(id_hierarchy_root); + if (id_root->override_library->reference->tag & LIB_TAG_MISSING) { id_root->tag |= data->missing_tag; } @@ -835,7 +866,10 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data) lib_override_overrides_group_tag_recursive(data); } -static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_root) +static bool lib_override_library_create_do(Main *bmain, + Scene *scene, + Library *owner_library, + ID *id_root) { BKE_main_relations_create(bmain, 0); LibOverrideGroupTagData data = {.bmain = bmain, @@ -854,12 +888,16 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo BKE_main_relations_free(bmain); lib_override_group_tag_data_clear(&data); - return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false); + const bool success = BKE_lib_override_library_create_from_tag( + bmain, owner_library, id_root, false); + + return success; } static void lib_override_library_create_post_process(Main *bmain, Scene *scene, ViewLayer *view_layer, + const Library *owner_library, ID *id_root, ID *id_reference, Collection *residual_storage, @@ -881,7 +919,8 @@ static void lib_override_library_create_post_process(Main *bmain, /* 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 && !ID_IS_LINKED(id_root->newid)) { + if (!is_resync && id_root != NULL && id_root->newid != NULL && + (!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) { switch (GS(id_root->name)) { case ID_GR: { Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ? @@ -926,7 +965,7 @@ 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)) { + if (ob_new == NULL || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) { continue; } @@ -989,6 +1028,7 @@ static void lib_override_library_create_post_process(Main *bmain, bool BKE_lib_override_library_create(Main *bmain, Scene *scene, ViewLayer *view_layer, + Library *owner_library, ID *id_root, ID *id_reference, ID **r_id_root_override) @@ -997,7 +1037,7 @@ bool BKE_lib_override_library_create(Main *bmain, *r_id_root_override = NULL; } - const bool success = lib_override_library_create_do(bmain, scene, id_root); + const bool success = lib_override_library_create_do(bmain, scene, owner_library, id_root); if (!success) { return success; @@ -1008,7 +1048,7 @@ bool BKE_lib_override_library_create(Main *bmain, } lib_override_library_create_post_process( - bmain, scene, view_layer, id_root, id_reference, NULL, false); + bmain, scene, view_layer, owner_library, id_root, id_reference, NULL, false); /* Cleanup. */ BKE_main_id_newptr_and_tag_clear(bmain); @@ -1033,120 +1073,187 @@ bool BKE_lib_override_library_template_create(struct ID *id) return true; } -bool BKE_lib_override_library_proxy_convert(Main *bmain, - Scene *scene, - ViewLayer *view_layer, - Object *ob_proxy) +static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int *r_best_level) { - /* `proxy_group`, if defined, is the empty instantiating the collection from which the proxy is - * coming. */ - Object *ob_proxy_group = ob_proxy->proxy_group; - const bool is_override_instancing_object = ob_proxy_group != NULL; - ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id : - &ob_proxy->proxy->id; - ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id; + if (curr_level > 1000) { + CLOG_ERROR(&LOG, + "Levels of dependency relationships between library overrides IDs is way too high, " + "skipping further processing loops (involves at least '%s')", + id->name); + BLI_assert(0); + return NULL; + } - /* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not - * sure this is a valid state, but for now just abort the overriding process. */ - if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) { - return false; + if (!ID_IS_OVERRIDE_LIBRARY(id)) { + BLI_assert(0); + return NULL; } - /* We manually convert the proxy object into a library override, further override handling will - * then be handled by `BKE_lib_override_library_create()` just as for a regular override - * creation. - */ - ob_proxy->proxy->id.tag |= LIB_TAG_DOIT; - ob_proxy->proxy->id.newid = &ob_proxy->id; - BKE_lib_override_library_init(&ob_proxy->id, &ob_proxy->proxy->id); + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); + BLI_assert(entry != NULL); - ob_proxy->proxy->proxy_from = NULL; - ob_proxy->proxy = ob_proxy->proxy_group = NULL; + int best_level_candidate = curr_level; + ID *best_root_id_candidate = id; - DEG_id_tag_update(&ob_proxy->id, ID_RECALC_COPY_ON_WRITE); + for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL; + 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. */ + continue; + } + + ID *from_id = from_id_entry->id_pointer.from; + if (ELEM(from_id, NULL, id)) { + continue; + } + if (!ID_IS_OVERRIDE_LIBRARY(from_id) || (from_id->lib != id->lib)) { + continue; + } - /* In case of proxy conversion, remap all local ID usages to linked IDs to their newly created - * overrides. - * While this might not be 100% the desired behavior, it is likely to be the case most of the - * time. Ref: T91711. */ - ID *id_iter; - FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { - if (!ID_IS_LINKED(id_iter)) { - id_iter->tag |= LIB_TAG_DOIT; + int level_candidate = curr_level + 1; + /* 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) { + best_root_id_candidate = root_id_candidate; + best_level_candidate = level_candidate; } } - FOREACH_MAIN_ID_END; - return BKE_lib_override_library_create(bmain, scene, view_layer, id_root, id_reference, NULL); + *r_best_level = best_level_candidate; + return best_root_id_candidate; } -static void lib_override_library_proxy_convert_do(Main *bmain, - Scene *scene, - Object *ob_proxy, - BlendFileReadReport *reports) +static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID *id_from) { - Object *ob_proxy_group = ob_proxy->proxy_group; - const bool is_override_instancing_object = ob_proxy_group != NULL; + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + if (id->override_library->hierarchy_root == id_root) { + /* Already set, nothing else to do here, sub-hierarchy is also assumed to be properly set + * then. */ + return; + } - const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, NULL, ob_proxy); + /* Hierarchy root already set, and not matching currently proposed one, try to find which is + * best. */ + if (id->override_library->hierarchy_root != NULL) { + /* 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)) { + /* Too complicated to deal with for now. */ + CLOG_WARN(&LOG, + "Inconsistency in library override hierarchy of ID '%s'.\n" + "\tNot enough data to verify validity of current proposed root '%s', assuming " + "already set one '%s' is valid.", + id->name, + id_root->name, + id->override_library->hierarchy_root->name); + return; + } - if (success) { - CLOG_INFO(&LOG, - 4, - "Proxy object '%s' successfully converted to library overrides", - ob_proxy->id.name); - /* Remove the instance empty from this scene, the items now have an overridden collection - * instead. */ - if (is_override_instancing_object) { - BKE_scene_collections_object_remove(bmain, scene, ob_proxy_group, true); - } - reports->count.proxies_to_lib_overrides_success++; - } -} + 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); -void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports) -{ - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - LinkNodePair proxy_objects = {NULL}; + bool do_replace_root = false; + for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL; + 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. */ + continue; + } - FOREACH_SCENE_OBJECT_BEGIN (scene, object) { - if (object->proxy_group != NULL) { - BLI_linklist_append(&proxy_objects, object); + if (id_from_ref == from_id_entry->id_pointer.from) { + /* A matching parent was found in reference linked data, assume given hierarchy root is + * the valid one. */ + do_replace_root = true; + CLOG_WARN( + &LOG, + "Inconsistency in library override hierarchy of ID '%s'.\n" + "\tCurrent proposed root '%s' detected as valid, will replace already set one '%s'.", + id->name, + id_root->name, + id->override_library->hierarchy_root->name); + break; + } } - } - FOREACH_SCENE_OBJECT_END; - FOREACH_SCENE_OBJECT_BEGIN (scene, object) { - if (object->proxy != NULL && object->proxy_group == NULL) { - BLI_linklist_append(&proxy_objects, object); + if (!do_replace_root) { + CLOG_WARN( + &LOG, + "Inconsistency in library override hierarchy of ID '%s'.\n" + "\tCurrent proposed root '%s' not detected as valid, keeping already set one '%s'.", + id->name, + id_root->name, + id->override_library->hierarchy_root->name); + return; } } - FOREACH_SCENE_OBJECT_END; - for (LinkNode *proxy_object_iter = proxy_objects.list; proxy_object_iter != NULL; - proxy_object_iter = proxy_object_iter->next) { - Object *proxy_object = proxy_object_iter->link; - lib_override_library_proxy_convert_do(bmain, scene, proxy_object, reports); + id->override_library->hierarchy_root = id_root; + } + + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); + BLI_assert(entry != NULL); + + for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL; + 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. */ + continue; + } + + ID *to_id = *to_id_entry->id_pointer.to; + if (ELEM(to_id, NULL, id)) { + continue; + } + if (!ID_IS_OVERRIDE_LIBRARY(to_id) || (to_id->lib != id->lib)) { + continue; } - BLI_linklist_free(proxy_objects.list, NULL); + /* Recursively process the sub-hierarchy. */ + lib_override_root_hierarchy_set(bmain, id_root, to_id, id); } +} - LISTBASE_FOREACH (Object *, object, &bmain->objects) { - if (ID_IS_LINKED(object)) { - if (object->proxy != NULL) { - CLOG_WARN(&LOG, "Did not try to convert linked proxy object '%s'", object->id.name); - reports->count.linked_proxies++; - } +void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) +{ + ID *id; + + BKE_main_relations_create(bmain, 0); + + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { continue; } + if (id->override_library->hierarchy_root != NULL) { + continue; + } + + int best_level = 0; + ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level); - if (object->proxy_group != NULL || object->proxy != NULL) { - CLOG_WARN( - &LOG, "Proxy object '%s' failed to be converted to library override", object->id.name); - reports->count.proxies_to_lib_overrides_failures++; + if (!ELEM(id_root->override_library->hierarchy_root, id_root, NULL)) { + 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'", + id->name, + id_root->name, + id_root->override_library->hierarchy_root->name); + continue; } + + lib_override_root_hierarchy_set(bmain, id_root, id_root, NULL); + + BLI_assert(id->override_library->hierarchy_root != NULL); } + FOREACH_MAIN_ID_END; + + BKE_main_relations_free(bmain); } static void lib_override_library_remap(Main *bmain, @@ -1214,6 +1321,7 @@ static bool lib_override_library_resync(Main *bmain, 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, @@ -1316,7 +1424,7 @@ static bool lib_override_library_resync(Main *bmain, * override IDs (including within the old overrides themselves, since those are tagged too * above). */ const bool success = BKE_lib_override_library_create_from_tag( - bmain, id_root_reference->lib, true); + bmain, NULL, id_root_reference, true); if (!success) { return success; @@ -1530,6 +1638,7 @@ static bool lib_override_library_resync(Main *bmain, lib_override_library_create_post_process(bmain, scene, view_layer, + NULL, id_root_reference, id_root, override_resync_residual_storage, @@ -1634,46 +1743,20 @@ static void lib_override_resync_tagging_finalize_recurse(Main *bmain, * * NOTE: Related to `lib_override_resync_tagging_finalize` above. */ -static ID *lib_override_library_main_resync_find_root_recurse(ID *id, int *level) -{ - (*level)++; - ID *return_id = id; - - switch (GS(id->name)) { - case ID_GR: { - /* Find the highest valid collection in the parenting hierarchy. - * Note that in practice, in any decent common case there is only one well defined root - * collection anyway. */ - int max_level = *level; - Collection *collection = (Collection *)id; - LISTBASE_FOREACH (CollectionParent *, collection_parent_iter, &collection->parents) { - Collection *collection_parent = collection_parent_iter->collection; - if (ID_IS_OVERRIDE_LIBRARY_REAL(collection_parent) && - collection_parent->id.lib == id->lib) { - int tmp_level = *level; - ID *tmp_id = lib_override_library_main_resync_find_root_recurse(&collection_parent->id, - &tmp_level); - if (tmp_level > max_level) { - max_level = tmp_level; - return_id = tmp_id; - } - } - } - break; - } - case ID_OB: { - Object *object = (Object *)id; - if (object->parent != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(object->parent) && - object->parent->id.lib == id->lib) { - return_id = lib_override_library_main_resync_find_root_recurse(&object->parent->id, level); - } - break; +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) { + id = id_type->owner_get(bmain, id); } - default: - break; + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id)); } - return return_id; + ID *hierarchy_root_id = id->override_library->hierarchy_root; + BLI_assert(hierarchy_root_id != NULL); + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(hierarchy_root_id)); + return hierarchy_root_id; } /* Ensure resync of all overrides at one level of indirect usage. @@ -1815,14 +1898,13 @@ static void lib_override_library_main_resync_on_library_indirect_level( Library *library = id->lib; - int level = 0; /* In complex non-supported cases, with several different override hierarchies sharing * relations between each-other, we may end up not actually updating/replacing the given * root id (see e.g. pro/shots/110_rextoria/110_0150_A/110_0150_A.anim.blend of sprites * project repository, r2687). * This can lead to infinite loop here, at least avoid this. */ id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; - id = lib_override_library_main_resync_find_root_recurse(id, &level); + id = lib_override_library_main_resync_root_get(bmain, id); id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id)); BLI_assert(id->lib == library); @@ -1954,7 +2036,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, override_resync_residual_storage, true); + bmain, scene, view_layer, NULL, NULL, NULL, override_resync_residual_storage, true); if (BKE_collection_is_empty(override_resync_residual_storage)) { BKE_collection_delete(bmain, override_resync_residual_storage, true); @@ -1980,6 +2062,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root) 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, diff --git a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c new file mode 100644 index 00000000000..d99a9b57a6e --- /dev/null +++ b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c @@ -0,0 +1,176 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "CLG_log.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_linklist.h" + +/* Required for proxy to liboverrides conversion code. */ +#define DNA_DEPRECATED_ALLOW + +#include "DNA_ID.h" +#include "DNA_collection_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "DEG_depsgraph.h" + +#include "BKE_collection.h" +#include "BKE_idtype.h" +#include "BKE_lib_id.h" +#include "BKE_lib_override.h" +#include "BKE_main.h" + +#include "BLO_readfile.h" + +static CLG_LogRef LOG = {"bke.liboverride_proxy_conversion"}; + +bool BKE_lib_override_library_proxy_convert(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + Object *ob_proxy) +{ + /* `proxy_group`, if defined, is the empty instantiating the collection from which the proxy is + * coming. */ + Object *ob_proxy_group = ob_proxy->proxy_group; + const bool is_override_instancing_object = ob_proxy_group != NULL; + ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id : + &ob_proxy->proxy->id; + ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id; + + /* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not + * sure this is a valid state, but for now just abort the overriding process. */ + if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_root)) { + if (ob_proxy->proxy != NULL) { + ob_proxy->proxy->proxy_from = NULL; + } + id_us_min((ID *)ob_proxy->proxy); + ob_proxy->proxy = ob_proxy->proxy_group = NULL; + return false; + } + + /* We manually convert the proxy object into a library override, further override handling will + * then be handled by `BKE_lib_override_library_create()` just as for a regular override + * creation. + */ + ob_proxy->proxy->id.tag |= LIB_TAG_DOIT; + ob_proxy->proxy->id.newid = &ob_proxy->id; + BKE_lib_override_library_init(&ob_proxy->id, &ob_proxy->proxy->id); + + ob_proxy->proxy->proxy_from = NULL; + ob_proxy->proxy = ob_proxy->proxy_group = NULL; + + DEG_id_tag_update(&ob_proxy->id, ID_RECALC_COPY_ON_WRITE); + + /* In case of proxy conversion, remap all local ID usages to linked IDs to their newly created + * overrides. Also do that for the IDs from the same lib as the proxy in case it is linked. + * While this might not be 100% the desired behavior, it is likely to be the case most of the + * time. Ref: T91711. */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (!ID_IS_LINKED(id_iter) || id_iter->lib == ob_proxy->id.lib) { + id_iter->tag |= LIB_TAG_DOIT; + } + } + FOREACH_MAIN_ID_END; + + return BKE_lib_override_library_create( + bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_reference, NULL); +} + +static void lib_override_library_proxy_convert_do(Main *bmain, + Scene *scene, + Object *ob_proxy, + BlendFileReadReport *reports) +{ + Object *ob_proxy_group = ob_proxy->proxy_group; + const bool is_override_instancing_object = ob_proxy_group != NULL; + + const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, NULL, ob_proxy); + + if (success) { + CLOG_INFO(&LOG, + 4, + "Proxy object '%s' successfully converted to library overrides", + ob_proxy->id.name); + /* Remove the instance empty from this scene, the items now have an overridden collection + * instead. */ + if (is_override_instancing_object) { + BKE_scene_collections_object_remove(bmain, scene, ob_proxy_group, true); + } + reports->count.proxies_to_lib_overrides_success++; + } +} + +void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports) +{ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LinkNodePair proxy_objects = {NULL}; + + FOREACH_SCENE_OBJECT_BEGIN (scene, object) { + if (object->proxy_group != NULL) { + BLI_linklist_append(&proxy_objects, object); + } + } + FOREACH_SCENE_OBJECT_END; + + FOREACH_SCENE_OBJECT_BEGIN (scene, object) { + if (object->proxy != NULL && object->proxy_group == NULL) { + BLI_linklist_append(&proxy_objects, object); + } + } + FOREACH_SCENE_OBJECT_END; + + for (LinkNode *proxy_object_iter = proxy_objects.list; proxy_object_iter != NULL; + proxy_object_iter = proxy_object_iter->next) { + Object *proxy_object = proxy_object_iter->link; + lib_override_library_proxy_convert_do(bmain, scene, proxy_object, reports); + } + + BLI_linklist_free(proxy_objects.list, NULL); + } + + LISTBASE_FOREACH (Object *, object, &bmain->objects) { + if (object->proxy_group != NULL || object->proxy != NULL) { + if (ID_IS_LINKED(object)) { + CLOG_WARN(&LOG, + "Linked proxy object '%s' from '%s' failed to be converted to library override", + object->id.name + 2, + object->id.lib->filepath); + } + else { + CLOG_WARN(&LOG, + "Proxy object '%s' failed to be converted to library override", + object->id.name + 2); + } + reports->count.proxies_to_lib_overrides_failures++; + if (object->proxy != NULL) { + object->proxy->proxy_from = NULL; + } + id_us_min((ID *)object->proxy); + object->proxy = object->proxy_group = NULL; + } + } +} diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 1f20a84098c..f49af9abffe 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -323,6 +323,8 @@ static bool library_foreach_ID_link(Main *bmain, IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE); CALLBACK_INVOKE_ID(id->override_library->storage, IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE); + + CALLBACK_INVOKE_ID(id->override_library->hierarchy_root, IDWALK_CB_LOOPBACK); } IDP_foreach_property(id->properties, @@ -471,7 +473,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) return ELEM(id_type_used, ID_MA); case ID_WS: return ELEM(id_type_used, ID_SCR, ID_SCE); - case ID_HA: + case ID_CV: return ELEM(id_type_used, ID_MA); case ID_PT: return ELEM(id_type_used, ID_MA); @@ -517,7 +519,7 @@ static int foreach_libblock_id_users_callback(LibraryIDLinkCallbackData *cb_data IDUsersIter *iter = cb_data->user_data; if (*id_p) { - /* 'Loopback' ID pointers (the ugly 'from' ones, Object->proxy_from and Key->from). + /* 'Loopback' ID pointers (the ugly 'from' ones, like Key->from). * Those are not actually ID usage, we can ignore them here. */ if (cb_flag & IDWALK_CB_LOOPBACK) { @@ -768,7 +770,7 @@ static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackD bool *is_changed = cb_data->user_data; if (*id_p) { - /* The infamous 'from' pointers (Key.from, Object.proxy_from, ...). + /* The infamous 'from' pointers (Key.from, ...). * those are not actually ID usage, so we ignore them here. */ if (cb_flag & IDWALK_CB_LOOPBACK) { return IDWALK_RET_NOP; diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index c3ccedb9608..8e375ff16b5 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -91,28 +91,20 @@ enum { ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */ }; -static void foreach_libblock_remap_callback_skip(const ID *id_owner, - ID **id_ptr, +static void foreach_libblock_remap_callback_skip(const ID *UNUSED(id_owner), + ID **UNUSED(id_ptr), IDRemap *id_remap_data, const int cb_flag, const bool is_indirect, const bool is_reference, - const bool is_never_null, - const bool is_obj, + const bool violates_never_null, + const bool UNUSED(is_obj), const bool is_obj_editmode) { if (is_indirect) { id_remap_data->skipped_indirect++; - if (is_obj) { - Object *ob = (Object *)id_owner; - if (ob->data == *id_ptr && ob->proxy != NULL) { - /* And another 'Proudly brought to you by Proxy Hell' hack! - * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */ - id_remap_data->skipped_direct++; - } - } } - else if (is_never_null || is_obj_editmode || is_reference) { + else if (violates_never_null || is_obj_editmode || is_reference) { id_remap_data->skipped_direct++; } else { @@ -135,11 +127,10 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner, IDRemap *id_remap_data, const int cb_flag, const bool is_indirect, - const bool is_never_null, - const bool force_user_refcount, - const bool is_obj_proxy) + const bool violates_never_null, + const bool force_user_refcount) { - if (!is_never_null) { + if (!violates_never_null) { *id_ptr = new_id; DEG_id_tag_update_ex(id_remap_data->bmain, id_self, @@ -170,16 +161,9 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner, /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) * are assumed to be set as needed, that extra user is processed in final handling. */ } - if (!is_indirect || is_obj_proxy) { + if (!is_indirect) { id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; } - /* We need to remap proxy_from pointer of remapped proxy... sigh. */ - if (is_obj_proxy && new_id != NULL) { - Object *ob = (Object *)id_owner; - if (ob->proxy == (Object *)new_id) { - ob->proxy->proxy_from = ob; - } - } } static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) @@ -221,16 +205,13 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) const bool is_reference = (cb_flag & IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE) != 0; const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0; const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; - /* NOTE: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, - * on the other hand since they get reset to lib data on file open/reload it is indirect too. - * Edit Mode is also a 'skip direct' case. */ const bool is_obj = (GS(id_owner->name) == ID_OB); - const bool is_obj_proxy = (is_obj && - (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group)); + /* NOTE: Edit Mode is a 'skip direct' case, unless specifically requested, obdata should not be + * remapped in this situation. */ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) && (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0); - const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && - (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); + const bool violates_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && + (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0; const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; const bool force_user_refcount = (id_remap_data->flag & ID_REMAP_FORCE_USER_REFCOUNT) != 0; @@ -258,7 +239,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL * (otherwise, we follow common NEVER_NULL flags). * (skipped_indirect too). */ - if ((is_never_null && skip_never_null) || + if ((violates_never_null && skip_never_null) || (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) || (skip_indirect && is_indirect) || (is_reference && skip_reference)) { foreach_libblock_remap_callback_skip(id_owner, @@ -267,7 +248,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) cb_flag, is_indirect, is_reference, - is_never_null, + violates_never_null, is_obj, is_obj_editmode); } @@ -280,9 +261,8 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) id_remap_data, cb_flag, is_indirect, - is_never_null, - force_user_refcount, - is_obj_proxy); + violates_never_null, + force_user_refcount); } return IDWALK_RET_NOP; @@ -430,10 +410,7 @@ static void libblock_remap_data( Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data) { IDRemap id_remap_data; - const int foreach_id_flags = ((remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ? - IDWALK_NO_INDIRECT_PROXY_DATA_USAGE : - IDWALK_NOP) | - ((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ? + const int foreach_id_flags = ((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ? IDWALK_DO_INTERNAL_RUNTIME_POINTERS : IDWALK_NOP); @@ -581,7 +558,7 @@ static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_ case ID_ME: case ID_CU: case ID_MB: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: if (new_id) { /* Only affects us in case obdata was relinked (changed). */ diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c index 64731be57ac..53b1a9c9e16 100644 --- a/source/blender/blenkernel/intern/main.c +++ b/source/blender/blenkernel/intern/main.c @@ -643,8 +643,8 @@ ListBase *which_libbase(Main *bmain, short type) return &(bmain->cachefiles); case ID_WS: return &(bmain->workspaces); - case ID_HA: - return &(bmain->hairs); + case ID_CV: + return &(bmain->hair_curves); case ID_PT: return &(bmain->pointclouds); case ID_VO: @@ -688,7 +688,7 @@ int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/]) lb[INDEX_ID_ME] = &(bmain->meshes); lb[INDEX_ID_CU] = &(bmain->curves); lb[INDEX_ID_MB] = &(bmain->metaballs); - lb[INDEX_ID_HA] = &(bmain->hairs); + lb[INDEX_ID_CV] = &(bmain->hair_curves); lb[INDEX_ID_PT] = &(bmain->pointclouds); lb[INDEX_ID_VO] = &(bmain->volumes); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 15469f910b4..1c1b2c2cd27 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -36,10 +36,10 @@ #include "DNA_anim_types.h" #include "DNA_collection_types.h" #include "DNA_curve_types.h" +#include "DNA_curves_types.h" #include "DNA_customdata_types.h" #include "DNA_defaults.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -341,9 +341,9 @@ Material ***BKE_object_material_array_p(Object *ob) bGPdata *gpd = ob->data; return &(gpd->mat); } - if (ob->type == OB_HAIR) { - Hair *hair = ob->data; - return &(hair->mat); + if (ob->type == OB_CURVES) { + Curves *curves = ob->data; + return &(curves->mat); } if (ob->type == OB_POINTCLOUD) { PointCloud *pointcloud = ob->data; @@ -374,9 +374,9 @@ short *BKE_object_material_len_p(Object *ob) bGPdata *gpd = ob->data; return &(gpd->totcol); } - if (ob->type == OB_HAIR) { - Hair *hair = ob->data; - return &(hair->totcol); + if (ob->type == OB_CURVES) { + Curves *curves = ob->data; + return &(curves->totcol); } if (ob->type == OB_POINTCLOUD) { PointCloud *pointcloud = ob->data; @@ -403,8 +403,8 @@ Material ***BKE_id_material_array_p(ID *id) return &(((MetaBall *)id)->mat); case ID_GD: return &(((bGPdata *)id)->mat); - case ID_HA: - return &(((Hair *)id)->mat); + case ID_CV: + return &(((Curves *)id)->mat); case ID_PT: return &(((PointCloud *)id)->mat); case ID_VO: @@ -429,8 +429,8 @@ short *BKE_id_material_len_p(ID *id) return &(((MetaBall *)id)->totcol); case ID_GD: return &(((bGPdata *)id)->totcol); - case ID_HA: - return &(((Hair *)id)->totcol); + case ID_CV: + return &(((Curves *)id)->totcol); case ID_PT: return &(((PointCloud *)id)->totcol); case ID_VO: @@ -454,7 +454,7 @@ static void material_data_index_remove_id(ID *id, short index) BKE_curve_material_index_remove((Curve *)id, index); break; case ID_MB: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: /* No material indices for these object data types. */ @@ -509,7 +509,7 @@ static void material_data_index_clear_id(ID *id) BKE_curve_material_index_clear((Curve *)id); break; case ID_MB: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: /* No material indices for these object data types. */ diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index ac6b0a04def..3c5cdb1ba78 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -15,6 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. + */ + +/** \file + * \ingroup bke + * * MetaBalls are created from a single Object (with a name without number in it), * here the DispList and BoundBox also is located. * All objects with the same name (but with a number in it) are added to this. @@ -22,10 +27,6 @@ * texture coordinates are patched within the displist */ -/** \file - * \ingroup bke - */ - #include <ctype.h> #include <float.h> #include <math.h> diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 73fe279552d..c1b1f62a881 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -685,6 +685,17 @@ static int customdata_compare( } break; } + case CD_PROP_INT8: { + const int8_t *l1_data = (int8_t *)l1->data; + const int8_t *l2_data = (int8_t *)l2->data; + + for (int i = 0; i < total_length; i++) { + if (l1_data[i] != l2_data[i]) { + return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; + } + } + break; + } case CD_PROP_BOOL: { const bool *l1_data = (bool *)l1->data; const bool *l2_data = (bool *)l2->data; diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc index 50db1bc1564..d0a57310fcf 100644 --- a/source/blender/blenkernel/intern/mesh_fair.cc +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -12,13 +12,12 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": - * https://github.com/fedackb/mesh-fairing. */ /** \file * \ingroup bke + * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": + * https://github.com/fedackb/mesh-fairing. */ #include "BLI_map.hh" diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c index 3f2d81b6dc2..4fb03c7b329 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.c +++ b/source/blender/blenkernel/intern/mesh_iterators.c @@ -34,7 +34,7 @@ #include "MEM_guardedalloc.h" -/* General note on iterating vers/loops/edges/polys and end mode. +/* General note on iterating verts/loops/edges/polys and end mode. * * The edit mesh pointer is set for both final and cage meshes in both cases when there are * modifiers applied and not. This helps consistency of checks in the draw manager, where the diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c index 134a1344f83..3c01d5a4a50 100644 --- a/source/blender/blenkernel/intern/mesh_merge.c +++ b/source/blender/blenkernel/intern/mesh_merge.c @@ -27,6 +27,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BLI_bitmap.h" #include "BLI_edgehash.h" #include "BLI_ghash.h" #include "BLI_utildefines.h" @@ -351,6 +352,8 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh, &poly_map, &poly_map_mem, mesh->mpoly, mesh->mloop, totvert, totpoly, totloop); } /* done preparing for fast poly compare */ + BLI_bitmap *vert_tag = BLI_BITMAP_NEW(mesh->totvert, __func__); + mp = mesh->mpoly; mv = mesh->mvert; for (i = 0; i < totpoly; i++, mp++) { @@ -365,11 +368,11 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh, if (vtargetmap[ml->v] == -1) { all_vertices_merged = false; /* This will be used to check for poly using several time the same vert. */ - mv[ml->v].flag &= ~ME_VERT_TMP_TAG; + BLI_BITMAP_DISABLE(vert_tag, ml->v); } else { /* This will be used to check for poly using several time the same vert. */ - mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG; + BLI_BITMAP_DISABLE(vert_tag, vtargetmap[ml->v]); } } @@ -457,8 +460,8 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh, #endif /* A loop is only valid if its matching edge is, * and it's not reusing a vertex already used by this poly. */ - if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) { - mv[mlv].flag |= ME_VERT_TMP_TAG; + if (LIKELY((newe[ml->e] != -1) && !BLI_BITMAP_TEST(vert_tag, mlv))) { + BLI_BITMAP_ENABLE(vert_tag, mlv); if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) { /* We need to create a new edge between last valid loop and this one! */ @@ -644,6 +647,8 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh, MEM_freeN(oldl); MEM_freeN(oldp); + MEM_freeN(vert_tag); + BLI_edgehash_free(ehash, NULL); if (poly_map != NULL) { diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 005c916b4e0..a5ba2767301 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -28,6 +28,7 @@ #include "CLG_log.h" +#include "BLI_bitmap.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -560,6 +561,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, * so be sure to leave at most one poly per loop! */ { + BLI_bitmap *vert_tag = BLI_BITMAP_NEW(mesh->totvert, __func__); + SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys"); SortPoly *prev_sp, *sp = sort_polys; int prev_end; @@ -608,7 +611,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, * so we have to ensure here all verts of current poly are cleared. */ for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) { if (ml->v < totvert) { - mverts[ml->v].flag &= ~ME_VERT_TMP_TAG; + BLI_BITMAP_DISABLE(vert_tag, ml->v); } } @@ -619,12 +622,12 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, PRINT_ERR("\tLoop %u has invalid vert reference (%u)", sp->loopstart + j, ml->v); sp->invalid = true; } - else if (mverts[ml->v].flag & ME_VERT_TMP_TAG) { + else if (BLI_BITMAP_TEST(vert_tag, ml->v)) { PRINT_ERR("\tPoly %u has duplicated vert reference at corner (%u)", i, j); sp->invalid = true; } else { - mverts[ml->v].flag |= ME_VERT_TMP_TAG; + BLI_BITMAP_ENABLE(vert_tag, ml->v); } *v = ml->v; } @@ -698,6 +701,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, } } + MEM_freeN(vert_tag); + /* Second check pass, testing polys using the same verts. */ qsort(sort_polys, totpoly, sizeof(SortPoly), search_poly_cmp); sp = prev_sp = sort_polys; diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 4f170535d18..4cedaff7c00 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -15,13 +15,12 @@ * * The Original Code is Copyright (C) 2005 by the Blender Foundation. * All rights reserved. - * Modifier stack implementation. - * - * BKE_modifier.h contains the function prototypes for this file. */ /** \file * \ingroup bke + * Modifier stack implementation. + * BKE_modifier.h contains the function prototypes for this file. */ /* Allow using deprecated functionality for .blend file I/O. */ @@ -1188,8 +1187,8 @@ void BKE_modifier_blend_write(BlendWriter *writer, ListBase *modbase) #if 0 CollisionModifierData *collmd = (CollisionModifierData *)md; - // TODO: CollisionModifier should use pointcache - // + have proper reset events before enabling this + /* TODO: CollisionModifier should use pointcache + * + have proper reset events before enabling this. */ writestruct(wd, DATA, MVert, collmd->numverts, collmd->x); writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew); writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces); diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 40d0c24c9af..a1c10a733ce 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -648,7 +648,6 @@ static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_addres bNodeTree *ntree = (bNodeTree *)id; /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - ntree->init = 0; /* to set callbacks and force setting types */ ntree->is_updating = false; ntree->typeinfo = nullptr; ntree->interface_type = nullptr; @@ -677,7 +676,6 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) { /* NOTE: writing and reading goes in sync, for speed. */ - ntree->init = 0; /* to set callbacks and force setting types */ ntree->is_updating = false; ntree->typeinfo = nullptr; ntree->interface_type = nullptr; @@ -1145,8 +1143,6 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) } else { ntree->typeinfo = &NodeTreeTypeUndefined; - - ntree->init &= ~NTREE_TYPE_INIT; } /* Deprecated integer type. */ @@ -1177,8 +1173,6 @@ static void node_set_typeinfo(const struct bContext *C, } else { node->typeinfo = &NodeTypeUndefined; - - ntree->init &= ~NTREE_TYPE_INIT; } } @@ -1199,8 +1193,6 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, } else { sock->typeinfo = &NodeSocketTypeUndefined; - - ntree->init &= ~NTREE_TYPE_INIT; } BKE_ntree_update_tag_socket_type(ntree, sock); } @@ -1218,8 +1210,6 @@ static void update_typeinfo(Main *bmain, } FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - ntree->init |= NTREE_TYPE_INIT; - if (treetype && STREQ(ntree->idname, treetype->idname)) { ntree_set_typeinfo(ntree, unregister ? nullptr : treetype); } @@ -1260,8 +1250,6 @@ static void update_typeinfo(Main *bmain, void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree) { - ntree->init |= NTREE_TYPE_INIT; - ntree_set_typeinfo(ntree, ntreeTypeFind(ntree->idname)); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -2674,11 +2662,6 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) ntree->id.flag |= LIB_EMBEDDED_DATA; } - /* Types are fully initialized at this point, - * if an undefined node is added later this will be reset. - */ - ntree->init |= NTREE_TYPE_INIT; - BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname)); ntree_set_typeinfo(ntree, ntreeTypeFind(idname)); @@ -4503,6 +4486,8 @@ static void registerCompositNodes() register_node_type_cmp_sepycca(); register_node_type_cmp_combycca(); register_node_type_cmp_premulkey(); + register_node_type_cmp_separate_xyz(); + register_node_type_cmp_combine_xyz(); register_node_type_cmp_diff_matte(); register_node_type_cmp_distance_matte(); diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index f9484205ef6..8faae6efb26 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -89,6 +89,7 @@ #include "BKE_constraint.h" #include "BKE_crazyspace.h" #include "BKE_curve.h" +#include "BKE_curves.h" #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_duplilist.h" @@ -103,7 +104,6 @@ #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" -#include "BKE_hair.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" @@ -325,45 +325,6 @@ static void object_free_data(ID *id) BKE_previewimg_free(&ob->preview); } -static void object_make_local(Main *bmain, ID *id, const int flags) -{ - if (!ID_IS_LINKED(id)) { - return; - } - - Object *ob = (Object *)id; - const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0; - const bool clear_proxy = (flags & LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING) == 0; - - bool force_local, force_copy; - BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy); - - if (force_local) { - BKE_lib_id_clear_library_data(bmain, &ob->id, flags); - BKE_lib_id_expand_local(bmain, &ob->id, flags); - if (clear_proxy) { - if (ob->proxy_from != nullptr) { - ob->proxy_from->proxy = nullptr; - ob->proxy_from->proxy_group = nullptr; - } - ob->proxy = ob->proxy_from = ob->proxy_group = nullptr; - } - } - else if (force_copy) { - Object *ob_new = (Object *)BKE_id_copy(bmain, &ob->id); - id_us_min(&ob_new->id); - - ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = nullptr; - - /* setting newid is mandatory for complex make_lib_local logic... */ - ID_NEW_SET(ob, ob_new); - - if (!lib_local) { - BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } -} - static void library_foreach_modifiersForeachIDLink(void *user_data, Object *UNUSED(object), ID **id_pointer, @@ -419,51 +380,25 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) { Object *object = (Object *)id; - /* Object is special, proxies make things hard... */ - const int proxy_cb_flag = ((BKE_lib_query_foreachid_process_flags_get(data) & - IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && - (object->proxy || object->proxy_group)) ? - IDWALK_CB_INDIRECT_USAGE : - 0; - /* object data special case */ if (object->type == OB_EMPTY) { /* empty can have nullptr or Image */ - BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, proxy_cb_flag | IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, IDWALK_CB_USER); } else { /* when set, this can't be nullptr */ if (object->data) { - BKE_LIB_FOREACHID_PROCESS_ID( - data, object->data, proxy_cb_flag | IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); + BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); } } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->parent, IDWALK_CB_NEVER_SELF); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->track, IDWALK_CB_NEVER_SELF); - /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF); - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy_group, IDWALK_CB_NOP); - - /* Special case! - * Since this field is set/owned by 'user' of this ID (and not ID itself), - * it is only indirect usage if proxy object is linked... Twisted. */ - { - const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( - data, - (object->proxy_from != nullptr && ID_IS_LINKED(object->proxy_from)) ? - IDWALK_CB_INDIRECT_USAGE : - 0, - true); - BKE_LIB_FOREACHID_PROCESS_IDSUPER( - data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF); - BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); - } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->poselib, IDWALK_CB_USER); for (int i = 0; i < object->totcol; i++) { - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->mat[i], IDWALK_CB_USER); } /* Note that ob->gpd is deprecated, so no need to handle it here. */ @@ -476,8 +411,6 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) /* Note that ob->effect is deprecated, so no need to handle it here. */ if (object->pose) { - const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( - data, proxy_cb_flag, false); LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( data, @@ -492,7 +425,6 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) BKE_constraints_id_loop( &pchan->constraints, library_foreach_constraintObjectLooper, data)); } - BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); } if (object->rigidbody_constraint) { @@ -627,9 +559,6 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre bArmature *arm = nullptr; if (ob->type == OB_ARMATURE) { arm = (bArmature *)ob->data; - if (arm && ob->pose && arm->act_bone) { - BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone)); - } } BKE_pose_blend_write(writer, ob->pose, arm); @@ -1305,7 +1234,7 @@ IDTypeInfo IDType_ID_OB = { /* init_data */ object_init_data, /* copy_data */ object_copy_data, /* free_data */ object_free_data, - /* make_local */ object_make_local, + /* make_local */ nullptr, /* foreach_id */ object_foreach_id, /* foreach_cache */ nullptr, /* foreach_path */ object_foreach_path, @@ -1486,10 +1415,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) } /* Only geometry objects should be able to get modifiers T25291. */ - if (ob->type == OB_HAIR) { - return (mti->modifyHair != nullptr) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly); - } - if (ELEM(ob->type, OB_POINTCLOUD, OB_VOLUME)) { + if (ELEM(ob->type, OB_POINTCLOUD, OB_VOLUME, OB_CURVES)) { return (mti->modifyGeometrySet != nullptr); } if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { @@ -2172,8 +2098,8 @@ static const char *get_obdata_defname(int type) return DATA_("Armature"); case OB_SPEAKER: return DATA_("Speaker"); - case OB_HAIR: - return DATA_("Hair"); + case OB_CURVES: + return DATA_("HairCurves"); case OB_POINTCLOUD: return DATA_("PointCloud"); case OB_VOLUME: @@ -2247,8 +2173,8 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) return BKE_lightprobe_add(bmain, name); case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name); - case OB_HAIR: - return BKE_hair_add(bmain, name); + case OB_CURVES: + return BKE_curves_add(bmain, name); case OB_POINTCLOUD: return BKE_pointcloud_add_default(bmain, name); case OB_VOLUME: @@ -2285,8 +2211,8 @@ int BKE_object_obdata_to_type(const ID *id) return OB_ARMATURE; case ID_LP: return OB_LIGHTPROBE; - case ID_HA: - return OB_HAIR; + case ID_CV: + return OB_CURVES; case ID_PT: return OB_POINTCLOUD; case ID_VO: @@ -2803,8 +2729,8 @@ Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplica id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags); } break; - case OB_HAIR: - if (dupflag & USER_DUP_HAIR) { + case OB_CURVES: + if (dupflag & USER_DUP_CURVES) { id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags); } break; @@ -2876,161 +2802,6 @@ bool BKE_object_obdata_is_libdata(const Object *ob) return (ob && ob->data && ID_IS_LINKED(ob->data)); } -/* -------------------------------------------------------------------- */ -/** \name Object Proxy API - * \{ */ - -/* when you make proxy, ensure the exposed layers are extern */ -static void armature_set_id_extern(Object *ob) -{ - bArmature *arm = (bArmature *)ob->data; - unsigned int lay = arm->layer_protected; - - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { - if (!(pchan->bone->layer & lay)) { - id_lib_extern((ID *)pchan->custom); - } - } -} - -void BKE_object_copy_proxy_drivers(Object *ob, Object *target) -{ - if ((target->adt) && (target->adt->drivers.first)) { - - /* add new animdata block */ - if (!ob->adt) { - ob->adt = BKE_animdata_ensure_id(&ob->id); - } - - /* make a copy of all the drivers (for now), then correct any links that need fixing */ - BKE_fcurves_free(&ob->adt->drivers); - BKE_fcurves_copy(&ob->adt->drivers, &target->adt->drivers); - - LISTBASE_FOREACH (FCurve *, fcu, &ob->adt->drivers) { - ChannelDriver *driver = fcu->driver; - - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - /* all drivers */ - DRIVER_TARGETS_LOOPER_BEGIN (dvar) { - if (dtar->id) { - if ((Object *)dtar->id == target) { - dtar->id = (ID *)ob; - } - else { - /* only on local objects because this causes indirect links - * 'a -> b -> c', blend to point directly to a.blend - * when a.blend has a proxy that's linked into `c.blend`. */ - if (!ID_IS_LINKED(ob)) { - id_lib_extern((ID *)dtar->id); - } - } - } - } - DRIVER_TARGETS_LOOPER_END; - } - } - } -} - -void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob) -{ - /* paranoia checks */ - if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) { - CLOG_ERROR(&LOG, "cannot make proxy"); - return; - } - - ob->proxy = target; - id_us_plus(&target->id); - ob->proxy_group = cob; - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - DEG_id_tag_update(&target->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - - /* copy transform - * - cob means this proxy comes from a collection, just apply the matrix - * so the object won't move from its dupli-transform. - * - * - no cob means this is being made from a linked object, - * this is closer to making a copy of the object - in-place. */ - if (cob) { - ob->rotmode = target->rotmode; - mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat); - if (cob->instance_collection) { /* should always be true */ - float tvec[3]; - mul_v3_mat3_m4v3(tvec, ob->obmat, cob->instance_collection->instance_offset); - sub_v3_v3(ob->obmat[3], tvec); - } - BKE_object_apply_mat4(ob, ob->obmat, false, true); - } - else { - BKE_object_transform_copy(ob, target); - ob->parent = target->parent; /* libdata */ - copy_m4_m4(ob->parentinv, target->parentinv); - } - - /* copy animdata stuff - drivers only for now... */ - BKE_object_copy_proxy_drivers(ob, target); - - /* skip constraints? */ - /* FIXME: this is considered by many as a bug */ - - /* set object type and link to data */ - ob->type = target->type; - ob->data = target->data; - id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */ - - /* copy material and index information */ - ob->actcol = ob->totcol = 0; - if (ob->mat) { - MEM_freeN(ob->mat); - } - if (ob->matbits) { - MEM_freeN(ob->matbits); - } - ob->mat = nullptr; - ob->matbits = nullptr; - if ((target->totcol) && (target->mat) && OB_TYPE_SUPPORT_MATERIAL(ob->type)) { - int i; - - ob->actcol = target->actcol; - ob->totcol = target->totcol; - - ob->mat = (Material **)MEM_dupallocN(target->mat); - ob->matbits = (char *)MEM_dupallocN(target->matbits); - for (i = 0; i < target->totcol; i++) { - /* don't need to run BKE_object_materials_test - * since we know this object is new and not used elsewhere */ - id_us_plus((ID *)ob->mat[i]); - } - } - - /* type conversions */ - if (target->type == OB_ARMATURE) { - copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */ - BKE_pose_rest(ob->pose, false); /* clear all transforms in channels */ - BKE_pose_rebuild(bmain, ob, (bArmature *)ob->data, true); /* set all internal links */ - - armature_set_id_extern(ob); - } - else if (target->type == OB_EMPTY) { - ob->empty_drawtype = target->empty_drawtype; - ob->empty_drawsize = target->empty_drawsize; - } - - /* copy IDProperties */ - if (ob->id.properties) { - IDP_FreeProperty(ob->id.properties); - ob->id.properties = nullptr; - } - if (target->id.properties) { - ob->id.properties = IDP_CopyProperty(target->id.properties); - } - - /* copy drawtype info */ - ob->dt = target->dt; -} - void BKE_object_obdata_size_init(struct Object *ob, const float size) { /* apply radius as a scale to types that support it */ @@ -3072,8 +2843,6 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size) } } -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Object Matrix Get/Set API * \{ */ @@ -3855,8 +3624,8 @@ BoundBox *BKE_object_boundbox_get(Object *ob) case OB_GPENCIL: bb = BKE_gpencil_boundbox_get(ob); break; - case OB_HAIR: - bb = BKE_hair_boundbox_get(ob); + case OB_CURVES: + bb = BKE_curves_boundbox_get(ob); break; case OB_POINTCLOUD: bb = BKE_pointcloud_boundbox_get(ob); @@ -4057,8 +3826,8 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us } break; } - case OB_HAIR: { - BoundBox bb = *BKE_hair_boundbox_get(ob); + case OB_CURVES: { + BoundBox bb = *BKE_curves_boundbox_get(ob); BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); changed = true; break; @@ -4365,33 +4134,10 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt) /** \name Object Evaluation/Update API * \{ */ -static void object_handle_update_proxy(Depsgraph *depsgraph, - Scene *scene, - Object *object, - const bool do_proxy_update) -{ - /* The case when this is a collection proxy, object_update is called in collection.c */ - if (object->proxy == nullptr) { - return; - } - /* set pointer in library proxy target, for copying, but restore it */ - object->proxy->proxy_from = object; - // printf("set proxy pointer for later collection stuff %s\n", ob->id.name); - - /* the no-group proxy case, we call update */ - if (object->proxy_group == nullptr) { - if (do_proxy_update) { - // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); - BKE_object_handle_update(depsgraph, scene, object->proxy); - } - } -} - void BKE_object_handle_update_ex(Depsgraph *depsgraph, Scene *scene, Object *ob, - RigidBodyWorld *rbw, - const bool do_proxy_update) + RigidBodyWorld *rbw) { const ID *object_data = (ID *)ob->data; const bool recalc_object = (ob->id.recalc & ID_RECALC_ALL) != 0; @@ -4399,7 +4145,6 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph, ((object_data->recalc & ID_RECALC_ALL) != 0) : false; if (!recalc_object && !recalc_data) { - object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update); return; } /* Speed optimization for animation lookups. */ @@ -4428,22 +4173,17 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph, if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { printf("recalcob %s\n", ob->id.name + 2); } - /* Handle proxy copy for target. */ - if (!BKE_object_eval_proxy_copy(depsgraph, ob)) { - BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, nullptr); - } + BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, nullptr); } if (recalc_data) { BKE_object_handle_data_update(depsgraph, scene, ob); } - - object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update); } void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob) { - BKE_object_handle_update_ex(depsgraph, scene, ob, nullptr, true); + BKE_object_handle_update_ex(depsgraph, scene, ob, nullptr); } void BKE_object_sculpt_data_create(Object *ob) @@ -5201,7 +4941,7 @@ bool BKE_object_supports_material_slots(struct Object *ob) OB_SURF, OB_FONT, OB_MBALL, - OB_HAIR, + OB_CURVES, OB_POINTCLOUD, OB_VOLUME, OB_GPENCIL); diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 1a208355870..6352fd19239 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 20014 by Blender Foundation. + * The Original Code is Copyright (C) 2014 by Blender Foundation. * All rights reserved. */ @@ -41,12 +41,12 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_curve.h" +#include "BKE_curves.h" #include "BKE_displist.h" #include "BKE_editmesh.h" #include "BKE_effect.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" -#include "BKE_hair.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -190,16 +190,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o break; } case OB_ARMATURE: - if (ID_IS_LINKED(ob) && ob->proxy_from) { - if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { - printf("Proxy copy error, lib Object: %s proxy Object: %s\n", - ob->id.name + 2, - ob->proxy_from->id.name + 2); - } - } - else { - BKE_pose_where_is(depsgraph, scene, ob); - } + BKE_pose_where_is(depsgraph, scene, ob); break; case OB_MBALL: @@ -223,8 +214,8 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o BKE_gpencil_update_layer_transforms(depsgraph, ob); break; } - case OB_HAIR: - BKE_hair_data_update(depsgraph, scene, ob); + case OB_CURVES: + BKE_curves_data_update(depsgraph, scene, ob); break; case OB_POINTCLOUD: BKE_pointcloud_data_update(depsgraph, scene, ob); @@ -311,33 +302,8 @@ void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object) object_sync_boundbox_to_original(object_orig, object); } -bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph, Object *object) -{ - /* Handle proxy copy for target, */ - if (ID_IS_LINKED(object) && object->proxy_from) { - DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); - if (object->proxy_from->proxy_group) { - /* Transform proxy into group space. */ - Object *obg = object->proxy_from->proxy_group; - float imat[4][4]; - invert_m4_m4(imat, obg->obmat); - mul_m4_m4m4(object->obmat, imat, object->proxy_from->obmat); - /* Should always be true. */ - if (obg->instance_collection) { - add_v3_v3(object->obmat[3], obg->instance_collection->instance_offset); - } - } - else { - copy_m4_m4(object->obmat, object->proxy_from->obmat); - } - return true; - } - return false; -} - -void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object) +void BKE_object_eval_uber_transform(Depsgraph *UNUSED(depsgraph), Object *UNUSED(object)) { - BKE_object_eval_proxy_copy(depsgraph, object); } void BKE_object_data_batch_cache_dirty_tag(ID *object_data) @@ -359,8 +325,8 @@ void BKE_object_data_batch_cache_dirty_tag(ID *object_data) case ID_GD: BKE_gpencil_batch_cache_dirty_tag((struct bGPdata *)object_data); break; - case ID_HA: - BKE_hair_batch_cache_dirty_tag((struct Hair *)object_data, BKE_HAIR_BATCH_DIRTY_ALL); + case ID_CV: + BKE_curves_batch_cache_dirty_tag((struct Curves *)object_data, BKE_CURVES_BATCH_DIRTY_ALL); break; case ID_PT: BKE_pointcloud_batch_cache_dirty_tag((struct PointCloud *)object_data, diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 97326c24a61..dacc24c32da 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -15,13 +15,13 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * Based on original code by Drew Whitehouse / Houdini Ocean Toolkit - * OpenMP hints by Christian Schnellhammer */ /** \file * \ingroup bke + * + * Based on original code by Drew Whitehouse / Houdini Ocean Toolkit + * OpenMP hints by Christian Schnellhammer */ #include <math.h> diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 4dba13ce4c2..aa08a6494d1 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -4640,7 +4640,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, * account when subdividing for instance. */ pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ? NULL : - psys->hair_out_mesh; /* XXX(@sybren) EEK. */ + psys->hair_out_mesh; /* XXX(@sybren): EEK. */ init_particle_interpolation(sim->ob, psys, pa, &pind); do_particle_interpolation(psys, p, pa, t, &pind, state); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index e489f9e2bac..6953ecf38c3 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -13,11 +13,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2007 by Janne Karhu. - * All rights reserved. - * Adaptive time step - * Classical SPH - * Copyright 2011-2012 AutoCRC + * Copyright 2007 Janne Karhu. All rights reserved. + * 2011-2012 AutoCRC (adaptive time step, Classical SPH). */ /** \file diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 9d66c354b54..2f63edebb67 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -580,7 +580,6 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss, #endif MVert *mvert = dm->getVertArray(dm); MEdge *medge = dm->getEdgeArray(dm); - // MFace *mface = dm->getTessFaceArray(dm); /* UNUSED */ MVert *mv; MEdge *me; MLoop *mloop = dm->getLoopArray(dm), *ml; @@ -1129,44 +1128,6 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) } } -static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - int index; - int totface; - int gridSize = ccgSubSurf_getGridSize(ss); - int edgeSize = ccgSubSurf_getEdgeSize(ss); - int i = 0; - DMFlagMat *faceFlags = ccgdm->faceFlags; - - totface = dm->getNumTessFaces(dm); - for (index = 0; index < totface; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - /* keep types in sync with MFace, avoid many conversions */ - char flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH; - short mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0; - - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - MFace *mf = &mface[i]; - mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, edgeSize, gridSize); - mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1, edgeSize, gridSize); - mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize); - mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0, edgeSize, gridSize); - mf->mat_nr = mat_nr; - mf->flag = flag; - mf->edcode = 0; - - i++; - } - } - } - } -} - typedef struct CopyFinalLoopArrayData { CCGDerivedMesh *ccgdm; MLoop *mloop; @@ -1457,63 +1418,6 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type) return DM_get_edge_data_layer(dm, type); } -static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type) -{ - if (type == CD_ORIGINDEX) { - /* create origindex on demand to save memory */ - int *origindex; - - /* Avoid re-creation if the layer exists already */ - origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX); - if (origindex) { - return origindex; - } - - DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); - origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX); - - /* silly loop counting up */ - range_vn_i(origindex, dm->getNumTessFaces(dm), 0); - - return origindex; - } - - if (type == CD_TESSLOOPNORMAL) { - /* Create tessloopnormal on demand to save memory. */ - /* Note that since tessellated face corners are the same a loops in CCGDM, - * and since all faces have four loops/corners, we can simplify the code - * here by converting tessloopnormals from 'short (*)[4][3]' to 'short (*)[3]'. */ - short(*tlnors)[3]; - - /* Avoid re-creation if the layer exists already */ - tlnors = DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL); - if (!tlnors) { - float(*lnors)[3]; - short(*tlnors_it)[3]; - const int numLoops = ccgDM_getNumLoops(dm); - int i; - - lnors = dm->getLoopDataArray(dm, CD_NORMAL); - if (!lnors) { - return NULL; - } - - DM_add_tessface_layer(dm, CD_TESSLOOPNORMAL, CD_CALLOC, NULL); - tlnors = tlnors_it = (short(*)[3])DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL); - - /* With ccgdm, we have a simple one to one mapping between loops - * and tessellated face corners. */ - for (i = 0; i < numLoops; i++, tlnors_it++, lnors++) { - normal_float_to_short_v3(*tlnors_it, *lnors); - } - } - - return tlnors; - } - - return DM_get_tessface_data_layer(dm, type); -} - static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type) { if (type == CD_ORIGINDEX) { @@ -1551,46 +1455,6 @@ static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type) return DM_get_poly_data_layer(dm, type); } -static void *ccgDM_get_vert_data(DerivedMesh *dm, int index, int type) -{ - if (type == CD_ORIGINDEX) { - /* ensure creation of CD_ORIGINDEX layer */ - ccgDM_get_vert_data_layer(dm, type); - } - - return DM_get_vert_data(dm, index, type); -} - -static void *ccgDM_get_edge_data(DerivedMesh *dm, int index, int type) -{ - if (type == CD_ORIGINDEX) { - /* ensure creation of CD_ORIGINDEX layer */ - ccgDM_get_edge_data_layer(dm, type); - } - - return DM_get_edge_data(dm, index, type); -} - -static void *ccgDM_get_tessface_data(DerivedMesh *dm, int index, int type) -{ - if (ELEM(type, CD_ORIGINDEX, CD_TESSLOOPNORMAL)) { - /* ensure creation of CD_ORIGINDEX/CD_TESSLOOPNORMAL layers */ - ccgDM_get_tessface_data_layer(dm, type); - } - - return DM_get_tessface_data(dm, index, type); -} - -static void *ccgDM_get_poly_data(DerivedMesh *dm, int index, int type) -{ - if (type == CD_ORIGINDEX) { - /* ensure creation of CD_ORIGINDEX layer */ - ccgDM_get_tessface_data_layer(dm, type); - } - - return DM_get_poly_data(dm, index, type); -} - static int ccgDM_getNumGrids(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; @@ -1705,25 +1569,6 @@ static BLI_bitmap **ccgDM_getGridHidden(DerivedMesh *dm) return ccgdm->gridHidden; } -static const MeshElemMap *ccgDM_getPolyMap(Object *ob, DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - if (!ccgdm->multires.mmd && !ccgdm->pmap && ob->type == OB_MESH) { - Mesh *me = ob->data; - - BKE_mesh_vert_poly_map_create(&ccgdm->pmap, - &ccgdm->pmap_mem, - me->mpoly, - me->mloop, - me->totvert, - me->totpoly, - me->totloop); - } - - return ccgdm->pmap; -} - /* WARNING! *MUST* be called in an 'loops_cache_rwlock' protected thread context! */ static void ccgDM_recalcLoopTri(DerivedMesh *dm) { @@ -1773,17 +1618,11 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray; ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray; - ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray; ccgdm->dm.copyLoopArray = ccgDM_copyFinalLoopArray; ccgdm->dm.copyPolyArray = ccgDM_copyFinalPolyArray; - ccgdm->dm.getVertData = ccgDM_get_vert_data; - ccgdm->dm.getEdgeData = ccgDM_get_edge_data; - ccgdm->dm.getTessFaceData = ccgDM_get_tessface_data; - ccgdm->dm.getPolyData = ccgDM_get_poly_data; ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer; ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer; - ccgdm->dm.getTessFaceDataArray = ccgDM_get_tessface_data_layer; ccgdm->dm.getPolyDataArray = ccgDM_get_poly_data_layer; ccgdm->dm.getNumGrids = ccgDM_getNumGrids; ccgdm->dm.getGridSize = ccgDM_getGridSize; @@ -1792,7 +1631,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) ccgdm->dm.getGridKey = ccgDM_getGridKey; ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats; ccgdm->dm.getGridHidden = ccgDM_getGridHidden; - ccgdm->dm.getPolyMap = ccgDM_getPolyMap; ccgdm->dm.recalcLoopTri = ccgDM_recalcLoopTri; @@ -1848,7 +1686,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, int index; int i; int vertNum = 0, edgeNum = 0, faceNum = 0; - int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex; + int *vertOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex; short *edgeFlags = ccgdm->edgeFlags; DMFlagMat *faceFlags = ccgdm->faceFlags; int *polyidx = NULL; @@ -1884,7 +1722,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX); edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX); - faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX); polyOrigIndex = DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX); has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0); @@ -2006,12 +1843,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, /* Copy over poly data, e.g. #CD_FACEMAP. */ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1); - /* Set original index data. */ - if (faceOrigIndex) { - /* reference the index in 'polyOrigIndex' */ - *faceOrigIndex = faceNum; - faceOrigIndex++; - } if (polyOrigIndex) { *polyOrigIndex = base_polyOrigIndex ? base_polyOrigIndex[origIndex] : origIndex; polyOrigIndex++; diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc index cb05337ef2a..b2011d2baf7 100644 --- a/source/blender/blenkernel/intern/type_conversions.cc +++ b/source/blender/blenkernel/intern/type_conversions.cc @@ -62,6 +62,11 @@ static bool float_to_bool(const float &a) { return a > 0.0f; } +static int8_t float_to_int8(const float &a) +{ + return std::clamp( + a, float(std::numeric_limits<int8_t>::min()), float(std::numeric_limits<int8_t>::max())); +} static ColorGeometry4f float_to_color(const float &a) { return ColorGeometry4f(a, a, a, 1.0f); @@ -83,6 +88,10 @@ static bool float2_to_bool(const float2 &a) { return !is_zero_v2(a); } +static int8_t float2_to_int8(const float2 &a) +{ + return float_to_int8((a.x + a.y) / 2.0f); +} static ColorGeometry4f float2_to_color(const float2 &a) { return ColorGeometry4f(a.x, a.y, 0.0f, 1.0f); @@ -92,6 +101,10 @@ static bool float3_to_bool(const float3 &a) { return !is_zero_v3(a); } +static int8_t float3_to_int8(const float3 &a) +{ + return float_to_int8((a.x + a.y + a.z) / 3.0f); +} static float float3_to_float(const float3 &a) { return (a.x + a.y + a.z) / 3.0f; @@ -113,6 +126,11 @@ static bool int_to_bool(const int32_t &a) { return a > 0; } +static int8_t int_to_int8(const int32_t &a) +{ + return std::clamp( + a, int(std::numeric_limits<int8_t>::min()), int(std::numeric_limits<int8_t>::max())); +} static float int_to_float(const int32_t &a) { return (float)a; @@ -130,10 +148,39 @@ static ColorGeometry4f int_to_color(const int32_t &a) return ColorGeometry4f((float)a, (float)a, (float)a, 1.0f); } +static bool int8_to_bool(const int8_t &a) +{ + return a > 0; +} +static int int8_to_int(const int8_t &a) +{ + return static_cast<int>(a); +} +static float int8_to_float(const int8_t &a) +{ + return (float)a; +} +static float2 int8_to_float2(const int8_t &a) +{ + return float2((float)a); +} +static float3 int8_to_float3(const int8_t &a) +{ + return float3((float)a); +} +static ColorGeometry4f int8_to_color(const int8_t &a) +{ + return ColorGeometry4f((float)a, (float)a, (float)a, 1.0f); +} + static float bool_to_float(const bool &a) { return (bool)a; } +static int8_t bool_to_int8(const bool &a) +{ + return static_cast<int8_t>(a); +} static int32_t bool_to_int(const bool &a) { return (int32_t)a; @@ -163,6 +210,10 @@ static int32_t color_to_int(const ColorGeometry4f &a) { return (int)rgb_to_grayscale(a); } +static int8_t color_to_int8(const ColorGeometry4f &a) +{ + return int_to_int8(color_to_int(a)); +} static float2 color_to_float2(const ColorGeometry4f &a) { return float2(a.r, a.g); @@ -180,33 +231,46 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion<float, float3, float_to_float3>(conversions); add_implicit_conversion<float, int32_t, float_to_int>(conversions); add_implicit_conversion<float, bool, float_to_bool>(conversions); + add_implicit_conversion<float, int8_t, float_to_int8>(conversions); add_implicit_conversion<float, ColorGeometry4f, float_to_color>(conversions); add_implicit_conversion<float2, float3, float2_to_float3>(conversions); add_implicit_conversion<float2, float, float2_to_float>(conversions); add_implicit_conversion<float2, int32_t, float2_to_int>(conversions); add_implicit_conversion<float2, bool, float2_to_bool>(conversions); + add_implicit_conversion<float2, int8_t, float2_to_int8>(conversions); add_implicit_conversion<float2, ColorGeometry4f, float2_to_color>(conversions); add_implicit_conversion<float3, bool, float3_to_bool>(conversions); + add_implicit_conversion<float3, int8_t, float3_to_int8>(conversions); add_implicit_conversion<float3, float, float3_to_float>(conversions); add_implicit_conversion<float3, int32_t, float3_to_int>(conversions); add_implicit_conversion<float3, float2, float3_to_float2>(conversions); add_implicit_conversion<float3, ColorGeometry4f, float3_to_color>(conversions); add_implicit_conversion<int32_t, bool, int_to_bool>(conversions); + add_implicit_conversion<int32_t, int8_t, int_to_int8>(conversions); add_implicit_conversion<int32_t, float, int_to_float>(conversions); add_implicit_conversion<int32_t, float2, int_to_float2>(conversions); add_implicit_conversion<int32_t, float3, int_to_float3>(conversions); add_implicit_conversion<int32_t, ColorGeometry4f, int_to_color>(conversions); + add_implicit_conversion<int8_t, bool, int8_to_bool>(conversions); + add_implicit_conversion<int8_t, int32_t, int8_to_int>(conversions); + add_implicit_conversion<int8_t, float, int8_to_float>(conversions); + add_implicit_conversion<int8_t, float2, int8_to_float2>(conversions); + add_implicit_conversion<int8_t, float3, int8_to_float3>(conversions); + add_implicit_conversion<int8_t, ColorGeometry4f, int8_to_color>(conversions); + add_implicit_conversion<bool, float, bool_to_float>(conversions); + add_implicit_conversion<bool, int8_t, bool_to_int8>(conversions); add_implicit_conversion<bool, int32_t, bool_to_int>(conversions); add_implicit_conversion<bool, float2, bool_to_float2>(conversions); add_implicit_conversion<bool, float3, bool_to_float3>(conversions); add_implicit_conversion<bool, ColorGeometry4f, bool_to_color>(conversions); add_implicit_conversion<ColorGeometry4f, bool, color_to_bool>(conversions); + add_implicit_conversion<ColorGeometry4f, int8_t, color_to_int8>(conversions); add_implicit_conversion<ColorGeometry4f, float, color_to_float>(conversions); add_implicit_conversion<ColorGeometry4f, int32_t, color_to_int>(conversions); add_implicit_conversion<ColorGeometry4f, float2, color_to_float2>(conversions); diff --git a/source/blender/blenkernel/intern/vfontdata_freetype.c b/source/blender/blenkernel/intern/vfontdata_freetype.c index 9b79d5635d1..60b7e4e5c8b 100644 --- a/source/blender/blenkernel/intern/vfontdata_freetype.c +++ b/source/blender/blenkernel/intern/vfontdata_freetype.c @@ -15,6 +15,10 @@ * * The Original Code is written by Rob Haarsma (phase) * All rights reserved. + */ + +/** \file + * \ingroup bke * * This code parses the Freetype font outline data to chains of Blender's bezier-triples. * Additional information can be found at the bottom of this file. @@ -22,10 +26,6 @@ * Code that uses exotic character maps is present but commented out. */ -/** \file - * \ingroup bke - */ - #include <ft2build.h> #include FT_FREETYPE_H /* not needed yet */ diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index a4f20f980b4..138c75acd7b 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Functions for writing avi-format files. - * Added interface for generic movie support (ton) */ /** \file + * Functions for writing AVI-format files. + * Added interface for generic movie support (ton) * \ingroup bke */ diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h index 3cf849efaef..ad6e350ba2c 100644 --- a/source/blender/blenlib/BLI_dlrbTree.h +++ b/source/blender/blenlib/BLI_dlrbTree.h @@ -99,6 +99,12 @@ typedef DLRBT_Node *(*DLRBT_NAlloc_FP)(void *data); */ typedef void (*DLRBT_NUpdate_FP)(void *node, void *data); +/** + * Free a node and the wrapped data. + * \param node: <DLRBT_Node> the node to free. + */ +typedef void (*DLRBT_NFree_FP)(void *node); + /* ********************************************** */ /* Public API */ @@ -122,7 +128,7 @@ void BLI_dlrbTree_init(DLRBT_Tree *tree); /** * Free the given tree's data but not the tree itself. */ -void BLI_dlrbTree_free(DLRBT_Tree *tree); +void BLI_dlrbTree_free(DLRBT_Tree *tree, DLRBT_NFree_FP free_cb); /** * Make sure the tree's Double-Linked list representation is valid. diff --git a/source/blender/blenlib/BLI_enumerable_thread_specific.hh b/source/blender/blenlib/BLI_enumerable_thread_specific.hh index b5981028893..ce7df1ff4b9 100644 --- a/source/blender/blenlib/BLI_enumerable_thread_specific.hh +++ b/source/blender/blenlib/BLI_enumerable_thread_specific.hh @@ -28,10 +28,12 @@ namespace blender::threading { +#ifndef WITH_TBB namespace enumerable_thread_specific_utils { inline std::atomic<int> next_id = 0; inline thread_local int thread_id = next_id.fetch_add(1, std::memory_order_relaxed); } // namespace enumerable_thread_specific_utils +#endif /** * This is mainly a wrapper for `tbb::enumerable_thread_specific`. The wrapper is needed because we diff --git a/source/blender/blenlib/BLI_fnmatch.h b/source/blender/blenlib/BLI_fnmatch.h index 1df5b6f814a..d3a5d5fb53e 100644 --- a/source/blender/blenlib/BLI_fnmatch.h +++ b/source/blender/blenlib/BLI_fnmatch.h @@ -14,15 +14,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. - * - * NOTE: The canonical source of this file is maintained with the GNU C Library. - * Bugs can be reported to <bug-glibc@prep.ai.mit.edu>. */ #pragma once /** \file * \ingroup bli + * \note The canonical source of this file is maintained with the GNU C Library. + * Bugs can be reported to <bug-glibc@prep.ai.mit.edu>. */ #ifdef __cplusplus diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index f73d1f22502..f970563d2a6 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -58,6 +58,12 @@ ListBase BLI_listbase_from_link(struct Link *some_link); */ void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); + +/** + * Returns the nth element after \a link, numbering from 0. + */ +void *BLI_findlinkfrom(struct Link *start, int number) ATTR_WARN_UNUSED_RESULT; + /** * Finds the first element of \a listbase which contains the null-terminated * string \a id at the specified offset, returning NULL if not found. diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h index 5768b098d2f..b3ce6c0747a 100644 --- a/source/blender/blenlib/BLI_math.h +++ b/source/blender/blenlib/BLI_math.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index f6462233106..69abe49c207 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index 0798acbb790..e1956d2bc2b 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_math_color_blend.h b/source/blender/blenlib/BLI_math_color_blend.h index 2aff629def8..df70da0eec3 100644 --- a/source/blender/blenlib/BLI_math_color_blend.h +++ b/source/blender/blenlib/BLI_math_color_blend.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 6d7159f73c6..2556aae6aa4 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_math_inline.h b/source/blender/blenlib/BLI_math_inline.h index 70f56d15164..35e08898385 100644 --- a/source/blender/blenlib/BLI_math_inline.h +++ b/source/blender/blenlib/BLI_math_inline.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 03b6ff25a4f..ac9364fc254 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once @@ -431,6 +429,20 @@ void mat3_to_size(float size[3], const float M[3][3]); void mat4_to_size(float size[3], const float M[4][4]); /** + * Return the largest scale on any axis, the equivalent of calling: + * \code{.c} + * mat3_to_size(size_v3, mat); + * size = size_v3[max_axis_v3(size_v3)]; + * \endcode + * .. without 2x unnecessary `sqrtf` calls. + */ +float mat3_to_size_max_axis(const float M[3][3]); +/** + * Only the first 3 axes are used. + */ +float mat4_to_size_max_axis(const float M[4][4]); + +/** * Extract scale factors from the matrix, with correction to ensure * exact volume in case of a sheared matrix. */ diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index c27cf71ce5f..907dc5601fe 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 1ed8d4fc005..04b7ac5db62 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ #pragma once diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh index e3dd8afd588..32a03213dc1 100644 --- a/source/blender/blenlib/BLI_string_ref.hh +++ b/source/blender/blenlib/BLI_string_ref.hh @@ -358,7 +358,9 @@ constexpr int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) con constexpr int64_t StringRefBase::find_first_of(char c, int64_t pos) const { - return this->find_first_of(StringRef(&c, 1), pos); + BLI_assert(pos >= 0); + return index_or_npos_to_int64( + std::string_view(*this).find_first_of(c, static_cast<size_t>(pos))); } constexpr int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const @@ -370,7 +372,8 @@ constexpr int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) cons constexpr int64_t StringRefBase::find_last_of(char c, int64_t pos) const { - return this->find_last_of(StringRef(&c, 1), pos); + BLI_assert(pos >= 0); + return index_or_npos_to_int64(std::string_view(*this).find_last_of(c, static_cast<size_t>(pos))); } constexpr int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const @@ -382,7 +385,9 @@ constexpr int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) constexpr int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const { - return this->find_first_not_of(StringRef(&c, 1), pos); + BLI_assert(pos >= 0); + return index_or_npos_to_int64( + std::string_view(*this).find_first_not_of(c, static_cast<size_t>(pos))); } constexpr int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const @@ -394,7 +399,9 @@ constexpr int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) constexpr int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const { - return this->find_last_not_of(StringRef(&c, 1), pos); + BLI_assert(pos >= 0); + return index_or_npos_to_int64( + std::string_view(*this).find_last_not_of(c, static_cast<size_t>(pos))); } constexpr StringRef StringRefBase::trim() const diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh index 84d5cd39bb4..8f75aa19cfe 100644 --- a/source/blender/blenlib/BLI_task.hh +++ b/source/blender/blenlib/BLI_task.hh @@ -31,6 +31,7 @@ # include <tbb/blocked_range.h> # include <tbb/parallel_for.h> # include <tbb/parallel_for_each.h> +# include <tbb/parallel_invoke.h> # include <tbb/parallel_reduce.h> # include <tbb/task_arena.h> # ifdef WIN32 @@ -103,6 +104,19 @@ Value parallel_reduce(IndexRange range, #endif } +/** + * Execute all of the provided functions. The functions might be executed in parallel or in serial + * or some combination of both. + */ +template<typename... Functions> void parallel_invoke(Functions &&...functions) +{ +#ifdef WITH_TBB + tbb::parallel_invoke(std::forward<Functions>(functions)...); +#else + (functions(), ...); +#endif +} + /** See #BLI_task_isolate for a description of what isolating a task means. */ template<typename Function> void isolate_task(const Function &function) { diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c index 262d112d914..bc61282fa20 100644 --- a/source/blender/blenlib/intern/BLI_dynstr.c +++ b/source/blender/blenlib/intern/BLI_dynstr.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Dynamically sized string ADT */ /** \file * \ingroup bli + * Dynamically sized string ADT. */ #include <stdio.h> diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index 765d2f0be55..f34179b2fa6 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Support for linked lists. */ /** \file diff --git a/source/blender/blenlib/intern/DLRB_tree.c b/source/blender/blenlib/intern/DLRB_tree.c index 66c394f5eb2..9c22afeb893 100644 --- a/source/blender/blenlib/intern/DLRB_tree.c +++ b/source/blender/blenlib/intern/DLRB_tree.c @@ -45,7 +45,7 @@ void BLI_dlrbTree_init(DLRBT_Tree *tree) } /* Helper for traversing tree and freeing sub-nodes */ -static void recursive_tree_free_nodes(DLRBT_Node *node) +static void recursive_tree_free_nodes(DLRBT_Node *node, DLRBT_NFree_FP free_cb) { /* sanity check */ if (node == NULL) { @@ -53,14 +53,16 @@ static void recursive_tree_free_nodes(DLRBT_Node *node) } /* free child nodes + subtrees */ - recursive_tree_free_nodes(node->left); - recursive_tree_free_nodes(node->right); + recursive_tree_free_nodes(node->left, free_cb); + recursive_tree_free_nodes(node->right, free_cb); /* free self */ - MEM_freeN(node); + if (free_cb) { + free_cb(node); + } } -void BLI_dlrbTree_free(DLRBT_Tree *tree) +void BLI_dlrbTree_free(DLRBT_Tree *tree, DLRBT_NFree_FP free_cb) { if (tree == NULL) { return; @@ -71,11 +73,19 @@ void BLI_dlrbTree_free(DLRBT_Tree *tree) */ if (tree->first) { /* free list */ - BLI_freelistN((ListBase *)tree); + if (free_cb) { + LISTBASE_FOREACH_MUTABLE(DLRBT_Node *, node, tree) { + free_cb(node); + } + BLI_listbase_clear((ListBase *)tree); + } + else { + BLI_freelistN((ListBase *)tree); + } } else { /* traverse tree, freeing sub-nodes */ - recursive_tree_free_nodes(tree->root); + recursive_tree_free_nodes(tree->root, free_cb); } /* clear pointers */ @@ -584,8 +594,10 @@ DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree, } default: /* update the duplicate node as appropriate */ { + /* Return the updated node after calling the callback. */ + node = parNode; if (update_cb) { - update_cb(parNode, data); + update_cb(node, data); } break; } diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c index 670ea75e9ea..31b8939753e 100644 --- a/source/blender/blenlib/intern/bitmap_draw_2d.c +++ b/source/blender/blenlib/intern/bitmap_draw_2d.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c index 6a0ca8bb33f..a2cc1a0fc12 100644 --- a/source/blender/blenlib/intern/hash_md5.c +++ b/source/blender/blenlib/intern/hash_md5.c @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * Copyright (C) 1995 Software Foundation, Inc. + * Copyright (C) 1995 Free Software Foundation, Inc. * * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */ diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index 513b08a589d..c21b448e505 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -537,6 +537,21 @@ void *BLI_rfindlink(const ListBase *listbase, int number) return link; } +void *BLI_findlinkfrom(Link *start, int number) +{ + Link *link = NULL; + + if (number >= 0) { + link = start; + while (link != NULL && number != 0) { + number--; + link = link->next; + } + } + + return link; +} + int BLI_findindex(const ListBase *listbase, const void *vlink) { Link *link = NULL; diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c index be70acf622a..f2e7f411524 100644 --- a/source/blender/blenlib/intern/math_base.c +++ b/source/blender/blenlib/intern/math_base.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index cfcc54b1136..a7729d83726 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c index 5e52873649e..60931f0c474 100644 --- a/source/blender/blenlib/intern/math_color.c +++ b/source/blender/blenlib/intern/math_color.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c index 73ecb2cf798..7d1003a05ba 100644 --- a/source/blender/blenlib/intern/math_color_blend_inline.c +++ b/source/blender/blenlib/intern/math_color_blend_inline.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index a7f229e7147..27cad310aa5 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 3800fc58a5b..afbaf0733b6 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file @@ -3299,8 +3297,8 @@ static bool point_in_slice(const float p[3], return (h >= 0.0f && h <= 1.0f); } -/* adult sister defining the slice planes by the origin and the normal - * NOTE |normal| may not be 1 but defining the thickness of the slice */ +/* Adult sister defining the slice planes by the origin and the normal. + * NOTE: |normal| may not be 1 but defining the thickness of the slice. */ static bool point_in_slice_as(const float p[3], const float origin[3], const float normal[3]) { float h, rp[3]; diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c index 09028a1eb9a..17580d84c38 100644 --- a/source/blender/blenlib/intern/math_geom_inline.c +++ b/source/blender/blenlib/intern/math_geom_inline.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c index 7225ca5fc94..fed330aa2f0 100644 --- a/source/blender/blenlib/intern/math_interp.c +++ b/source/blender/blenlib/intern/math_interp.c @@ -706,9 +706,9 @@ void BLI_ewa_filter(const int width, } } - /* d should hopefully never be zero anymore */ + /* `d` should hopefully never be zero anymore. */ d = 1.0f / d; mul_v3_fl(result, d); - /* clipping can be ignored if alpha used, texr->trgba[3] already includes filtered edge */ + /* Clipping can be ignored if alpha used, `texr->trgba[3]` already includes filtered edge. */ result[3] = use_alpha ? result[3] * d : 1.0f; } diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index f307672361b..73e64c2bee7 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file @@ -2144,6 +2142,16 @@ void mat4_to_size(float size[3], const float M[4][4]) size[2] = len_v3(M[2]); } +float mat3_to_size_max_axis(const float M[3][3]) +{ + return sqrtf(max_fff(len_squared_v3(M[0]), len_squared_v3(M[1]), len_squared_v3(M[2]))); +} + +float mat4_to_size_max_axis(const float M[4][4]) +{ + return sqrtf(max_fff(len_squared_v3(M[0]), len_squared_v3(M[1]), len_squared_v3(M[2]))); +} + void mat4_to_size_fix_shear(float size[3], const float M[4][4]) { mat4_to_size(size, M); diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index dbcf3a6500c..9de9e3d2045 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index a0afab8a179..fb23018b0e0 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 3022dbbe4ff..3e932572038 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index f39797c980c..3b9b7ed6ddb 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * various string, file, list operations. */ /** \file * \ingroup bli + * Various string, file, list operations. */ #include <ctype.h> diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index 9fe82069d2c..4fd6670507a 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * (uit traces) maart 95 */ /** \file diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index 21162904dbd..d785d3d17f8 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2017 by the Blender FOundation. + * The Original Code is Copyright (C) 2017 by the Blender Foundation. * All rights reserved. */ diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index 11345fc7242..57f3b740a03 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Windows-posix compatibility layer, windows-specific functions. */ /** \file * \ingroup bli + * Windows-posix compatibility layer, windows-specific functions. */ #ifdef WIN32 diff --git a/source/blender/blenlib/intern/winstuff_dir.c b/source/blender/blenlib/intern/winstuff_dir.c index 6f99ea075bb..f8ab3dc8403 100644 --- a/source/blender/blenlib/intern/winstuff_dir.c +++ b/source/blender/blenlib/intern/winstuff_dir.c @@ -12,7 +12,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * Windows-posix compatibility layer for opendir/readdir/closedir */ /** \file diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc index 9e4d7c7dd36..88f597cdf67 100644 --- a/source/blender/blenlib/tests/BLI_listbase_test.cc +++ b/source/blender/blenlib/tests/BLI_listbase_test.cc @@ -80,18 +80,26 @@ TEST(listbase, FindLinkOrIndex) EXPECT_EQ(BLI_rfindlink(&lb, 0), (void *)nullptr); EXPECT_EQ(BLI_rfindlink(&lb, 1), (void *)nullptr); EXPECT_EQ(BLI_findindex(&lb, link1), -1); + EXPECT_EQ(BLI_findlinkfrom((Link *)lb.first, -1), (void *)nullptr); + EXPECT_EQ(BLI_findlinkfrom((Link *)lb.first, 0), (void *)nullptr); + EXPECT_EQ(BLI_findlinkfrom((Link *)lb.first, 1), (void *)nullptr); /* One link */ BLI_addtail(&lb, link1); EXPECT_EQ(BLI_findlink(&lb, 0), link1); EXPECT_EQ(BLI_rfindlink(&lb, 0), link1); EXPECT_EQ(BLI_findindex(&lb, link1), 0); + EXPECT_EQ(BLI_findlinkfrom((Link *)lb.first, 0), link1); /* Two links */ BLI_addtail(&lb, link2); EXPECT_EQ(BLI_findlink(&lb, 1), link2); EXPECT_EQ(BLI_rfindlink(&lb, 0), link2); EXPECT_EQ(BLI_findindex(&lb, link2), 1); + EXPECT_EQ(BLI_findlinkfrom((Link *)lb.first, 1), link2); + + /* After end of list */ + EXPECT_EQ(BLI_findlinkfrom((Link *)lb.first, 2), (void *)nullptr); BLI_freelistN(&lb); } diff --git a/source/blender/blenlib/tests/BLI_task_test.cc b/source/blender/blenlib/tests/BLI_task_test.cc index 3bb6f6f753c..1ed732c1f18 100644 --- a/source/blender/blenlib/tests/BLI_task_test.cc +++ b/source/blender/blenlib/tests/BLI_task_test.cc @@ -1,6 +1,7 @@ /* Apache License, Version 2.0 */ #include "testing/testing.h" +#include <atomic> #include <cstring> #include "atomic_ops.h" @@ -12,6 +13,7 @@ #include "BLI_listbase.h" #include "BLI_mempool.h" #include "BLI_task.h" +#include "BLI_task.hh" #define NUM_ITEMS 10000 @@ -280,3 +282,15 @@ TEST(task, ListBaseIter) MEM_freeN(items_buffer); BLI_threadapi_exit(); } + +TEST(task, ParallelInvoke) +{ + std::atomic<int> counter = 0; + blender::threading::parallel_invoke([&]() { counter++; }, + [&]() { counter++; }, + [&]() { counter++; }, + [&]() { counter++; }, + [&]() { counter++; }, + [&]() { counter++; }); + EXPECT_EQ(counter, 6); +} diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index c4c3b42cb63..066b180dcc9 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -117,8 +117,6 @@ typedef struct BlendFileReadReport { /* Number of root override IDs that were resynced. */ int resynced_lib_overrides; - /* Number of (non-converted) linked proxies. */ - int linked_proxies; /* Number of proxies converted to library overrides. */ int proxies_to_lib_overrides_success; /* Number of proxies that failed to convert to library overrides. */ diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index 0e2c22d7e4d..772abebeb26 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -15,13 +15,13 @@ * * The Original Code is Copyright (C) 2004 Blender Foundation. * All rights reserved. - * external writefile function prototypes */ #pragma once /** \file * \ingroup blenloader + * External writefile function prototypes. */ #include "BLI_filereader.h" @@ -91,6 +91,8 @@ void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, size_t s /** * Not memfile itself. */ +/* **************** support for memory-write, for undo buffers *************** */ + extern void BLO_memfile_free(MemFile *memfile); /** * Result is that 'first' is being freed. diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 245514d4977..1ff713160df 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -86,10 +86,6 @@ if(WITH_BUILDINFO) add_definitions(-DWITH_BUILDINFO) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) endif() diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index f3c92aec338..f01d6afb22d 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * .blend file reading entry point */ /** \file * \ingroup blenloader + * `.blend` file reading entry point. */ #include <stddef.h> @@ -419,9 +419,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, fd->skip_flags = params->skip_flags; BLI_strncpy(fd->relabase, filename, sizeof(fd->relabase)); - /* clear ob->proxy_from pointers in old main */ - blo_clear_proxy_pointers_from_lib(oldmain); - /* separate libraries from old main */ blo_split_main(&old_mainlist, oldmain); /* add the library pointers in oldmap lookup */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 38f2d8bb22c..6757177a385 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1580,15 +1580,6 @@ static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, } } -void blo_clear_proxy_pointers_from_lib(Main *oldmain) -{ - LISTBASE_FOREACH (Object *, ob, &oldmain->objects) { - if (ID_IS_LINKED(ob) && ob->proxy_from != NULL && !ID_IS_LINKED(ob->proxy_from)) { - ob->proxy_from = NULL; - } - } -} - /* XXX disabled this feature - packed files also belong in temp saves and quit.blend, * to make restore work. */ @@ -2008,6 +1999,7 @@ static void lib_link_id(BlendLibReader *reader, ID *id) if (id->override_library) { BLO_read_id_address(reader, id->lib, &id->override_library->reference); BLO_read_id_address(reader, id->lib, &id->override_library->storage); + BLO_read_id_address(reader, id->lib, &id->override_library->hierarchy_root); } lib_link_id_embedded_id(reader, id); @@ -2997,7 +2989,7 @@ static const char *dataname(short id_code) return "Data from CF"; case ID_WS: return "Data from WS"; - case ID_HA: + case ID_CV: return "Data from HA"; case ID_PT: return "Data from PT"; @@ -3207,18 +3199,8 @@ static void read_libblock_undo_restore_identical( id_old->recalc |= direct_link_id_restore_recalc_exceptions(id_old); id_old->recalc_after_undo_push = 0; - /* As usual, proxies require some special love... - * In `blo_clear_proxy_pointers_from_lib()` we clear all `proxy_from` pointers to local IDs, for - * undo. This is required since we do not re-read linked data in that case, so we also do not - * re-'lib_link' their pointers. - * Those `proxy_from` pointers are then re-defined properly when lib_linking the newly read local - * object. However, in case of re-used data 'as-is', we never lib_link it again, so we have to - * fix those backward pointers here. */ if (GS(id_old->name) == ID_OB) { Object *ob = (Object *)id_old; - if (ob->proxy != NULL) { - ob->proxy->proxy_from = ob; - } /* For undo we stay in object mode during undo presses, so keep editmode disabled for re-used * data-blocks too. */ ob->mode &= ~OB_MODE_EDIT; diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 21b0354b097..d75aab9ba9c 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * blenloader readfile private function prototypes */ /** \file * \ingroup blenloader + * blenloader readfile private function prototypes. */ #pragma once @@ -144,14 +144,6 @@ FileData *blo_filedata_from_memfile(struct MemFile *memfile, const struct BlendFileReadParams *params, struct BlendFileReadReport *reports); -/** - * Lib linked proxy objects point to our local data, we need - * to clear that pointer before reading the undo memfile since - * the object might be removed, it is set again in reading - * if the local object still exists. - * This is only valid for local proxy objects though, linked ones should not be affected here. - */ -void blo_clear_proxy_pointers_from_lib(struct Main *oldmain); void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain); /** * Set old main packed data to zero if it has been restored diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index dfa6135dac9..638e6a13b01 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2004 Blender Foundation * All rights reserved. - * .blend file reading entry point */ /** \file diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 888bd244007..87b5da09a60 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -32,11 +32,11 @@ #include "DNA_cachefile_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" +#include "DNA_curves_types.h" #include "DNA_fluid_types.h" #include "DNA_genfile.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" #include "DNA_light_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -1120,10 +1120,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /* Hair and PointCloud attributes. */ - for (Hair *hair = bmain->hairs.first; hair != NULL; hair = hair->id.next) { - do_versions_point_attributes(&hair->pdata); - } + /* PointCloud attributes. */ for (PointCloud *pointcloud = bmain->pointclouds.first; pointcloud != NULL; pointcloud = pointcloud->id.next) { do_versions_point_attributes(&pointcloud->pdata); @@ -1422,10 +1419,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /* Hair and PointCloud attributes names. */ - LISTBASE_FOREACH (Hair *, hair, &bmain->hairs) { - do_versions_point_attribute_names(&hair->pdata); - } + /* PointCloud attributes names. */ LISTBASE_FOREACH (PointCloud *, pointcloud, &bmain->pointclouds) { do_versions_point_attribute_names(&pointcloud->pdata); } diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 90730439c51..001dffdca10 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -1107,6 +1107,15 @@ static bool seq_transform_origin_set(Sequence *seq, void *UNUSED(user_data)) return true; } +static bool seq_transform_filter_set(Sequence *seq, void *UNUSED(user_data)) +{ + StripTransform *transform = seq->strip->transform; + if (seq->strip->transform != NULL) { + transform->filter = SEQ_TRANSFORM_FILTER_BILINEAR; + } + return true; +} + static void do_version_subsurface_methods(bNode *node) { if (node->type == SH_NODE_SUBSURFACE_SCATTERING) { @@ -2549,6 +2558,14 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 302, 2)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed != NULL) { + SEQ_for_each_callback(&scene->ed->seqbase, seq_transform_filter_set, NULL); + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index aa3eef4b475..4eda63d0817 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -999,7 +999,7 @@ static void write_libraries(WriteData *wd, Main *main) if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { printf( "ERROR: write file: data-block '%s' from lib '%s' is not linkable " - "but is flagged as directly linked", + "but is flagged as directly linked\n", id->name, main->curlib->filepath_abs); BLI_assert(0); diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index 21296143226..379ff923229 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -55,24 +55,14 @@ bool BLT_lang_is_ime_supported(void); #define N_(msgid) msgid #define CTX_N_(context, msgid) msgid -/* Those macros should be used everywhere in UI code. */ -#ifdef WITH_INTERNATIONAL +/* These macros should be used everywhere in UI code. */ /*# define _(msgid) BLT_gettext(msgid) */ -# define IFACE_(msgid) BLT_translate_do_iface(NULL, msgid) -# define TIP_(msgid) BLT_translate_do_tooltip(NULL, msgid) -# define DATA_(msgid) BLT_translate_do_new_dataname(NULL, msgid) -# define CTX_IFACE_(context, msgid) BLT_translate_do_iface(context, msgid) -# define CTX_TIP_(context, msgid) BLT_translate_do_tooltip(context, msgid) -# define CTX_DATA_(context, msgid) BLT_translate_do_new_dataname(context, msgid) -#else -/*# define _(msgid) msgid */ -# define IFACE_(msgid) msgid -# define TIP_(msgid) msgid -# define DATA_(msgid) msgid -# define CTX_IFACE_(context, msgid) ((void)(0 ? (context) : 0), msgid) -# define CTX_TIP_(context, msgid) ((void)(0 ? (context) : 0), msgid) -# define CTX_DATA_(context, msgid) ((void)(0 ? (context) : 0), msgid) -#endif +#define IFACE_(msgid) BLT_translate_do_iface(NULL, msgid) +#define TIP_(msgid) BLT_translate_do_tooltip(NULL, msgid) +#define DATA_(msgid) BLT_translate_do_new_dataname(NULL, msgid) +#define CTX_IFACE_(context, msgid) BLT_translate_do_iface(context, msgid) +#define CTX_TIP_(context, msgid) BLT_translate_do_tooltip(context, msgid) +#define CTX_DATA_(context, msgid) BLT_translate_do_new_dataname(context, msgid) /* Helper macro, when we want to define a same msgid for multiple msgctxt... * Does nothing in C, but is "parsed" by our i18n py tools. @@ -121,7 +111,7 @@ bool BLT_lang_is_ime_supported(void); #define BLT_I18NCONTEXT_ID_CURVE "Curve" #define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle" #define BLT_I18NCONTEXT_ID_GPENCIL "GPencil" -#define BLT_I18NCONTEXT_ID_HAIR "Hair" +#define BLT_I18NCONTEXT_ID_CURVES "Curves" #define BLT_I18NCONTEXT_ID_ID "ID" #define BLT_I18NCONTEXT_ID_IMAGE "Image" // #define BLT_I18NCONTEXT_ID_IPO "Ipo" /* DEPRECATED */ @@ -183,7 +173,7 @@ typedef struct { BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVE, "id_curve"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, "id_fs_linestyle"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_GPENCIL, "id_gpencil"), \ - BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_HAIR, "id_hair"), \ + BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVES, "id_curves"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ID, "id_id"), \ BLT_I18NCONTEXTS_ITEM( \ BLT_I18NCONTEXT_ID_IMAGE, \ diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index e2ed005cf9e..a61327238fe 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -207,10 +207,6 @@ if(WITH_BULLET) add_definitions(-DWITH_BULLET) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index e5ede75f737..900844af4e5 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -93,6 +93,7 @@ enum { SIMVERT_FACE, SIMVERT_VGROUP, SIMVERT_EDGE, + SIMVERT_CREASE, }; /* Poke face center calculation */ diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 2f471bf0b81..b429399f310 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -451,6 +451,16 @@ static bool nearly_parallel_normalized(const float d1[3], const float d2[3]) return compare_ff(fabsf(direction_dot), 1.0f, BEVEL_EPSILON_ANG_DOT); } +/** + * calculate the determinant of a matrix formed by three vectors + * \return dot(a, cross(b, c)) = determinant(a, b, c) + */ +static float determinant_v3v3v3(const float a[3], const float b[3], const float c[3]) +{ + return a[0] * b[1] * c[2] + a[1] * b[2] * c[0] + a[2] * b[0] * c[1] - a[0] * b[2] * c[1] - + a[1] * b[0] * c[2] - a[2] * b[1] * c[0]; +} + /* Make a new BoundVert of the given kind, inserting it at the end of the circular linked * list with entry point bv->boundstart, and return it. */ static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3]) @@ -4118,44 +4128,114 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) VMesh *vm_out = new_adj_vmesh(bp->mem_arena, n_boundary, ns_out, vm_in->boundstart); /* First we adjust the boundary vertices of the input mesh, storing in output mesh. */ + BoundVert *bndv = vm_in->boundstart; for (int i = 0; i < n_boundary; i++) { + float co1[3], co2[3], acc[3]; + EdgeHalf *e = bndv->elast; + /* Generate tangents. This is hacked together and would ideally be done elsewhere and then only + * used here. */ + float tangent[3], tangent2[3], normal[3]; + bool convex = true; + bool orthogonal = false; + float stretch = 0.0f; + if (e) { + /* Projection direction is direction of the edge. */ + sub_v3_v3v3(tangent, e->e->v1->co, e->e->v2->co); + if (e->is_rev) { + negate_v3(tangent); + } + normalize_v3(tangent); + if (bndv->is_arc_start || bndv->is_patch_start) { + BMFace *face = e->fnext; + if (face) { + copy_v3_v3(normal, face->no); + } + else { + zero_v3(normal); + } + madd_v3_v3v3fl(co2, bndv->profile.middle, normal, 0.1f); + } + if (bndv->is_arc_start || bp->affect_type == BEVEL_AFFECT_VERTICES) { + EdgeHalf *e1 = bndv->next->elast; + BLI_assert(e1); + sub_v3_v3v3(tangent2, e1->e->v1->co, e1->e->v2->co); + if (e1->is_rev) { + negate_v3(tangent2); + } + normalize_v3(tangent2); + + convex = determinant_v3v3v3(tangent2, tangent, normal) < 0; + + add_v3_v3(tangent2, tangent); + normalize_v3(tangent2); + copy_v3_v3(tangent, tangent2); + } + /* Calculate a factor which determines how much the interpolated mesh is + * going to be stretched out into the direction of the tangent. + * It is currently using the difference along the tangent of the + * central point on the profile and the current center vertex position. */ + get_profile_point(bp, &bndv->profile, ns_in2, ns_in, co); + stretch = dot_v3v3(tangent, mesh_vert(vm_in, i, ns_in2, ns_in2)->co) - dot_v3v3(tangent, co); + stretch = fabsf(stretch); + /* Scale the tangent by stretch. The divide by ns_in2 comes from the Levin Paper. */ + mul_v3_fl(tangent, stretch / ns_in2); + orthogonal = bndv->is_patch_start; + } + else if (bndv->prev->is_patch_start) { + /* If this is the second edge of a patch and therefore #e is NULL, + * then e->fprev has to be used/not NULL. */ + BLI_assert(bndv->prev->elast); + BMFace *face = bndv->prev->elast->fnext; + if (face) { + copy_v3_v3(normal, face->no); + } + else { + zero_v3(normal); + } + orthogonal = true; + } + else { + /** Should only come here from make_cube_corner_adj_vmesh. */ + sub_v3_v3v3(co1, mesh_vert(vm_in, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 1)->co); + sub_v3_v3v3(co2, mesh_vert(vm_in, i, 0, 1)->co, mesh_vert(vm_in, i, 0, 2)->co); + cross_v3_v3v3(tangent, co1, co2); + /** The following constant is chosen to best match the old results. */ + normalize_v3_length(tangent, 1.5f / ns_out); + } + /** Copy corner vertex. */ copy_v3_v3(mesh_vert(vm_out, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 0)->co); + /** Copy the rest of the boundary vertices. */ for (int k = 1; k < ns_in; k++) { copy_v3_v3(co, mesh_vert(vm_in, i, 0, k)->co); - /* Smooth boundary rule. Custom profiles shouldn't be smoothed. */ - if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { - float co1[3], co2[3], acc[3]; - copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co); - copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co); - - add_v3_v3v3(acc, co1, co2); - madd_v3_v3fl(acc, co, -2.0f); - madd_v3_v3fl(co, acc, -1.0f / 6.0f); - } + copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co); + copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co); + + add_v3_v3v3(acc, co1, co2); + if (bndv->is_arc_start) { + sub_v3_v3(co1, co); + sub_v3_v3(co2, co); + normalize_v3(co1); + normalize_v3(co2); + add_v3_v3v3(tangent, co1, co2); + /* This is an empirical formula to make the result look good. */ + normalize_v3(tangent); + float dot = convex ? fminf(0, dot_v3v3(tangent2, tangent)) : 1.0f; + mul_v3_fl(tangent, stretch / ns_in * dot); + } + else if (orthogonal) { + sub_v3_v3(co1, co); + cross_v3_v3v3(tangent, normal, co1); + /* This is an empirical formula to make the result look good. */ + normalize_v3_length(tangent, -bp->offset * 0.7071f / ns_in); + } + mul_v3_fl(co, 2.0f); + madd_v3_v3fl(co, acc, -0.25f); + madd_v3_v3fl(co, mesh_vert(vm_in, i, 1, k)->co, -0.5f); + add_v3_v3(co, tangent); copy_v3_v3(mesh_vert_canon(vm_out, i, 0, 2 * k)->co, co); } - } - /* Now adjust odd boundary vertices in output mesh, based on even ones. */ - BoundVert *bndv = vm_out->boundstart; - for (int i = 0; i < n_boundary; i++) { - for (int k = 1; k < ns_out; k += 2) { - get_profile_point(bp, &bndv->profile, k, ns_out, co); - - /* Smooth if using a non-custom profile. */ - if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { - float co1[3], co2[3], acc[3]; - copy_v3_v3(co1, mesh_vert_canon(vm_out, i, 0, k - 1)->co); - copy_v3_v3(co2, mesh_vert_canon(vm_out, i, 0, k + 1)->co); - - add_v3_v3v3(acc, co1, co2); - madd_v3_v3fl(acc, co, -2.0f); - madd_v3_v3fl(co, acc, -1.0f / 6.0f); - } - - copy_v3_v3(mesh_vert_canon(vm_out, i, 0, k)->co, co); - } bndv = bndv->next; } vmesh_copy_equiv_verts(vm_out); @@ -4163,7 +4243,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) /* Copy adjusted verts back into vm_in. */ for (int i = 0; i < n_boundary; i++) { for (int k = 0; k < ns_in; k++) { - copy_v3_v3(mesh_vert(vm_in, i, 0, k)->co, mesh_vert(vm_out, i, 0, 2 * k)->co); + copy_v3_v3(mesh_vert_canon(vm_in, i, 0, k)->co, mesh_vert_canon(vm_out, i, 0, 2 * k)->co); } } @@ -4248,7 +4328,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) vmesh_copy_equiv_verts(vm_out); /* The center vertex is special. */ - gamma = sabin_gamma(n_boundary); + gamma = sabin_gamma(n_boundary) * 0.5f; beta = -gamma; /* Accumulate edge verts in co1, face verts in co2. */ float co1[3], co2[3]; diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc index e244bc377db..91883b0adee 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.cc +++ b/source/blender/bmesh/tools/bmesh_boolean.cc @@ -192,12 +192,12 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out, bool keep_hidden BM_elem_flag_enable(bmv, KEEP_FLAG); } else { - new_bmvs[v] = NULL; + new_bmvs[v] = nullptr; } } for (int v : m_out.vert_index_range()) { const Vert *vertp = m_out.vert(v); - if (new_bmvs[v] == NULL) { + if (new_bmvs[v] == nullptr) { float co[3]; const double3 &d_co = vertp->co; for (int i = 0; i < 3; ++i) { diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index b9b365a3175..2f473ef2945 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -274,10 +274,14 @@ set(SRC # converter nodes nodes/COM_CombineColorNode.cc nodes/COM_CombineColorNode.h + nodes/COM_CombineXYZNode.cc + nodes/COM_CombineXYZNode.h nodes/COM_IDMaskNode.cc nodes/COM_IDMaskNode.h nodes/COM_SeparateColorNode.cc nodes/COM_SeparateColorNode.h + nodes/COM_SeparateXYZNode.cc + nodes/COM_SeparateXYZNode.h nodes/COM_MapRangeNode.cc nodes/COM_MapRangeNode.h @@ -631,10 +635,6 @@ list(APPEND SRC unset(GENSRC) unset(GENSRC_DIR) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_OPENIMAGEDENOISE) add_definitions(-DWITH_OPENIMAGEDENOISE) add_definitions(-DOIDN_STATIC_LIB) diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc index 6cf6c698a2f..d0b3ae74446 100644 --- a/source/blender/compositor/intern/COM_Converter.cc +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -44,6 +44,7 @@ #include "COM_ColorSpillNode.h" #include "COM_ColorToBWNode.h" #include "COM_CombineColorNode.h" +#include "COM_CombineXYZNode.h" #include "COM_CompositorNode.h" #include "COM_ConvertAlphaNode.h" #include "COM_ConvertColorSpaceNode.h" @@ -96,6 +97,7 @@ #include "COM_ScaleOperation.h" #include "COM_SceneTimeNode.h" #include "COM_SeparateColorNode.h" +#include "COM_SeparateXYZNode.h" #include "COM_SetAlphaNode.h" #include "COM_SetValueOperation.h" #include "COM_SplitViewerNode.h" @@ -434,6 +436,12 @@ Node *COM_convert_bnode(bNode *b_node) case CMP_NODE_CONVERT_COLOR_SPACE: node = new ConvertColorSpaceNode(b_node); break; + case CMP_NODE_SEPARATE_XYZ: + node = new SeparateXYZNode(b_node); + break; + case CMP_NODE_COMBINE_XYZ: + node = new CombineXYZNode(b_node); + break; } return node; } diff --git a/source/blender/compositor/nodes/COM_AntiAliasingNode.cc b/source/blender/compositor/nodes/COM_AntiAliasingNode.cc index b11c57041d9..d1b2e69d7ff 100644 --- a/source/blender/compositor/nodes/COM_AntiAliasingNode.cc +++ b/source/blender/compositor/nodes/COM_AntiAliasingNode.cc @@ -1,6 +1,4 @@ /* - * Copyright 2017, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: IRIE Shinsuke + * Copyright 2017, Blender Foundation. */ #include "COM_AntiAliasingNode.h" diff --git a/source/blender/compositor/nodes/COM_AntiAliasingNode.h b/source/blender/compositor/nodes/COM_AntiAliasingNode.h index 05c51d5856a..bcae235b434 100644 --- a/source/blender/compositor/nodes/COM_AntiAliasingNode.h +++ b/source/blender/compositor/nodes/COM_AntiAliasingNode.h @@ -1,6 +1,4 @@ /* - * Copyright 2017, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: IRIE Shinsuke + * Copyright 2017, Blender Foundation. */ #pragma once diff --git a/source/blender/compositor/nodes/COM_CombineXYZNode.cc b/source/blender/compositor/nodes/COM_CombineXYZNode.cc new file mode 100644 index 00000000000..2b71b94e192 --- /dev/null +++ b/source/blender/compositor/nodes/COM_CombineXYZNode.cc @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_CombineXYZNode.h" + +#include "COM_ConvertOperation.h" + +namespace blender::compositor { + +CombineXYZNode::CombineXYZNode(bNode *editor_node) : Node(editor_node) +{ +} + +void CombineXYZNode::convert_to_operations(NodeConverter &converter, + const CompositorContext &UNUSED(context)) const +{ + NodeInput *input_x_socket = this->get_input_socket(0); + NodeInput *input_y_socket = this->get_input_socket(1); + NodeInput *input_z_socket = this->get_input_socket(2); + NodeOutput *output_socket = this->get_output_socket(0); + + CombineChannelsOperation *operation = new CombineChannelsOperation(); + if (input_x_socket->is_linked()) { + operation->set_canvas_input_index(0); + } + else if (input_y_socket->is_linked()) { + operation->set_canvas_input_index(1); + } + else { + operation->set_canvas_input_index(2); + } + converter.add_operation(operation); + + converter.map_input_socket(input_x_socket, operation->get_input_socket(0)); + converter.map_input_socket(input_y_socket, operation->get_input_socket(1)); + converter.map_input_socket(input_z_socket, operation->get_input_socket(2)); + converter.map_output_socket(output_socket, operation->get_output_socket()); +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CombineXYZNode.h b/source/blender/compositor/nodes/COM_CombineXYZNode.h new file mode 100644 index 00000000000..c3bb69b03ed --- /dev/null +++ b/source/blender/compositor/nodes/COM_CombineXYZNode.h @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "COM_Node.h" + +namespace blender::compositor { + +/** + * \brief SeparateXYZNode + * \ingroup Node + */ +class CombineXYZNode : public Node { + public: + CombineXYZNode(bNode *editor_node); + void convert_to_operations(NodeConverter &converter, + const CompositorContext &context) const override; +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_FilterNode.cc b/source/blender/compositor/nodes/COM_FilterNode.cc index 2108e68cbec..4eca1492fe9 100644 --- a/source/blender/compositor/nodes/COM_FilterNode.cc +++ b/source/blender/compositor/nodes/COM_FilterNode.cc @@ -48,7 +48,7 @@ void FilterNode::convert_to_operations(NodeConverter &converter, 2 / 16.0f, 1 / 16.0f); break; - case CMP_FILT_SHARP: + case CMP_FILT_SHARP_BOX: operation = new ConvolutionFilterOperation(); operation->set3x3Filter(-1, -1, -1, -1, 9, -1, -1, -1, -1); break; @@ -80,6 +80,10 @@ void FilterNode::convert_to_operations(NodeConverter &converter, operation = new ConvolutionFilterOperation(); operation->set3x3Filter(1, 2, 1, 0, 1, 0, -1, -2, -1); break; + case CMP_FILT_SHARP_DIAMOND: + operation = new ConvolutionFilterOperation(); + operation->set3x3Filter(0, -1, 0, -1, 5, -1, 0, -1, 0); + break; default: operation = new ConvolutionFilterOperation(); operation->set3x3Filter(0, 0, 0, 0, 1, 0, 0, 0, 0); diff --git a/source/blender/compositor/nodes/COM_SeparateXYZNode.cc b/source/blender/compositor/nodes/COM_SeparateXYZNode.cc new file mode 100644 index 00000000000..749116d6217 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SeparateXYZNode.cc @@ -0,0 +1,63 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_SeparateXYZNode.h" + +#include "COM_ConvertOperation.h" + +namespace blender::compositor { + +SeparateXYZNode::SeparateXYZNode(bNode *editor_node) : Node(editor_node) +{ + /* pass */ +} + +void SeparateXYZNode::convert_to_operations(NodeConverter &converter, + const CompositorContext &UNUSED(context)) const +{ + NodeInput *vector_socket = this->get_input_socket(0); + NodeOutput *output_x_socket = this->get_output_socket(0); + NodeOutput *output_y_socket = this->get_output_socket(1); + NodeOutput *output_z_socket = this->get_output_socket(2); + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->set_channel(0); + converter.add_operation(operation); + converter.map_input_socket(vector_socket, operation->get_input_socket(0)); + converter.map_output_socket(output_x_socket, operation->get_output_socket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->set_channel(1); + converter.add_operation(operation); + converter.map_input_socket(vector_socket, operation->get_input_socket(0)); + converter.map_output_socket(output_y_socket, operation->get_output_socket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->set_channel(2); + converter.add_operation(operation); + converter.map_input_socket(vector_socket, operation->get_input_socket(0)); + converter.map_output_socket(output_z_socket, operation->get_output_socket(0)); + } +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SeparateXYZNode.h b/source/blender/compositor/nodes/COM_SeparateXYZNode.h new file mode 100644 index 00000000000..1efa017d9e3 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SeparateXYZNode.h @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "COM_Node.h" + +namespace blender::compositor { + +/** + * \brief SeparateXYZNode + * \ingroup Node + */ +class SeparateXYZNode : public Node { + public: + SeparateXYZNode(bNode *editor_node); + void convert_to_operations(NodeConverter &converter, + const CompositorContext &context) const override; +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc index 20e85c69ac8..c466338b61c 100644 --- a/source/blender/compositor/operations/COM_SMAAOperation.cc +++ b/source/blender/compositor/operations/COM_SMAAOperation.cc @@ -1,6 +1,4 @@ /* - * Copyright 2017, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: IRIE Shinsuke + * Copyright 2017, Blender Foundation. */ #include "COM_SMAAOperation.h" diff --git a/source/blender/compositor/operations/COM_SMAAOperation.h b/source/blender/compositor/operations/COM_SMAAOperation.h index ec04594e0aa..bac33f0a2b4 100644 --- a/source/blender/compositor/operations/COM_SMAAOperation.h +++ b/source/blender/compositor/operations/COM_SMAAOperation.h @@ -1,6 +1,4 @@ /* - * Copyright 2017, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: IRIE Shinsuke + * Copyright 2017, Blender Foundation. */ #pragma once diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 41253117096..91c7fac68de 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -70,6 +70,7 @@ set(SRC intern/eval/deg_eval_flush.cc intern/eval/deg_eval_runtime_backup.cc intern/eval/deg_eval_runtime_backup_animation.cc + intern/eval/deg_eval_runtime_backup_gpencil.cc intern/eval/deg_eval_runtime_backup_modifier.cc intern/eval/deg_eval_runtime_backup_movieclip.cc intern/eval/deg_eval_runtime_backup_object.cc @@ -131,6 +132,7 @@ set(SRC intern/eval/deg_eval_flush.h intern/eval/deg_eval_runtime_backup.h intern/eval/deg_eval_runtime_backup_animation.h + intern/eval/deg_eval_runtime_backup_gpencil.h intern/eval/deg_eval_runtime_backup_modifier.h intern/eval/deg_eval_runtime_backup_movieclip.h intern/eval/deg_eval_runtime_backup_object.h diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index 0461d8b63fd..8e4a7dafcd6 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -111,9 +111,6 @@ typedef enum eDepsObjectComponentType { /* Parameters Component - Default when nothing else fits * (i.e. just SDNA property setting). */ DEG_OB_COMP_PARAMETERS, - /* Generic "Proxy-Inherit" Component. - * TODO(sergey): Also for instancing of subgraphs? */ - DEG_OB_COMP_PROXY, /* Animation Component. * * TODO(sergey): merge in with parameters? */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index b2e136c3d3b..990021dc29b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -125,10 +125,6 @@ bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan) { - /* Proxies don't have BONE_SEGMENTS */ - if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { - return false; - } return check_pchan_has_bbone(object, pchan); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 79d674e8415..ba1432d9ec8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -599,7 +599,7 @@ void DepsgraphNodeBuilder::build_id(ID *id) case ID_CU: case ID_LT: case ID_GD: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: build_object_data_geometry_datablock(id); @@ -726,9 +726,6 @@ void DepsgraphNodeBuilder::build_object(int base_index, eDepsNode_LinkedState_Type linked_state, bool is_visible) { - if (object->proxy != nullptr) { - object->proxy->proxy_from = object; - } const bool has_object = built_map_.checkIsBuiltAndTag(object); /* When there is already object in the dependency graph accumulate visibility an linked state @@ -819,9 +816,6 @@ void DepsgraphNodeBuilder::build_object(int base_index, (object->pd->tex != nullptr)) { build_texture(object->pd->tex); } - /* Proxy object to copy from. */ - build_object_proxy_from(object, is_visible); - build_object_proxy_group(object, is_visible); /* Object dupligroup. */ if (object->instance_collection != nullptr) { build_object_instance_collection(object, is_visible); @@ -875,22 +869,6 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index, }); } -void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_object_visible) -{ - if (object->proxy_from == nullptr) { - return; - } - build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_object_visible); -} - -void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_object_visible) -{ - if (object->proxy_group == nullptr) { - return; - } - build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_object_visible); -} - void DepsgraphNodeBuilder::build_object_instance_collection(Object *object, bool is_object_visible) { if (object->instance_collection == nullptr) { @@ -916,18 +894,13 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) case OB_MBALL: case OB_LATTICE: case OB_GPENCIL: - case OB_HAIR: + case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: build_object_data_geometry(object); break; case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { - build_proxy_rig(object); - } - else { - build_rig(object); - } + build_rig(object); break; case OB_LAMP: build_object_data_light(object); @@ -1183,12 +1156,6 @@ void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve) } build_id(dtar->id); build_driver_id_property(dtar->id, dtar->rna_path); - /* Corresponds to dtar_id_ensure_proxy_from(). */ - if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != nullptr)) { - Object *proxy_from = ((Object *)dtar->id)->proxy_from; - build_id(&proxy_from->id); - build_driver_id_property(&proxy_from->id, dtar->rna_path); - } } DRIVER_TARGETS_LOOPER_END; } @@ -1596,7 +1563,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata) op_node->set_as_entry(); break; } - case ID_HA: { + case ID_CV: { op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); op_node->set_as_entry(); break; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index a1db4aaf693..6e319383478 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -184,8 +184,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { Object *object, eDepsNode_LinkedState_Type linked_state, bool is_visible); - virtual void build_object_proxy_from(Object *object, bool is_object_visible); - virtual void build_object_proxy_group(Object *object, bool is_object_visible); virtual void build_object_instance_collection(Object *object, bool is_object_visible); virtual void build_object_from_layer(int base_index, Object *object, @@ -232,7 +230,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); virtual void build_rig(Object *object); - virtual void build_proxy_rig(Object *object); virtual void build_armature(bArmature *armature); virtual void build_armature_bones(ListBase *bones); virtual void build_shapekeys(Key *key); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index e8dda7b8de4..0e196450f60 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -306,72 +306,4 @@ void DepsgraphNodeBuilder::build_rig(Object *object) } } -void DepsgraphNodeBuilder::build_proxy_rig(Object *object) -{ - bArmature *armature = (bArmature *)object->data; - OperationNode *op_node; - Object *object_cow = get_cow_datablock(object); - /* Sanity check. */ - BLI_assert(object->pose != nullptr); - /* Armature. */ - build_armature(armature); - /* speed optimization for animation lookups */ - BKE_pose_channels_hash_ensure(object->pose); - if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(object->pose); - } - op_node = add_operation_node( - &object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT, - [object_cow](::Depsgraph *depsgraph) { BKE_pose_eval_proxy_init(depsgraph, object_cow); }); - op_node->set_as_entry(); - - int pchan_index = 0; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - op_node = add_operation_node( - &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); - op_node->set_as_entry(); - /* Bone is ready for solvers. */ - add_operation_node(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); - /* Bone is fully evaluated. */ - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE, - [object_cow, pchan_index](::Depsgraph *depsgraph) { - BKE_pose_eval_proxy_copy_bone( - depsgraph, object_cow, pchan_index); - }); - op_node->set_as_exit(); - - /* Custom properties. */ - if (pchan->prop != nullptr) { - build_idproperties(pchan->prop); - add_operation_node( - &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name); - } - - /* Custom shape. */ - if (pchan->custom != nullptr) { - /* NOTE: The relation builder will ensure visibility of the custom shape object. */ - build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false); - } - - pchan_index++; - } - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_CLEANUP, - [object_cow](::Depsgraph *depsgraph) { - BKE_pose_eval_proxy_cleanup(depsgraph, object_cow); - }); - op_node = add_operation_node( - &object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_DONE, - [object_cow](::Depsgraph *depsgraph) { BKE_pose_eval_proxy_done(depsgraph, object_cow); }); - op_node->set_as_exit(); -} - } // namespace blender::deg diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index cb43ef685d4..26dd7bc1363 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -555,7 +555,7 @@ void DepsgraphRelationBuilder::build_id(ID *id) case ID_MB: case ID_CU: case ID_LT: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: case ID_GD: @@ -787,9 +787,6 @@ void DepsgraphRelationBuilder::build_object(Object *object) (object->pd->tex != nullptr)) { build_texture(object->pd->tex); } - /* Proxy object to copy from. */ - build_object_proxy_from(object); - build_object_proxy_group(object); /* Object dupligroup. */ if (object->instance_collection != nullptr) { build_collection(nullptr, object, object->instance_collection); @@ -804,31 +801,6 @@ void DepsgraphRelationBuilder::build_object(Object *object) build_parameters(&object->id); } -void DepsgraphRelationBuilder::build_object_proxy_from(Object *object) -{ - if (object->proxy_from == nullptr) { - return; - } - /* Object is linked here (comes from the library). */ - build_object(object->proxy_from); - ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM); - ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); - add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); -} - -void DepsgraphRelationBuilder::build_object_proxy_group(Object *object) -{ - if (ELEM(object->proxy_group, nullptr, object->proxy)) { - return; - } - /* Object is local here (local in .blend file, users interacts with it). */ - build_object(object->proxy_group); - OperationKey proxy_group_eval_key( - &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); - OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); - add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform"); -} - void DepsgraphRelationBuilder::build_object_from_layer_relations(Object *object) { OperationKey object_from_layer_entry_key( @@ -877,7 +849,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) case OB_MBALL: case OB_LATTICE: case OB_GPENCIL: - case OB_HAIR: + case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: { build_object_data_geometry(object); @@ -895,12 +867,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) break; } case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { - build_proxy_rig(object); - } - else { - build_rig(object); - } + build_rig(object); break; case OB_LAMP: build_object_data_light(object); @@ -1663,18 +1630,9 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) } build_id(target_id); build_driver_id_property(target_id, dtar->rna_path); - /* Look up the proxy - matches dtar_id_ensure_proxy_from during evaluation. */ Object *object = nullptr; if (GS(target_id->name) == ID_OB) { object = (Object *)target_id; - if (object->proxy_from != nullptr) { - /* Redirect the target to the proxy, like in evaluation. */ - object = object->proxy_from; - target_id = &object->id; - /* Prepare the redirected target. */ - build_id(target_id); - build_driver_id_property(target_id, dtar->rna_path); - } } /* Special handling for directly-named bones. */ if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (object && object->type == OB_ARMATURE) && @@ -2034,7 +1992,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part) "Particle Texture -> Particle Reset", RELATION_FLAG_FLUSH_USER_EDIT_ONLY); add_relation(texture_key, particle_settings_eval_key, "Particle Texture -> Particle Eval"); - /* TODO(sergey): Consider moving texture space handling to an own + /* TODO(sergey): Consider moving texture space handling to its own * function. */ if (mtex->texco == TEXCO_OBJECT && mtex->object != nullptr) { ComponentKey object_key(&mtex->object->id, NodeType::TRANSFORM); @@ -2343,7 +2301,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) } break; } - case ID_HA: + case ID_CV: break; case ID_PT: break; @@ -2967,7 +2925,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) continue; } int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE); - if ((ELEM(id_type, ID_ME, ID_HA, ID_PT, ID_VO) && comp_node->type == NodeType::GEOMETRY) || + if ((ELEM(id_type, ID_ME, ID_CV, ID_PT, ID_VO) && comp_node->type == NodeType::GEOMETRY) || (id_type == ID_CF && comp_node->type == NodeType::CACHE)) { rel_flag &= ~RELATION_FLAG_NO_FLUSH; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index d699c799e40..df315176a92 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -216,8 +216,6 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { Object *object, Collection *collection); virtual void build_object(Object *object); - virtual void build_object_proxy_from(Object *object); - virtual void build_object_proxy_group(Object *object); virtual void build_object_from_layer_relations(Object *object); virtual void build_object_data(Object *object); virtual void build_object_data_camera(Object *object); @@ -273,7 +271,6 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { const bPoseChannel *rootchan, const RootPChanMap *root_map); virtual void build_rig(Object *object); - virtual void build_proxy_rig(Object *object); virtual void build_shapekeys(Key *key); virtual void build_armature(bArmature *armature); virtual void build_armature_bones(ListBase *bones); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 856e37ee473..377ef9fc357 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -471,65 +471,4 @@ void DepsgraphRelationBuilder::build_rig(Object *object) } } -void DepsgraphRelationBuilder::build_proxy_rig(Object *object) -{ - bArmature *armature = (bArmature *)object->data; - Object *proxy_from = object->proxy_from; - build_armature(armature); - OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); - OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); - OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - build_idproperties(pchan->prop); - OperationKey bone_local_key( - &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); - OperationKey bone_ready_key( - &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); - OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); - OperationKey from_bone_done_key( - &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); - add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local"); - add_relation(bone_local_key, bone_ready_key, "Local -> Ready"); - add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); - add_relation(bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup"); - add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done", RELATION_FLAG_GODMODE); - /* Make sure bone in the proxy is not done before its FROM is done. */ - if (check_pchan_has_bbone(object, pchan)) { - OperationKey from_bone_segments_key( - &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS); - add_relation(from_bone_segments_key, - bone_done_key, - "Bone Segments -> Bone Done", - RELATION_FLAG_GODMODE); - } - else { - add_relation(from_bone_done_key, bone_done_key, "Bone Done -> Bone Done"); - } - - /* Parent relation: even though the proxy bone itself doesn't need - * the parent bone, some users expect the parent to be ready if the - * bone itself is (e.g. for computing the local space matrix). - */ - if (pchan->parent != nullptr) { - OperationKey parent_key( - &object->id, NodeType::BONE, pchan->parent->name, OperationCode::BONE_DONE); - add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone"); - } - - if (pchan->prop != nullptr) { - OperationKey bone_parameters( - &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name); - OperationKey from_bone_parameters( - &proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name); - add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters"); - } - - /* Custom shape. */ - if (pchan->custom != nullptr) { - build_object(pchan->custom); - add_visibility_relation(&pchan->custom->id, &armature->id); - } - } -} - } // namespace blender::deg diff --git a/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc b/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc index 9e62432ea54..b77b935b9f6 100644 --- a/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc +++ b/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc @@ -63,17 +63,6 @@ class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder { return DepsgraphNodeBuilder::need_pull_base_into_graph(base); } - void build_object_proxy_group(Object *object, bool is_visible) override - { - if (object->proxy_group == nullptr) { - return; - } - if (!filter_.contains(&object->proxy_group->id)) { - return; - } - DepsgraphNodeBuilder::build_object_proxy_group(object, is_visible); - } - protected: DepsgraphFromIDsFilter filter_; }; @@ -96,17 +85,6 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder { return DepsgraphRelationBuilder::need_pull_base_into_graph(base); } - void build_object_proxy_group(Object *object) override - { - if (object->proxy_group == nullptr) { - return; - } - if (!filter_.contains(&object->proxy_group->id)) { - return; - } - DepsgraphRelationBuilder::build_object_proxy_group(object); - } - protected: DepsgraphFromIDsFilter filter_; }; diff --git a/source/blender/depsgraph/intern/builder/pipeline_from_ids.h b/source/blender/depsgraph/intern/builder/pipeline_from_ids.h index 79fcfc52446..8c89bbf1660 100644 --- a/source/blender/depsgraph/intern/builder/pipeline_from_ids.h +++ b/source/blender/depsgraph/intern/builder/pipeline_from_ids.h @@ -36,10 +36,7 @@ namespace deg { * visibility and other flags assigned to the objects. * All other bases (the ones which points to object which is outside of the set of IDs) are * completely ignored. - * - * - Proxy groups pointing to objects which are outside of the IDs set are also ignored. - * This way we avoid high-poly character body pulled into the dependency graph when it's coming - * from a library into an animation file and the dependency graph constructed for a proxy rig. */ + */ class FromIDsBuilderPipeline : public AbstractBuilderPipeline { public: diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 36120ae76d1..ef82584d671 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -99,7 +99,6 @@ static const int deg_debug_node_type_color_map[][2] = { /* Outer Types */ {NodeType::PARAMETERS, 2}, - {NodeType::PROXY, 3}, {NodeType::ANIMATION, 4}, {NodeType::TRANSFORM, 5}, {NodeType::GEOMETRY, 6}, @@ -404,7 +403,6 @@ static void deg_debug_graphviz_node(DotExportContext &ctx, case NodeType::PARAMETERS: case NodeType::ANIMATION: case NodeType::TRANSFORM: - case NodeType::PROXY: case NodeType::GEOMETRY: case NodeType::SEQUENCER: case NodeType::EVAL_POSE: diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 11074b5bf72..b9ec01d729c 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -87,7 +87,7 @@ void depsgraph_geometry_tag_to_component(const ID *id, NodeType *component_type) bool is_selectable_data_id_type(const ID_Type id_type) { - return ELEM(id_type, ID_ME, ID_CU, ID_MB, ID_LT, ID_GD, ID_HA, ID_PT, ID_VO); + return ELEM(id_type, ID_ME, ID_CU, ID_MB, ID_LT, ID_GD, ID_CV, ID_PT, ID_VO); } void depsgraph_select_tag_to_component_opcode(const ID *id, @@ -526,12 +526,6 @@ void graph_tag_ids_for_visible_update(Depsgraph *graph) * this. */ for (deg::IDNode *id_node : graph->id_nodes) { const ID_Type id_type = GS(id_node->id_orig->name); - if (id_type == ID_OB) { - Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig); - if (object_orig->proxy != nullptr) { - object_orig->proxy->proxy_from = object_orig; - } - } if (!id_node->visible_components_mask) { /* ID has no components which affects anything visible. @@ -597,7 +591,7 @@ NodeType geometry_tag_to_component(const ID *id) case OB_LATTICE: case OB_MBALL: case OB_GPENCIL: - case OB_HAIR: + case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: return NodeType::GEOMETRY; @@ -611,7 +605,7 @@ NodeType geometry_tag_to_component(const ID *id) case ID_CU: case ID_LT: case ID_MB: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: case ID_GR: diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index c2b85caad66..48166567354 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -43,6 +43,7 @@ #include "BKE_curve.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_update_cache.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -646,8 +647,8 @@ void set_particle_system_modifiers_loaded(Object *object_cow) void reset_particle_system_edit_eval(const Depsgraph *depsgraph, Object *object_cow) { - /* Inactive (and render) dependency graphs are living in own little bubble, should not care about - * edit mode at all. */ + /* Inactive (and render) dependency graphs are living in their own little bubble, should not care + * about edit mode at all. */ if (!DEG_is_active(reinterpret_cast<const ::Depsgraph *>(depsgraph))) { return; } @@ -708,25 +709,6 @@ void update_animation_data_after_copy(const ID *id_orig, ID *id_cow) update_nla_tracks_orig_pointers(&anim_data_orig->nla_tracks, &anim_data_cow->nla_tracks); } -/* Some builders (like motion path one) will ignore proxies from being built. This code makes it so - * proxy and proxy_group pointers never point to an original objects, preventing evaluation code - * from assign evaluated pointer to an original proxy->proxy_from. */ -void update_proxy_pointers_after_copy(const Depsgraph *depsgraph, - const Object *object_orig, - Object *object_cow) -{ - if (object_cow->proxy != nullptr) { - if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy->id)) { - object_cow->proxy = nullptr; - } - } - if (object_cow->proxy_group != nullptr) { - if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy_group->id)) { - object_cow->proxy_group = nullptr; - } - } -} - /* Do some special treatment of data transfer from original ID to its * CoW complementary part. * @@ -756,11 +738,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, } BKE_pose_pchan_index_rebuild(object_cow->pose); } - if (object_cow->type == OB_GPENCIL) { - BKE_gpencil_update_orig_pointers(object_orig, object_cow); - } update_particles_after_copy(depsgraph, object_orig, object_cow); - update_proxy_pointers_after_copy(depsgraph, object_orig, object_cow); break; } case ID_SCE: { @@ -912,6 +890,13 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode update_edit_mode_pointers(depsgraph, id_orig, id_cow); return id_cow; } + /* In case we don't need to do a copy-on-write, we can use the update cache of the grease + * pencil data to do an update-on-write.*/ + if (id_type == ID_GD && BKE_gpencil_can_avoid_full_copy_on_write( + (const ::Depsgraph *)depsgraph, (bGPdata *)id_orig)) { + BKE_gpencil_update_on_write((bGPdata *)id_orig, (bGPdata *)id_cow); + return id_cow; + } } RuntimeBackup backup(depsgraph); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index bc023766a46..728f631f789 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 20137Blender Foundation. + * The Original Code is Copyright (C) 2017 Blender Foundation. * All rights reserved. */ diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc index 8bf64af7d5d..85ac8b509c2 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc @@ -40,7 +40,8 @@ RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph) object_backup(depsgraph), drawdata_ptr(nullptr), movieclip_backup(depsgraph), - volume_backup(depsgraph) + volume_backup(depsgraph), + gpencil_backup(depsgraph) { drawdata_backup.first = drawdata_backup.last = nullptr; } @@ -75,6 +76,8 @@ void RuntimeBackup::init_from_id(ID *id) case ID_VO: volume_backup.init_from_volume(reinterpret_cast<Volume *>(id)); break; + case ID_GD: + gpencil_backup.init_from_gpencil(reinterpret_cast<bGPdata *>(id)); default: break; } @@ -115,6 +118,8 @@ void RuntimeBackup::restore_to_id(ID *id) case ID_VO: volume_backup.restore_to_volume(reinterpret_cast<Volume *>(id)); break; + case ID_GD: + gpencil_backup.restore_to_gpencil(reinterpret_cast<bGPdata *>(id)); default: break; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h index 0629dbe62b4..c4f6bd954c0 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h @@ -31,6 +31,7 @@ #include "intern/eval/deg_eval_runtime_backup_scene.h" #include "intern/eval/deg_eval_runtime_backup_sound.h" #include "intern/eval/deg_eval_runtime_backup_volume.h" +#include "intern/eval/deg_eval_runtime_backup_gpencil.h" namespace blender { namespace deg { @@ -71,6 +72,7 @@ class RuntimeBackup { DrawDataList *drawdata_ptr; MovieClipBackup movieclip_backup; VolumeBackup volume_backup; + GPencilBackup gpencil_backup; }; } // namespace deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.cc new file mode 100644 index 00000000000..63d1eb9f711 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.cc @@ -0,0 +1,59 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2022 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#include "intern/eval/deg_eval_runtime_backup_gpencil.h" +#include "intern/depsgraph.h" + +#include "BKE_gpencil.h" +#include "BKE_gpencil_update_cache.h" + +#include "DNA_gpencil_types.h" + +namespace blender::deg { + +GPencilBackup::GPencilBackup(const Depsgraph *depsgraph) : depsgraph(depsgraph) +{ +} + +void GPencilBackup::init_from_gpencil(bGPdata *UNUSED(gpd)) +{ +} + +void GPencilBackup::restore_to_gpencil(bGPdata *gpd) +{ + bGPdata *gpd_orig = reinterpret_cast<bGPdata *>(gpd->id.orig_id); + + /* We check for the active depsgraph here to avoid freeing the cache on the original object + * multiple times. This free is only needed for the case where we tagged a full update in the + * update cache and did not do an update-on-write. */ + if (depsgraph->is_active) { + BKE_gpencil_free_update_cache(gpd_orig); + } + /* Doing a copy-on-write copies the update cache pointer. Make sure to reset it + * to NULL as we should never use the update cache from eval data. */ + gpd->runtime.update_cache = NULL; + /* Make sure to update the original runtime pointers in the eval data. */ + BKE_gpencil_data_update_orig_pointers(gpd_orig, gpd); +} + +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h new file mode 100644 index 00000000000..baf0f6a6945 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h @@ -0,0 +1,45 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2022 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +struct bGPdata; + +namespace blender { +namespace deg { + +struct Depsgraph; + +/* Backup of volume datablocks runtime data. */ +class GPencilBackup { + public: + GPencilBackup(const Depsgraph *depsgraph); + + void init_from_gpencil(bGPdata *gpd); + void restore_to_gpencil(bGPdata *gpd); + + const Depsgraph* depsgraph; +}; + +} // namespace deg +} // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc index 17369f723ec..10507948246 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc @@ -127,7 +127,7 @@ void ObjectRuntimeBackup::restore_to_object(Object *object) } } } - else if (ELEM(object->type, OB_HAIR, OB_POINTCLOUD, OB_VOLUME)) { + else if (ELEM(object->type, OB_CURVES, OB_POINTCLOUD, OB_VOLUME)) { if (object->id.recalc & ID_RECALC_GEOMETRY) { /* Free evaluated caches. */ object->data = data_orig; diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 075bfd35ec1..1eb76d76c22 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -67,8 +67,6 @@ const char *nodeTypeAsString(NodeType type) /* **** Outer Types **** */ case NodeType::PARAMETERS: return "PARAMETERS"; - case NodeType::PROXY: - return "PROXY"; case NodeType::ANIMATION: return "ANIMATION"; case NodeType::TRANSFORM: @@ -174,7 +172,6 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type) case NodeType::BONE: case NodeType::SHADING: case NodeType::CACHE: - case NodeType::PROXY: case NodeType::SIMULATION: case NodeType::NTREE_OUTPUT: return DEG_SCENE_COMP_PARAMETERS; @@ -194,8 +191,6 @@ NodeType nodeTypeFromObjectComponent(eDepsObjectComponentType component_type) return NodeType::UNDEFINED; case DEG_OB_COMP_PARAMETERS: return NodeType::PARAMETERS; - case DEG_OB_COMP_PROXY: - return NodeType::PROXY; case DEG_OB_COMP_ANIMATION: return NodeType::ANIMATION; case DEG_OB_COMP_TRANSFORM: @@ -219,8 +214,6 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type) switch (type) { case NodeType::PARAMETERS: return DEG_OB_COMP_PARAMETERS; - case NodeType::PROXY: - return DEG_OB_COMP_PROXY; case NodeType::ANIMATION: return DEG_OB_COMP_ANIMATION; case NodeType::TRANSFORM: diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index 25bbb9a7237..72d3e375bcd 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -77,8 +77,6 @@ enum class NodeType { /* Parameters Component - Default when nothing else fits * (i.e. just SDNA property setting). */ PARAMETERS, - /* Generic "Proxy-Inherit" Component. */ - PROXY, /* Animation Component */ ANIMATION, /* Transform Component (Parenting/Constraints) */ diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 4c430904e44..e14f758c739 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -339,7 +339,6 @@ DEG_COMPONENT_NODE_DEFINE(Particles, PARTICLE_SYSTEM, ID_RECALC_GEOMETRY); DEG_COMPONENT_NODE_DEFINE(ParticleSettings, PARTICLE_SETTINGS, 0); DEG_COMPONENT_NODE_DEFINE(PointCache, POINT_CACHE, 0); DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY); -DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY); DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0); DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_SHADING); DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM); @@ -373,7 +372,6 @@ void deg_register_component_depsnodes() register_node_typeinfo(&DNTI_PARTICLE_SETTINGS); register_node_typeinfo(&DNTI_POINT_CACHE); register_node_typeinfo(&DNTI_IMAGE_ANIMATION); - register_node_typeinfo(&DNTI_PROXY); register_node_typeinfo(&DNTI_EVAL_POSE); register_node_typeinfo(&DNTI_SEQUENCER); register_node_typeinfo(&DNTI_SHADING); diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index f7acd8c72c3..d45d4642937 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -192,7 +192,6 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles); DEG_COMPONENT_NODE_DECLARE_GENERIC(ParticleSettings); DEG_COMPONENT_NODE_DECLARE_GENERIC(Pose); DEG_COMPONENT_NODE_DECLARE_GENERIC(PointCache); -DEG_COMPONENT_NODE_DECLARE_GENERIC(Proxy); DEG_COMPONENT_NODE_DECLARE_GENERIC(Sequencer); DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(Shading); DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters); diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 47d99963ef9..17feb39a072 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -86,9 +86,9 @@ set(SRC intern/mesh_extractors/extract_mesh_vbo_vcol.cc intern/mesh_extractors/extract_mesh_vbo_weights.cc intern/draw_cache_impl_curve.cc + intern/draw_cache_impl_curves.cc intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c - intern/draw_cache_impl_hair.cc intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.c intern/draw_cache_impl_metaball.c diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 80207523a65..8f02e96b168 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -56,7 +56,7 @@ #include "BLI_math_bits.h" #include "BLI_rect.h" -#include "DNA_hair_types.h" +#include "DNA_curves_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_particle_types.h" @@ -248,25 +248,25 @@ static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedat return grp; } -static void eevee_cryptomatte_hair_cache_populate(EEVEE_Data *vedata, - EEVEE_ViewLayerData *sldata, - Object *ob, - ParticleSystem *psys, - ModifierData *md, - Material *material) +static void eevee_cryptomatte_curves_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob, + ParticleSystem *psys, + ModifierData *md, + Material *material) { DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create( vedata, sldata, ob, material, true); DRW_shgroup_hair_create_sub(ob, psys, md, grp, NULL); } -void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata, - EEVEE_ViewLayerData *sldata, - Object *ob) +void EEVEE_cryptomatte_object_curves_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob) { - BLI_assert(ob->type == OB_HAIR); - Material *material = BKE_object_material_get_eval(ob, HAIR_MATERIAL_NR); - eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, NULL, NULL, material); + BLI_assert(ob->type == OB_CURVES); + Material *material = BKE_object_material_get_eval(ob, CURVES_MATERIAL_NR); + eevee_cryptomatte_curves_cache_populate(vedata, sldata, ob, NULL, NULL, material); } void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata, @@ -291,7 +291,7 @@ void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata, continue; } Material *material = BKE_object_material_get_eval(ob, part->omat); - eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, psys, md, material); + eevee_cryptomatte_curves_cache_populate(vedata, sldata, ob, psys, md, material); } } } diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index b453df284ed..64553acd228 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -177,7 +177,7 @@ static void *motion_blur_deform_data_get(EEVEE_MotionBlurData *mb, Object *ob, b if (hair) { EEVEE_HairMotionData *hair_step; /* Ugly, we allocate for each modifiers and just fill based on modifier index in the list. */ - int psys_len = (ob->type != OB_HAIR) ? BLI_listbase_count(&ob->modifiers) : 1; + int psys_len = (ob->type != OB_CURVES) ? BLI_listbase_count(&ob->modifiers) : 1; hair_step = MEM_callocN(sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]) * psys_len, __func__); hair_step->psys_len = psys_len; diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index 4748323d6a7..d0c0635a1fb 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -251,7 +251,7 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), effects->dof_coc_params[1] = -aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); - /* FIXME(fclem) This is broken for vertically fit sensor. */ + /* FIXME(@fclem): This is broken for vertically fit sensor. */ effects->dof_coc_params[1] *= viewport_size[0] / sensor_scaled; if ((scene_eval->eevee.flag & SCE_EEVEE_DOF_JITTER) != 0) { @@ -625,7 +625,7 @@ static void dof_reduce_pass_init(EEVEE_FramebufferList *fbl, } if (txl->dof_reduced_color) { - /* TODO(fclem) In the future, we need to check if mip_count did not change. + /* TODO(@fclem): In the future, we need to check if mip_count did not change. * For now it's ok as we always define all mip level. */ if (res[0] != GPU_texture_width(txl->dof_reduced_color) || res[1] != GPU_texture_width(txl->dof_reduced_color)) { @@ -642,7 +642,8 @@ static void dof_reduce_pass_init(EEVEE_FramebufferList *fbl, txl->dof_reduced_coc = GPU_texture_create_2d( "dof_reduced_coc", UNPACK2(res), mip_count, GPU_R16F, NULL); - /* TODO(fclem) Remove once we have immutable storage or when mips are generated on creation. */ + /* TODO(@fclem): Remove once we have immutable storage or when mips are generated on creation. + */ GPU_texture_generate_mipmap(txl->dof_reduced_color); GPU_texture_generate_mipmap(txl->dof_reduced_coc); } diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index fc9b8b0cde4..9b6b5c5f08d 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -125,7 +125,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob) if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) { EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); } - else if (ob->type == OB_HAIR) { + else if (ob->type == OB_CURVES) { EEVEE_object_hair_cache_populate(vedata, sldata, ob, &cast_shadow); } else if (ob->type == OB_VOLUME) { diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index c51fc18a406..c7a8d2cc001 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -1077,8 +1077,8 @@ void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata, pinfo->intensity_fac = intensity; - /* find cell position on the virtual 3D texture */ - /* NOTE : Keep in sync with load_irradiance_cell() */ + /* Find cell position on the virtual 3D texture. */ + /* NOTE: Keep in sync with `load_irradiance_cell()`. */ #if defined(IRRADIANCE_SH_L2) int size[2] = {3, 3}; #elif defined(IRRADIANCE_HL2) diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index a027a29c813..b8586ee0f68 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -33,7 +33,7 @@ #include "BKE_paint.h" #include "BKE_particle.h" -#include "DNA_hair_types.h" +#include "DNA_curves_types.h" #include "DNA_modifier_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" @@ -925,7 +925,7 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, Object *ob, bool *cast_shadow) { - eevee_hair_cache_populate(vedata, sldata, ob, NULL, NULL, HAIR_MATERIAL_NR, cast_shadow); + eevee_hair_cache_populate(vedata, sldata, ob, NULL, NULL, CURVES_MATERIAL_NR, cast_shadow); } void EEVEE_materials_cache_finish(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 766e721b1b8..883d2eff852 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -1385,9 +1385,9 @@ void EEVEE_cryptomatte_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *s void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob); -void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata, - EEVEE_ViewLayerData *sldata, - Object *ob); +void EEVEE_cryptomatte_object_curves_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob); void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); /** * Register the render passes needed for cryptomatte diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 9e7a67060da..2fd033b6745 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -244,10 +244,10 @@ void EEVEE_render_cache(void *vedata, EEVEE_cryptomatte_cache_populate(data, sldata, ob); } } - else if (ob->type == OB_HAIR) { + else if (ob->type == OB_CURVES) { EEVEE_object_hair_cache_populate(vedata, sldata, ob, &cast_shadow); if (do_cryptomatte) { - EEVEE_cryptomatte_object_hair_cache_populate(data, sldata, ob); + EEVEE_cryptomatte_object_curves_cache_populate(data, sldata, ob); } } else if (ob->type == OB_VOLUME) { @@ -517,8 +517,7 @@ static void eevee_render_draw_background(EEVEE_Data *vedata) EEVEE_PassList *psl = vedata->psl; /* Prevent background to write to data buffers. - * NOTE : This also make sure the textures are bound - * to the right double buffer. */ + * NOTE: This also make sure the textures are bound to the right double buffer. */ GPU_framebuffer_ensure_config(&fbl->main_fb, {GPU_ATTACHMENT_LEAVE, GPU_ATTACHMENT_LEAVE, diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 48c24d138e6..81d9d560320 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -49,7 +49,7 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; if (effects->enabled_effects & EFFECT_SSS) { - /* NOTE : we need another stencil because the stencil buffer is on the same texture + /* NOTE: we need another stencil because the stencil buffer is on the same texture * as the depth buffer we are sampling from. This could be avoided if the stencil is * a separate texture but that needs OpenGL 4.4 or ARB_texture_stencil8. * OR OpenGL 4.3 / ARB_ES3_compatibility if using a render-buffer instead. */ diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 1061b2f91a2..1c7ef775ac2 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -56,7 +56,7 @@ vec2 get_ao_noise(void) { vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy; /* Decorrelate noise from AA. */ - /* TODO(fclem) we should use a more general approach for more random number dimensions. */ + /* TODO(@fclem): we should use a more general approach for more random number dimensions. */ noise = fract(noise * 6.1803402007); return noise; } diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl index 4f9791ac95f..5bf20fe6979 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl @@ -43,7 +43,7 @@ void closure_Diffuse_light_eval(ClosureInputDiffuse cl_in, inout ClosureOutputDiffuse cl_out) { float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L); - /* TODO(fclem) We could try to shadow lights that are shadowless with the ambient_occlusion + /* TODO(@fclem): We could try to shadow lights that are shadowless with the ambient_occlusion * factor here. */ cl_out.radiance += light.data.l_color * (light.data.l_diff * light.vis * light.contact_shadow * radiance); diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl index 00d265a48b0..584aacc9e19 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl @@ -63,7 +63,7 @@ ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in, /* The brdf split sum LUT is applied after the radiance accumulation. * Correct the LTC so that its energy is constant. */ - /* TODO(fclem) Optimize this so that only one scale factor is stored. */ + /* TODO(@fclem): Optimize this so that only one scale factor is stored. */ vec4 ltc_brdf = texture(utilTex, vec3(lut_uv, LTC_BRDF_LAYER)).barg; vec2 split_sum_brdf = ltc_brdf.zw; cl_eval.ltc_brdf_scale = (ltc_brdf.x + ltc_brdf.y) / (split_sum_brdf.x + split_sum_brdf.y); diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl index db9ae0f7034..f5c45d147e6 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl @@ -52,7 +52,7 @@ const float unit_ring_radius = 1.0 / float(gather_ring_count); const float unit_sample_radius = 1.0 / float(gather_ring_count + 0.5); const float large_kernel_radius = 0.5 + float(gather_ring_count); const float smaller_kernel_radius = 0.5 + float(gather_ring_count - gather_density_change_ring); -/* NOTE(fclem) the bias is reducing issues with density change visible transition. */ +/* NOTE(@fclem): the bias is reducing issues with density change visible transition. */ const float radius_downscale_factor = smaller_kernel_radius / large_kernel_radius; const int change_density_at_ring = (gather_ring_count - gather_density_change_ring + 1); const float coc_radius_error = 2.0; @@ -83,7 +83,7 @@ void dof_gather_init(float base_radius, #endif center_co = gl_FragCoord.xy + jitter_ofs * base_radius * unit_sample_radius; - /* TODO(fclem) Seems like the default lod selection is too big. Bias to avoid blocky moving + /* TODO(@fclem): Seems like the default lod selection is too big. Bias to avoid blocky moving * out of focus shapes. */ const float lod_bias = -2.0; lod = max(floor(log2(base_radius * unit_sample_radius) + 0.5) + lod_bias, 0.0); @@ -111,7 +111,7 @@ void dof_gather_accumulator(float base_radius, * a ring. So we need to compensate for fast gather that does not check CoC intersection. */ base_radius += (0.5 - noise.x) * 1.5 * unit_ring_radius * base_radius; } - /* TODO(fclem) another seed? For now Cranly-Partterson rotation with golden ratio. */ + /* TODO(@fclem): another seed? For now Cranly-Partterson rotation with golden ratio. */ noise.x = fract(noise.x + 0.61803398875); float lod, isect_mul; @@ -172,7 +172,7 @@ void dof_gather_accumulator(float base_radius, } #ifdef DOF_FOREGROUND_PASS /* Reduce issue with closer foreground over distant foreground. */ - /* TODO(fclem) this seems to not be completely correct as the issue remains. */ + /* TODO(@fclem): This seems to not be completely correct as the issue remains. */ float ring_area = (sqr(float(ring) + 0.5 + coc_radius_error) - sqr(float(ring) - 0.5 + coc_radius_error)) * sqr(base_radius * unit_sample_radius); diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl index e5b68637563..e288e1a55ea 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl @@ -66,7 +66,7 @@ float dof_hdr_color_weight(vec4 color) { /* From UE4. Very fast "luma" weighting. */ float luma = (color.g * 2.0) + (color.r + color.b); - /* TODO(fclem) Pass correct exposure. */ + /* TODO(@fclem): Pass correct exposure. */ const float exposure = 1.0; return 1.0 / (luma * exposure + 4.0); } @@ -92,7 +92,7 @@ vec4 dof_downsample_bilateral_coc_weights(vec4 cocs) { float chosen_coc = dof_coc_select(cocs); - const float scale = 4.0; /* TODO(fclem) revisit. */ + const float scale = 4.0; /* TODO(@fclem): revisit. */ /* NOTE: The difference between the cocs should be inside a abs() function, * but we follow UE4 implementation to improve how dithered transparency looks (see slide 19). */ return saturate(1.0 - (chosen_coc - cocs) * scale); @@ -373,7 +373,7 @@ void dof_gather_accumulate_sample_pair(DofGatherData pair_data[2], #if 0 const float mirroring_threshold = -layer_threshold - layer_offset; - /* TODO(fclem) Promote to parameter? dither with Noise? */ + /* TODO(@fclem): Promote to parameter? dither with Noise? */ const float mirroring_min_distance = 15.0; if (pair_data[0].coc < mirroring_threshold && (pair_data[1].coc - mirroring_min_distance) > pair_data[0].coc) { @@ -487,7 +487,8 @@ void dof_gather_accumulate_sample_ring(DofGatherData ring_data, } } -/* FIXME(fclem) Seems to be wrong since it needs ringcount+1 as input for slightfocus gather. */ +/* FIXME(@fclem): Seems to be wrong since it needs `ringcount + 1` as input for slightfocus gather. + */ int dof_gather_total_sample_count(const int ring_count, const int ring_density) { return (ring_count * ring_count - ring_count) * ring_density + 1; diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl index f349806d37e..59564890d7e 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl @@ -25,7 +25,8 @@ flat out float spritesize; /* Load 4 Circle of confusion values. texel_co is centered around the 4 taps. */ vec4 fetch_cocs(vec2 texel_co) { - /* TODO(fclem) The textureGather(sampler, co, comp) variant isn't here on some implementations. + /* TODO(@fclem): The `textureGather(sampler, co, comp)` variant isn't here on some + * implementations. */ #if 0 // GPU_ARB_texture_gather vec2 uvs = texel_co / vec2(textureSize(cocBuffer, 0)); diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl index 70f1e9f1e66..85f8a12aa88 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl @@ -45,7 +45,7 @@ vec3 view_position_derivative_from_depth(vec2 uvs, vec2 ofs, vec3 vP, float dept } } -/* TODO(fclem) port to a common place for other effects to use. */ +/* TODO(@fclem): port to a common place for other effects to use. */ bool reconstruct_view_position_and_normal_from_depth(vec2 uvs, out vec3 vP, out vec3 vNg) { vec2 texel_size = vec2(abs(dFdx(uvs.x)), abs(dFdy(uvs.y))); diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl index 2f1efd588f7..f4ff28eaee4 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl @@ -31,7 +31,7 @@ void main() { vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); /* Decorrelate from AA. */ - /* TODO(fclem) we should use a more general approach for more random number dimensions. */ + /* TODO(@fclem): we should use a more general approach for more random number dimensions. */ vec2 random_px = floor(fract(rand.xy * 2.2074408460575947536) * 1.99999) - 0.5; rand.xy = fract(rand.xy * 3.2471795724474602596); diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl index ee48c468630..ba90f5ae531 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl @@ -212,7 +212,7 @@ vec3 view_position_derivative_from_depth(vec2 uvs, vec2 ofs, vec3 vP, float dept } } -/* TODO(fclem) port to a common place for other effects to use. */ +/* TODO(@fclem): port to a common place for other effects to use. */ bool reconstruct_view_position_and_normal_from_depth(vec2 uvs, out vec3 vP, out vec3 vNg) { vec2 texel_size = vec2(abs(dFdx(uvs.x)), abs(dFdy(uvs.y))); diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index 8aba1090b58..5a79dfc2663 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -472,7 +472,7 @@ GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void) GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure( &draw_engine_gpencil_type, gpencil_view_layer_data_free); - /* NOTE(fclem) Putting this stuff in viewlayer means it is shared by all viewports. + /* NOTE(&fclem): Putting this stuff in viewlayer means it is shared by all viewports. * For now it is ok, but in the future, it could become a problem if we implement * the caching system. */ if (*vldata == NULL) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 9bc340a2786..dfa0d350485 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -788,7 +788,7 @@ static void gpencil_draw_mask(GPENCIL_Data *vedata, GPENCIL_tObject *ob, GPENCIL const float clear_col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; float clear_depth = ob->is_drawmode3d ? 1.0f : 0.0f; bool inverted = false; - /* OPTI(fclem) we could optimize by only clearing if the new mask_bits does not contain all + /* OPTI(@fclem): we could optimize by only clearing if the new mask_bits does not contain all * the masks already rendered in the buffer, and drawing only the layers not already drawn. */ bool cleared = false; diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh index b56f3062901..52d57ea2ba5 100644 --- a/source/blender/draw/engines/image/image_drawing_mode.hh +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -227,7 +227,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD IMAGE_InstanceData &instance_data) const { while (iterator.get_next_change() == ePartialUpdateIterResult::ChangeAvailable) { - /* Quick exit when tile_buffer isn't availble. */ + /* Quick exit when tile_buffer isn't available. */ if (iterator.tile_data.tile_buffer == nullptr) { continue; } @@ -247,8 +247,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD GPUTexture *texture = info.texture; const float texture_width = GPU_texture_width(texture); const float texture_height = GPU_texture_height(texture); - // TODO - // early bound check. + /* TODO: early bound check. */ ImageTileWrapper tile_accessor(iterator.tile_data.tile); float tile_offset_x = static_cast<float>(tile_accessor.get_tile_x_offset()); float tile_offset_y = static_cast<float>(tile_accessor.get_tile_y_offset()); @@ -274,9 +273,9 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD if (!region_overlap) { continue; } - // convert the overlapping region to texel space and to ss_pixel space... - // TODO: first convert to ss_pixel space as integer based. and from there go back to texel - // space. But perhaps this isn't needed and we could use an extraction offset somehow. + /* Convert the overlapping region to texel space and to ss_pixel space... + * TODO: first convert to ss_pixel space as integer based. and from there go back to texel + * space. But perhaps this isn't needed and we could use an extraction offset somehow. */ rcti gpu_texture_region_to_update; BLI_rcti_init( &gpu_texture_region_to_update, @@ -297,8 +296,8 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD ceil((changed_overlapping_region_in_uv_space.ymin - tile_offset_y) * tile_height), ceil((changed_overlapping_region_in_uv_space.ymax - tile_offset_y) * tile_height)); - // Create an image buffer with a size - // extract and scale into an imbuf + /* Create an image buffer with a size. + * Extract and scale into an imbuf. */ const int texture_region_width = BLI_rcti_size_x(&gpu_texture_region_to_update); const int texture_region_height = BLI_rcti_size_y(&gpu_texture_region_to_update); @@ -394,7 +393,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD * * Returns true when a float buffer was created. Somehow the VSE cache increases the ref * counter, but might use a different mechanism for destructing the image, that doesn't free the - * rect_float as the refcounter isn't 0. To work around this we destruct any created local + * rect_float as the reference-counter isn't 0. To work around this we destruct any created local * buffers ourself. */ bool ensure_float_buffer(ImBuf &image_buffer) const @@ -477,18 +476,18 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD instance_data->partial_update.ensure_image(image); instance_data->clear_dirty_flag(); - // Step: Find out which screen space textures are needed to draw on the screen. Remove the - // screen space textures that aren't needed. + /* Step: Find out which screen space textures are needed to draw on the screen. Remove the + * screen space textures that aren't needed. */ const ARegion *region = draw_ctx->region; method.update_screen_space_bounds(region); method.update_region_uv_bounds(region); method.update_screen_uv_bounds(); - // Step: Update the GPU textures based on the changes in the image. + /* Step: Update the GPU textures based on the changes in the image. */ instance_data->update_gpu_texture_allocations(); update_textures(*instance_data, image, iuser); - // Step: Add the GPU textures to the shgroup. + /* Step: Add the GPU textures to the shgroup. */ instance_data->update_batches(); add_depth_shgroups(*instance_data, image, iuser); add_shgroups(instance_data); diff --git a/source/blender/draw/engines/image/image_texture_info.hh b/source/blender/draw/engines/image/image_texture_info.hh index 5cf9016a8c8..8c3b7494831 100644 --- a/source/blender/draw/engines/image/image_texture_info.hh +++ b/source/blender/draw/engines/image/image_texture_info.hh @@ -50,9 +50,9 @@ struct TextureInfo { rctf clipping_uv_bounds; /** - * \brief Batch to draw the associated texton the screen. + * \brief Batch to draw the associated text on the screen. * - * contans a VBO with `pos` and 'uv'. + * Contains a VBO with `pos` and `uv`. * `pos` (2xF32) is relative to the origin of the space. * `uv` (2xF32) reflect the uv bounds. */ diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 4029f1237e8..f9694b329aa 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -191,20 +191,17 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_sphere(false); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->solid.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); grp = DRW_shgroup_create(sh, armature_ps); DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.4f); cb->transp.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); sh = OVERLAY_shader_armature_shape(false); grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->solid.custom_fill = grp; cb->solid.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); @@ -213,7 +210,6 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) grp = DRW_shgroup_create(sh, armature_ps); DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f); cb->transp.custom_fill = grp; cb->transp.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); @@ -335,7 +331,6 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_envelope(false); grp = DRW_shgroup_create(sh, armature_ps); DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isDistance", false); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); cb->solid.envelope_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); @@ -371,7 +366,6 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) sh = OVERLAY_shader_armature_envelope(false); grp = DRW_shgroup_create(sh, armature_transp_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); @@ -2044,6 +2038,128 @@ static void draw_bone_name(ArmatureDrawContext *ctx, /** \} */ /* -------------------------------------------------------------------- */ +/** \name Pose Bone Culling + * + * Used for selection since drawing many bones can be slow, see: T91253. + * + * Bounding spheres are used with margins added to ensure bones are included. + * An added margin is needed because #BKE_pchan_minmax only returns the bounds + * of the bones head & tail which doesn't account for parts of the bone users may select + * (octahedral spheres or envelope radius for example). + * \{ */ + +static void pchan_culling_calc_bsphere(const Object *ob, + const bPoseChannel *pchan, + BoundSphere *r_bsphere) +{ + float min[3], max[3]; + INIT_MINMAX(min, max); + BKE_pchan_minmax(ob, pchan, min, max); + mid_v3_v3v3(r_bsphere->center, min, max); + r_bsphere->radius = len_v3v3(min, r_bsphere->center); +} + +/** + * \return true when bounding sphere from `pchan` intersect the view. + * (same for other "test" functions defined here). + */ +static bool pchan_culling_test_simple(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + BoundSphere bsphere; + pchan_culling_calc_bsphere(ob, pchan, &bsphere); + return DRW_culling_sphere_test(view, &bsphere); +} + +static bool pchan_culling_test_with_radius_scale(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan, + const float scale) +{ + BoundSphere bsphere; + pchan_culling_calc_bsphere(ob, pchan, &bsphere); + bsphere.radius *= scale; + return DRW_culling_sphere_test(view, &bsphere); +} + +static bool pchan_culling_test_custom(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + /* For more aggressive culling the bounding box of the custom-object could be used. */ + return pchan_culling_test_simple(view, ob, pchan); +} + +static bool pchan_culling_test_wire(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + BLI_assert(((const bArmature *)ob->data)->drawtype == ARM_WIRE); + return pchan_culling_test_simple(view, ob, pchan); +} + +static bool pchan_culling_test_line(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + BLI_assert(((const bArmature *)ob->data)->drawtype == ARM_LINE); + /* Account for the end-points, as the line end-points size is in pixels, this is a rough value. + * Since the end-points are small the difference between having any margin or not is unlikely + * to be noticeable. */ + const float scale = 1.1f; + return pchan_culling_test_with_radius_scale(view, ob, pchan, scale); +} + +static bool pchan_culling_test_envelope(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + const bArmature *arm = ob->data; + BLI_assert(arm->drawtype == ARM_ENVELOPE); + UNUSED_VARS_NDEBUG(arm); + BoundSphere bsphere; + pchan_culling_calc_bsphere(ob, pchan, &bsphere); + bsphere.radius += max_ff(pchan->bone->rad_head, pchan->bone->rad_tail) * + mat4_to_size_max_axis(ob->obmat) * mat4_to_size_max_axis(pchan->disp_mat); + return DRW_culling_sphere_test(view, &bsphere); +} + +static bool pchan_culling_test_bbone(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + const bArmature *arm = ob->data; + BLI_assert(arm->drawtype == ARM_B_BONE); + UNUSED_VARS_NDEBUG(arm); + const float ob_scale = mat4_to_size_max_axis(ob->obmat); + const Mat4 *bbones_mat = (const Mat4 *)pchan->draw_data->bbone_matrix; + for (int i = pchan->bone->segments; i--; bbones_mat++) { + BoundSphere bsphere; + float size[3]; + mat4_to_size(size, bbones_mat->mat); + copy_v3_v3(bsphere.center, bbones_mat->mat[3]); + bsphere.radius = len_v3(size) * ob_scale; + if (DRW_culling_sphere_test(view, &bsphere)) { + return true; + } + } + return false; +} + +static bool pchan_culling_test_octohedral(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + /* No type assertion as this is a fallback (files from the future will end up here). */ + /* Account for spheres on the end-points. */ + const float scale = 1.2f; + return pchan_culling_test_with_radius_scale(view, ob, pchan, scale); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Main Draw Loops * \{ */ @@ -2084,7 +2200,9 @@ static void draw_armature_edit(ArmatureDrawContext *ctx) boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; - draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag); + if (!is_select) { + draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag); + } if (arm->drawtype == ARM_ENVELOPE) { draw_bone_update_disp_matrix_default(eBone, NULL); @@ -2107,12 +2225,14 @@ static void draw_armature_edit(ArmatureDrawContext *ctx) draw_bone_octahedral(ctx, eBone, NULL, arm, boneflag, constflag, select_id); } - if (show_text && (arm->flag & ARM_DRAWNAMES)) { - draw_bone_name(ctx, eBone, NULL, arm, boneflag); - } + if (!is_select) { + if (show_text && (arm->flag & ARM_DRAWNAMES)) { + draw_bone_name(ctx, eBone, NULL, arm, boneflag); + } - if (arm->flag & ARM_DRAWAXES) { - draw_axes(ctx, eBone, NULL, arm); + if (arm->flag & ARM_DRAWAXES) { + draw_axes(ctx, eBone, NULL, arm); + } } } } @@ -2187,6 +2307,8 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) } } + const DRWView *view = is_pose_select ? DRW_view_default_get() : NULL; + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, index += 0x10000) { Bone *bone = pchan->bone; const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0; @@ -2221,43 +2343,60 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; } - draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag); + if (!is_pose_select) { + draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag); + } if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) { draw_bone_update_disp_matrix_custom(pchan); - draw_bone_custom_shape(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + if (!is_pose_select || pchan_culling_test_custom(view, ob, pchan)) { + draw_bone_custom_shape(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + } } else if (arm->drawtype == ARM_ENVELOPE) { draw_bone_update_disp_matrix_default(NULL, pchan); - draw_bone_envelope(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + if (!is_pose_select || pchan_culling_test_envelope(view, ob, pchan)) { + draw_bone_envelope(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + } } else if (arm->drawtype == ARM_LINE) { draw_bone_update_disp_matrix_default(NULL, pchan); - draw_bone_line(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + if (!is_pose_select || pchan_culling_test_line(view, ob, pchan)) { + draw_bone_line(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + } } else if (arm->drawtype == ARM_WIRE) { draw_bone_update_disp_matrix_bbone(NULL, pchan); - draw_bone_wire(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + if (!is_pose_select || pchan_culling_test_wire(view, ob, pchan)) { + draw_bone_wire(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + } } else if (arm->drawtype == ARM_B_BONE) { draw_bone_update_disp_matrix_bbone(NULL, pchan); - draw_bone_box(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + if (!is_pose_select || pchan_culling_test_bbone(view, ob, pchan)) { + draw_bone_box(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + } } else { draw_bone_update_disp_matrix_default(NULL, pchan); - draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + if (!is_pose_select || pchan_culling_test_octohedral(view, ob, pchan)) { + draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id); + } } - if (draw_dofs) { - draw_bone_degrees_of_freedom(ctx, pchan); - } + /* These aren't included in the selection. */ + if (!is_pose_select) { + if (draw_dofs) { + draw_bone_degrees_of_freedom(ctx, pchan); + } - if (show_text && (arm->flag & ARM_DRAWNAMES)) { - draw_bone_name(ctx, NULL, pchan, arm, boneflag); - } + if (show_text && (arm->flag & ARM_DRAWNAMES)) { + draw_bone_name(ctx, NULL, pchan, arm, boneflag); + } - if (arm->flag & ARM_DRAWAXES) { - draw_axes(ctx, NULL, pchan, arm); + if (arm->flag & ARM_DRAWAXES) { + draw_axes(ctx, NULL, pchan, arm); + } } } } @@ -2365,9 +2504,6 @@ static bool POSE_is_driven_by_active_armature(Object *ob) if (ob_arm) { const DRWContextState *draw_ctx = DRW_context_state_get(); bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx); - if (!is_active && ob_arm->proxy_from) { - is_active = OVERLAY_armature_is_pose_mode(ob_arm->proxy_from, draw_ctx); - } return is_active; } diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 12db2bd02cf..54e8ef80854 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -262,7 +262,7 @@ static bool overlay_object_is_edit_mode(const OVERLAY_PrivateData *pd, const Obj return pd->ctx_mode == CTX_MODE_EDIT_METABALL; case OB_FONT: return pd->ctx_mode == CTX_MODE_EDIT_TEXT; - case OB_HAIR: + case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: /* No edit mode yet. */ @@ -316,7 +316,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) OB_MBALL, OB_FONT, OB_GPENCIL, - OB_HAIR, + OB_CURVES, OB_POINTCLOUD, OB_VOLUME); const bool draw_surface = (ob->dt >= OB_WIRE) && (renderable || (ob->dt == OB_WIRE)); diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index a2362cd8850..de0003625a2 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -484,7 +484,7 @@ static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, cons texcosize = mb->size; break; } - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: { /* No user defined texture space support. */ diff --git a/source/blender/draw/engines/overlay/overlay_fade.c b/source/blender/draw/engines/overlay/overlay_fade.c index 0971021f1c0..557a8976ff7 100644 --- a/source/blender/draw/engines/overlay/overlay_fade.c +++ b/source/blender/draw/engines/overlay/overlay_fade.c @@ -43,7 +43,6 @@ void OVERLAY_fade_cache_init(OVERLAY_Data *vedata) GPUShader *sh = OVERLAY_shader_uniform_color(); pd->fade_grp[i] = DRW_shgroup_create(sh, psl->fade_ps[i]); - DRW_shgroup_uniform_block(pd->fade_grp[i], "globalsBlock", G_draw.block_ubo); const DRWContextState *draw_ctx = DRW_context_state_get(); float color[4]; diff --git a/source/blender/draw/engines/overlay/overlay_volume.c b/source/blender/draw/engines/overlay/overlay_volume.c index ad0ccf1c7c4..b13351984a3 100644 --- a/source/blender/draw/engines/overlay/overlay_volume.c +++ b/source/blender/draw/engines/overlay/overlay_volume.c @@ -37,7 +37,6 @@ void OVERLAY_volume_cache_init(OVERLAY_Data *vedata) GPUShader *sh = OVERLAY_shader_depth_only(); DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->volume_ps); pd->volume_selection_surface_grp = grp; - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } else { psl->volume_ps = NULL; diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl index f7792dc0371..8f90c1acbbb 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl @@ -40,7 +40,7 @@ void main() } else if (lineStyle == OVERLAY_UV_LINE_STYLE_DASH) { if (fract(line_distance / dashLength) < 0.5) { - inner_color = mix(vec4(1.0), colorEdgeSelect, selectionFac_f); + inner_color = mix(vec4(vec3(0.35), 1.0), colorEdgeSelect, selectionFac_f); } } else if (lineStyle == OVERLAY_UV_LINE_STYLE_BLACK) { diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh index f577ae197b4..e93f241ad3c 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh @@ -13,7 +13,7 @@ GPU_SHADER_CREATE_INFO(workbench_composite) .fragment_out(0, Type::VEC4, "fragColor") .typedef_source("workbench_shader_shared.h") .fragment_source("workbench_composite_frag.glsl") - .additional_info("draw_fullscreen"); + .additional_info("draw_fullscreen", "draw_view"); /** \} */ diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh index 60d79ed50d9..29468d6002a 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh @@ -3,11 +3,7 @@ GPU_SHADER_CREATE_INFO(workbench_effect_cavity_common) .fragment_out(0, Type::VEC4, "fragColor") - .sampler(0, ImageType::DEPTH_2D, "depthBuffer") - .sampler(1, ImageType::FLOAT_2D, "normalBuffer") - .sampler(2, ImageType::UINT_2D, "objectIdBuffer") - .sampler(3, ImageType::FLOAT_2D, "cavityJitter") - .uniform_buf(3, "vec4", "samples_coords[512]") + .sampler(0, ImageType::FLOAT_2D, "normalBuffer") .uniform_buf(4, "WorldData", "world_data", Frequency::PASS) .typedef_source("workbench_shader_shared.h") .fragment_source("workbench_effect_cavity_frag.glsl") @@ -17,15 +13,23 @@ GPU_SHADER_CREATE_INFO(workbench_effect_cavity_common) GPU_SHADER_CREATE_INFO(workbench_effect_cavity) .do_static_compilation(true) .define("USE_CAVITY") + .uniform_buf(3, "vec4", "samples_coords[512]") + .sampler(1, ImageType::DEPTH_2D, "depthBuffer") + .sampler(2, ImageType::FLOAT_2D, "cavityJitter") .additional_info("workbench_effect_cavity_common"); GPU_SHADER_CREATE_INFO(workbench_effect_curvature) .do_static_compilation(true) .define("USE_CURVATURE") + .sampler(1, ImageType::UINT_2D, "objectIdBuffer") .additional_info("workbench_effect_cavity_common"); GPU_SHADER_CREATE_INFO(workbench_effect_cavity_curvature) .do_static_compilation(true) .define("USE_CAVITY") .define("USE_CURVATURE") + .uniform_buf(3, "vec4", "samples_coords[512]") + .sampler(1, ImageType::DEPTH_2D, "depthBuffer") + .sampler(2, ImageType::FLOAT_2D, "cavityJitter") + .sampler(3, ImageType::UINT_2D, "objectIdBuffer") .additional_info("workbench_effect_cavity_common"); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl index ad83d6f39e5..880f17b0c9d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -5,6 +5,8 @@ /* From The Alchemy screen-space ambient obscurance algorithm * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */ +#ifdef USE_CAVITY + void cavity_compute(vec2 screenco, sampler2D depthBuffer, sampler2D normalBuffer, @@ -90,3 +92,5 @@ void cavity_compute(vec2 screenco, cavities = clamp(cavities * world_data.cavity_valley_factor, 0.0, 1.0); edges = edges * world_data.cavity_ridge_factor; } + +#endif /* USE_CAVITY */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl index 18a093275c5..a6f7a1f522a 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl @@ -1,4 +1,8 @@ +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) + +#ifdef USE_CURVATURE + float curvature_soft_clamp(float curvature, float control) { if (curvature < 0.5 / control) { @@ -43,3 +47,5 @@ void curvature_compute(vec2 uv, curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge); } } + +#endif /* USE_CURVATURE */ diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c index 04ff2077443..e58c88c5dcc 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_cavity.c +++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c @@ -164,10 +164,10 @@ void workbench_cavity_cache_init(WORKBENCH_Data *data) grp = DRW_shgroup_create(sh, psl->cavity_ps); DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx); - DRW_shgroup_uniform_block(grp, "samples_coords", wpd->vldata->cavity_sample_ubo); DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo); if (SSAO_ENABLED(wpd)) { + DRW_shgroup_uniform_block(grp, "samples_coords", wpd->vldata->cavity_sample_ubo); DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth); DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx); } diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 0dfc3c4b119..8773c78e82f 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -34,8 +34,8 @@ #include "BKE_paint.h" #include "BKE_particle.h" +#include "DNA_curves_types.h" #include "DNA_fluid_types.h" -#include "DNA_hair_types.h" #include "DNA_image_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" @@ -419,9 +419,9 @@ void workbench_cache_populate(void *ved, Object *ob) workbench_shadow_cache_populate(vedata, ob, has_transp_mat); } } - else if (ob->type == OB_HAIR) { + else if (ob->type == OB_CURVES) { int color_type = workbench_color_type_get(wpd, ob, NULL, NULL, NULL); - workbench_cache_hair_populate(wpd, ob, NULL, NULL, color_type, false, HAIR_MATERIAL_NR); + workbench_cache_hair_populate(wpd, ob, NULL, NULL, color_type, false, CURVES_MATERIAL_NR); } else if (ob->type == OB_VOLUME) { if (wpd->shading.type != OB_WIRE) { diff --git a/source/blender/draw/engines/workbench/workbench_shader_shared.h b/source/blender/draw/engines/workbench/workbench_shader_shared.h index 0bfd5957834..c63760a634d 100644 --- a/source/blender/draw/engines/workbench/workbench_shader_shared.h +++ b/source/blender/draw/engines/workbench/workbench_shader_shared.h @@ -1,6 +1,6 @@ #ifndef GPU_SHADER -# include "gpu_shader_shared_utils.h" +# include "GPU_shader_shared_utils.h" #endif #define WORKBENCH_SHADER_SHARED_H diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index af262272577..d4491223c10 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -286,28 +286,32 @@ template< /** The number of values that can be stored in this uniform buffer. */ int64_t len /** True if the buffer only resides on GPU memory and cannot be accessed. */ - /* TODO(fclem): Currently unsupported. */ + /* TODO(@fclem): Currently unsupported. */ /* bool device_only = false */> class UniformArrayBuffer : public detail::UniformCommon<T, len, false> { public: UniformArrayBuffer() { - /* TODO(fclem) We should map memory instead. */ + /* TODO(@fclem): We should map memory instead. */ this->data_ = (T *)MEM_mallocN_aligned(len * sizeof(T), 16, this->name_); } + ~UniformArrayBuffer() + { + MEM_freeN(this->data_); + } }; template< /** Type of the values stored in this uniform buffer. */ typename T /** True if the buffer only resides on GPU memory and cannot be accessed. */ - /* TODO(fclem): Currently unsupported. */ + /* TODO(@fclem): Currently unsupported. */ /* bool device_only = false */> class UniformBuffer : public T, public detail::UniformCommon<T, 1, false> { public: UniformBuffer() { - /* TODO(fclem) How could we map this? */ + /* TODO(@fclem): How could we map this? */ this->data_ = static_cast<T *>(this); } @@ -641,7 +645,7 @@ class Texture : NonCopyable { bool cubemap = false) { - /* TODO(fclem) In the future, we need to check if mip_count did not change. + /* TODO(@fclem): In the future, we need to check if mip_count did not change. * For now it's ok as we always define all MIP level. */ if (tx_) { int3 size = this->size(); @@ -653,7 +657,7 @@ class Texture : NonCopyable { if (tx_ == nullptr) { tx_ = create(w, h, d, mips, format, data, layered, cubemap); if (mips > 1) { - /* TODO(fclem) Remove once we have immutable storage or when mips are + /* TODO(@fclem): Remove once we have immutable storage or when mips are * generated on creation. */ GPU_texture_generate_mipmap(tx_); } @@ -674,20 +678,20 @@ class Texture : NonCopyable { if (h == 0) { return GPU_texture_create_1d(name_, w, mips, format, data); } - else if (d == 0) { + else if (cubemap) { if (layered) { - return GPU_texture_create_1d_array(name_, w, h, mips, format, data); + return GPU_texture_create_cube_array(name_, w, d, mips, format, data); } else { - return GPU_texture_create_2d(name_, w, h, mips, format, data); + return GPU_texture_create_cube(name_, w, mips, format, data); } } - else if (cubemap) { + else if (d == 0) { if (layered) { - return GPU_texture_create_cube_array(name_, w, d, mips, format, data); + return GPU_texture_create_1d_array(name_, w, h, mips, format, data); } else { - return GPU_texture_create_cube(name_, w, mips, format, data); + return GPU_texture_create_2d(name_, w, h, mips, format, data); } } else { diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 8c56d21746d..d531d8ad9f8 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -66,6 +66,15 @@ extern "C" { #endif +/* Uncomment to track unused resource bindings. */ +// #define DRW_UNUSED_RESOURCE_TRACKING + +#ifdef DRW_UNUSED_RESOURCE_TRACKING +# define DRW_DEBUG_FILE_LINE_ARGS , const char *file, int line +#else +# define DRW_DEBUG_FILE_LINE_ARGS +#endif + struct GPUBatch; struct GPUMaterial; struct GPUShader; @@ -468,6 +477,10 @@ void DRW_shgroup_call_compute(DRWShadingGroup *shgroup, int groups_x_len, int groups_y_len, int groups_z_len); +/** + * \warning this keeps the ref to groups_ref until it actually dispatch. + */ +void DRW_shgroup_call_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3]); void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count); void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_count); void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count); @@ -534,6 +547,11 @@ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask); /** + * Issue a barrier command. + */ +void DRW_shgroup_barrier(DRWShadingGroup *shgroup, eGPUBarrier type); + +/** * Issue a clear command. */ void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup, @@ -559,12 +577,12 @@ void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex); -void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, - const char *name, - const struct GPUUniformBuf *ubo); -void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup, - const char *name, - struct GPUUniformBuf **ubo); +void DRW_shgroup_uniform_block_ex(DRWShadingGroup *shgroup, + const char *name, + const struct GPUUniformBuf *ubo DRW_DEBUG_FILE_LINE_ARGS); +void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup, + const char *name, + struct GPUUniformBuf **ubo DRW_DEBUG_FILE_LINE_ARGS); void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, @@ -624,9 +642,32 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, const char *name, const float (*value)[4], int arraysize); -void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup, - const char *name, - struct GPUVertBuf *vertex_buffer); +void DRW_shgroup_vertex_buffer_ex(DRWShadingGroup *shgroup, + const char *name, + struct GPUVertBuf *vertex_buffer DRW_DEBUG_FILE_LINE_ARGS); +void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup, + const char *name, + struct GPUVertBuf **vertex_buffer DRW_DEBUG_FILE_LINE_ARGS); + +#ifdef DRW_UNUSED_RESOURCE_TRACKING +# define DRW_shgroup_vertex_buffer(shgroup, name, vert) \ + DRW_shgroup_vertex_buffer_ex(shgroup, name, vert, __FILE__, __LINE__) +# define DRW_shgroup_vertex_buffer_ref(shgroup, name, vert) \ + DRW_shgroup_vertex_buffer_ref_ex(shgroup, name, vert, __FILE__, __LINE__) +# define DRW_shgroup_uniform_block(shgroup, name, ubo) \ + DRW_shgroup_uniform_block_ex(shgroup, name, ubo, __FILE__, __LINE__) +# define DRW_shgroup_uniform_block_ref(shgroup, name, ubo) \ + DRW_shgroup_uniform_block_ref_ex(shgroup, name, ubo, __FILE__, __LINE__) +#else +# define DRW_shgroup_vertex_buffer(shgroup, name, vert) \ + DRW_shgroup_vertex_buffer_ex(shgroup, name, vert) +# define DRW_shgroup_vertex_buffer_ref(shgroup, name, vert) \ + DRW_shgroup_vertex_buffer_ref_ex(shgroup, name, vert) +# define DRW_shgroup_uniform_block(shgroup, name, ubo) \ + DRW_shgroup_uniform_block_ex(shgroup, name, ubo) +# define DRW_shgroup_uniform_block_ref(shgroup, name, ubo) \ + DRW_shgroup_uniform_block_ref_ex(shgroup, name, ubo) +#endif bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index a4564ce2668..430b28f1224 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -19,7 +19,7 @@ */ #include "DNA_curve_types.h" -#include "DNA_hair_types.h" +#include "DNA_curves_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" @@ -835,7 +835,7 @@ GPUBatch *DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold) return NULL; case OB_MBALL: return DRW_cache_mball_edge_detection_get(ob, r_is_manifold); - case OB_HAIR: + case OB_CURVES: return NULL; case OB_POINTCLOUD: return NULL; @@ -859,7 +859,7 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob) return NULL; case OB_MBALL: return DRW_cache_mball_face_wireframe_get(ob); - case OB_HAIR: + case OB_CURVES: return NULL; case OB_POINTCLOUD: return DRW_pointcloud_batch_cache_get_dots(ob); @@ -886,7 +886,7 @@ GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob) return NULL; case OB_MBALL: return NULL; - case OB_HAIR: + case OB_CURVES: return NULL; case OB_POINTCLOUD: return NULL; @@ -910,7 +910,7 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) return NULL; case OB_MBALL: return DRW_cache_mball_surface_get(ob); - case OB_HAIR: + case OB_CURVES: return NULL; case OB_POINTCLOUD: return DRW_cache_pointcloud_surface_get(ob); @@ -935,7 +935,7 @@ GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) return DRW_curve_batch_cache_pos_vertbuf_get(ob->data); case OB_MBALL: return DRW_mball_batch_cache_pos_vertbuf_get(ob); - case OB_HAIR: + case OB_CURVES: return NULL; case OB_POINTCLOUD: return NULL; @@ -967,8 +967,8 @@ int DRW_cache_object_material_count_get(struct Object *ob) return DRW_curve_material_count_get(ob->data); case OB_MBALL: return DRW_metaball_material_count_get(ob->data); - case OB_HAIR: - return DRW_hair_material_count_get(ob->data); + case OB_CURVES: + return DRW_curves_material_count_get(ob->data); case OB_POINTCLOUD: return DRW_pointcloud_material_count_get(ob->data); case OB_VOLUME: @@ -994,7 +994,7 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, return NULL; case OB_MBALL: return DRW_cache_mball_surface_shaded_get(ob, gpumat_array, gpumat_array_len); - case OB_HAIR: + case OB_CURVES: return NULL; case OB_POINTCLOUD: return DRW_cache_pointcloud_surface_shaded_get(ob, gpumat_array, gpumat_array_len); @@ -3403,8 +3403,8 @@ void drw_batch_cache_validate(Object *ob) case OB_LATTICE: DRW_lattice_batch_cache_validate((Lattice *)ob->data); break; - case OB_HAIR: - DRW_hair_batch_cache_validate((Hair *)ob->data); + case OB_CURVES: + DRW_curves_batch_cache_validate((Curves *)ob->data); break; case OB_POINTCLOUD: DRW_pointcloud_batch_cache_validate((PointCloud *)ob->data); diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 30e5a10df91..b94dd466364 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -246,14 +246,14 @@ struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob, struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob); struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold); -/* Hair */ - -struct GPUBatch *DRW_cache_hair_surface_get(struct Object *ob); -struct GPUBatch **DRW_cache_hair_surface_shaded_get(struct Object *ob, - struct GPUMaterial **gpumat_array, - uint gpumat_array_len); -struct GPUBatch *DRW_cache_hair_face_wireframe_get(struct Object *ob); -struct GPUBatch *DRW_cache_hair_edge_detection_get(struct Object *ob, bool *r_is_manifold); +/* Curves */ + +struct GPUBatch *DRW_cache_curves_surface_get(struct Object *ob); +struct GPUBatch **DRW_cache_curves_surface_shaded_get(struct Object *ob, + struct GPUMaterial **gpumat_array, + uint gpumat_array_len); +struct GPUBatch *DRW_cache_curves_face_wireframe_get(struct Object *ob); +struct GPUBatch *DRW_cache_curves_edge_detection_get(struct Object *ob, bool *r_is_manifold); /* PointCloud */ diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 6a2f4b91ad1..9c6814d910e 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -33,7 +33,7 @@ struct ParticleSystem; struct TaskGraph; struct Curve; -struct Hair; +struct Curves; struct Lattice; struct Mesh; struct MetaBall; @@ -73,9 +73,9 @@ void DRW_particle_batch_cache_free(struct ParticleSystem *psys); void DRW_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd); void DRW_gpencil_batch_cache_free(struct bGPdata *gpd); -void DRW_hair_batch_cache_dirty_tag(struct Hair *hair, int mode); -void DRW_hair_batch_cache_validate(struct Hair *hair); -void DRW_hair_batch_cache_free(struct Hair *hair); +void DRW_curves_batch_cache_dirty_tag(struct Curves *curves, int mode); +void DRW_curves_batch_cache_validate(struct Curves *curves); +void DRW_curves_batch_cache_free(struct Curves *curves); void DRW_pointcloud_batch_cache_dirty_tag(struct PointCloud *pointcloud, int mode); void DRW_pointcloud_batch_cache_validate(struct PointCloud *pointcloud); @@ -188,7 +188,7 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt); /** \name Hair * \{ */ -int DRW_hair_material_count_get(struct Hair *hair); +int DRW_curves_material_count_get(struct Curves *curves); /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_hair.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index d236f0c2f59..8ec97495fcf 100644 --- a/source/blender/draw/intern/draw_cache_impl_hair.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -29,13 +29,16 @@ #include "BLI_listbase.h" #include "BLI_math_base.h" +#include "BLI_math_vec_types.hh" #include "BLI_math_vector.h" +#include "BLI_math_vector.hh" +#include "BLI_span.hh" #include "BLI_utildefines.h" -#include "DNA_hair_types.h" +#include "DNA_curves_types.h" #include "DNA_object_types.h" -#include "BKE_hair.h" +#include "BKE_curves.h" #include "GPU_batch.h" #include "GPU_material.h" @@ -44,7 +47,11 @@ #include "draw_cache_impl.h" /* own include */ #include "draw_hair_private.h" /* own include */ -static void hair_batch_cache_clear(Hair *hair); +using blender::float3; +using blender::IndexRange; +using blender::Span; + +static void curves_batch_cache_clear(Curves *curves); /* ---------------------------------------------------------------------- */ /* Hair GPUBatch Cache */ @@ -58,19 +65,19 @@ struct HairBatchCache { /* GPUBatch cache management. */ -static bool hair_batch_cache_valid(Hair *hair) +static bool curves_batch_cache_valid(Curves *curves) { - HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); + HairBatchCache *cache = static_cast<HairBatchCache *>(curves->batch_cache); return (cache && cache->is_dirty == false); } -static void hair_batch_cache_init(Hair *hair) +static void curves_batch_cache_init(Curves *curves) { - HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); + HairBatchCache *cache = static_cast<HairBatchCache *>(curves->batch_cache); if (!cache) { cache = MEM_cnew<HairBatchCache>(__func__); - hair->batch_cache = cache; + curves->batch_cache = cache; } else { memset(cache, 0, sizeof(*cache)); @@ -79,28 +86,28 @@ static void hair_batch_cache_init(Hair *hair) cache->is_dirty = false; } -void DRW_hair_batch_cache_validate(Hair *hair) +void DRW_curves_batch_cache_validate(Curves *curves) { - if (!hair_batch_cache_valid(hair)) { - hair_batch_cache_clear(hair); - hair_batch_cache_init(hair); + if (!curves_batch_cache_valid(curves)) { + curves_batch_cache_clear(curves); + curves_batch_cache_init(curves); } } -static HairBatchCache *hair_batch_cache_get(Hair *hair) +static HairBatchCache *curves_batch_cache_get(Curves *curves) { - DRW_hair_batch_cache_validate(hair); - return static_cast<HairBatchCache *>(hair->batch_cache); + DRW_curves_batch_cache_validate(curves); + return static_cast<HairBatchCache *>(curves->batch_cache); } -void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode) +void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode) { - HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); + HairBatchCache *cache = static_cast<HairBatchCache *>(curves->batch_cache); if (cache == nullptr) { return; } switch (mode) { - case BKE_HAIR_BATCH_DIRTY_ALL: + case BKE_CURVES_BATCH_DIRTY_ALL: cache->is_dirty = true; break; default: @@ -108,9 +115,9 @@ void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode) } } -static void hair_batch_cache_clear(Hair *hair) +static void curves_batch_cache_clear(Curves *curves) { - HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); + HairBatchCache *cache = static_cast<HairBatchCache *>(curves->batch_cache); if (!cache) { return; } @@ -118,69 +125,67 @@ static void hair_batch_cache_clear(Hair *hair) particle_batch_cache_clear_hair(&cache->hair); } -void DRW_hair_batch_cache_free(Hair *hair) +void DRW_curves_batch_cache_free(Curves *curves) { - hair_batch_cache_clear(hair); - MEM_SAFE_FREE(hair->batch_cache); + curves_batch_cache_clear(curves); + MEM_SAFE_FREE(curves->batch_cache); } -static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache) +static void ensure_seg_pt_count(Curves *curves, ParticleHairCache *curves_cache) { - if ((hair_cache->pos != nullptr && hair_cache->indices != nullptr) || - (hair_cache->proc_point_buf != nullptr)) { + if ((curves_cache->pos != nullptr && curves_cache->indices != nullptr) || + (curves_cache->proc_point_buf != nullptr)) { return; } - hair_cache->strands_len = 0; - hair_cache->elems_len = 0; - hair_cache->point_len = 0; - - HairCurve *curve = hair->curves; - int num_curves = hair->totcurve; - for (int i = 0; i < num_curves; i++, curve++) { - hair_cache->strands_len++; - hair_cache->elems_len += curve->numpoints + 1; - hair_cache->point_len += curve->numpoints; - } + curves_cache->strands_len = curves->geometry.curve_size; + curves_cache->elems_len = curves->geometry.point_size + curves->geometry.curve_size; + curves_cache->point_len = curves->geometry.point_size; } -static void hair_batch_cache_fill_segments_proc_pos(Hair *hair, - GPUVertBufRaw *attr_step, - GPUVertBufRaw *length_step) +static void curves_batch_cache_fill_segments_proc_pos(Curves *curves, + GPUVertBufRaw *attr_step, + GPUVertBufRaw *length_step) { /* TODO: use hair radius layer if available. */ - HairCurve *curve = hair->curves; - int num_curves = hair->totcurve; - for (int i = 0; i < num_curves; i++, curve++) { - float(*curve_co)[3] = hair->co + curve->firstpoint; + const int curve_size = curves->geometry.curve_size; + Span<int> offsets{curves->geometry.offsets, curves->geometry.curve_size + 1}; + + Span<float3> positions{(float3 *)curves->geometry.position, curves->geometry.point_size}; + + for (const int i : IndexRange(curve_size)) { + const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]); + + Span<float3> spline_positions = positions.slice(curve_range); float total_len = 0.0f; - float *co_prev = nullptr, *seg_data_first; - for (int j = 0; j < curve->numpoints; j++) { + float *seg_data_first; + for (const int i_spline : spline_positions.index_range()) { float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step); - copy_v3_v3(seg_data, curve_co[j]); - if (co_prev) { - total_len += len_v3v3(co_prev, curve_co[j]); + copy_v3_v3(seg_data, spline_positions[i_spline]); + if (i_spline == 0) { + seg_data_first = seg_data; } else { - seg_data_first = seg_data; + total_len += blender::math::distance(spline_positions[i_spline - 1], + spline_positions[i_spline]); } seg_data[3] = total_len; - co_prev = curve_co[j]; } /* Assign length value. */ *(float *)GPU_vertbuf_raw_step(length_step) = total_len; if (total_len > 0.0f) { /* Divide by total length to have a [0-1] number. */ - for (int j = 0; j < curve->numpoints; j++, seg_data_first += 4) { + for ([[maybe_unused]] const int i_spline : spline_positions.index_range()) { seg_data_first[3] /= total_len; + seg_data_first += 4; } } } } -static void hair_batch_cache_ensure_procedural_pos(Hair *hair, - ParticleHairCache *cache, - GPUMaterial *gpu_material) +static void curves_batch_cache_ensure_procedural_pos(Curves *curves, + ParticleHairCache *cache, + GPUMaterial *gpu_material) { if (cache->proc_point_buf == nullptr) { /* initialize vertex format */ @@ -203,7 +208,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair, GPUVertBufRaw length_step; GPU_vertbuf_attr_get_raw_data(cache->proc_length_buf, length_id, &length_step); - hair_batch_cache_fill_segments_proc_pos(hair, &point_step, &length_step); + curves_batch_cache_fill_segments_proc_pos(curves, &point_step, &length_step); /* Create vbo immediately to bind to texture buffer. */ GPU_vertbuf_use(cache->proc_point_buf); @@ -222,19 +227,23 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair, } } -static void hair_batch_cache_fill_strands_data(Hair *hair, - GPUVertBufRaw *data_step, - GPUVertBufRaw *seg_step) +static void curves_batch_cache_fill_strands_data(Curves *curves, + GPUVertBufRaw *data_step, + GPUVertBufRaw *seg_step) { - HairCurve *curve = hair->curves; - int num_curves = hair->totcurve; - for (int i = 0; i < num_curves; i++, curve++) { - *(uint *)GPU_vertbuf_raw_step(data_step) = curve->firstpoint; - *(ushort *)GPU_vertbuf_raw_step(seg_step) = curve->numpoints - 1; + const int curve_size = curves->geometry.curve_size; + Span<int> offsets{curves->geometry.offsets, curves->geometry.curve_size + 1}; + + for (const int i : IndexRange(curve_size)) { + const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]); + + *(uint *)GPU_vertbuf_raw_step(data_step) = curve_range.start(); + *(ushort *)GPU_vertbuf_raw_step(seg_step) = curve_range.size() - 1; } } -static void hair_batch_cache_ensure_procedural_strand_data(Hair *hair, ParticleHairCache *cache) +static void curves_batch_cache_ensure_procedural_strand_data(Curves *curves, + ParticleHairCache *cache) { GPUVertBufRaw data_step, seg_step; @@ -253,18 +262,18 @@ static void hair_batch_cache_ensure_procedural_strand_data(Hair *hair, ParticleH GPU_vertbuf_data_alloc(cache->proc_strand_seg_buf, cache->strands_len); GPU_vertbuf_attr_get_raw_data(cache->proc_strand_seg_buf, seg_id, &seg_step); - hair_batch_cache_fill_strands_data(hair, &data_step, &seg_step); + curves_batch_cache_fill_strands_data(curves, &data_step, &seg_step); /* Create vbo immediately to bind to texture buffer. */ GPU_vertbuf_use(cache->proc_strand_buf); - cache->strand_tex = GPU_texture_create_from_vertbuf("hair_strand", cache->proc_strand_buf); + cache->strand_tex = GPU_texture_create_from_vertbuf("curves_strand", cache->proc_strand_buf); GPU_vertbuf_use(cache->proc_strand_seg_buf); - cache->strand_seg_tex = GPU_texture_create_from_vertbuf("hair_strand_seg", + cache->strand_seg_tex = GPU_texture_create_from_vertbuf("curves_strand_seg", cache->proc_strand_seg_buf); } -static void hair_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, int subdiv) +static void curves_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, int subdiv) { /* Same format as point_tex. */ GPUVertFormat format = {0}; @@ -285,14 +294,15 @@ static void hair_batch_cache_ensure_procedural_final_points(ParticleHairCache *c cache->final[subdiv].proc_buf); } -static void hair_batch_cache_fill_segments_indices(Hair *hair, - const int res, - GPUIndexBufBuilder *elb) +static void curves_batch_cache_fill_segments_indices(Curves *curves, + const int res, + GPUIndexBufBuilder *elb) { - HairCurve *curve = hair->curves; - int num_curves = hair->totcurve; + const int curve_size = curves->geometry.curve_size; + uint curr_point = 0; - for (int i = 0; i < num_curves; i++, curve++) { + + for ([[maybe_unused]] const int i : IndexRange(curve_size)) { for (int k = 0; k < res; k++) { GPU_indexbuf_add_generic_vert(elb, curr_point++); } @@ -300,10 +310,10 @@ static void hair_batch_cache_fill_segments_indices(Hair *hair, } } -static void hair_batch_cache_ensure_procedural_indices(Hair *hair, - ParticleHairCache *cache, - int thickness_res, - int subdiv) +static void curves_batch_cache_ensure_procedural_indices(Curves *curves, + ParticleHairCache *cache, + int thickness_res, + int subdiv) { BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */ @@ -328,7 +338,7 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair, GPUIndexBufBuilder elb; GPU_indexbuf_init_ex(&elb, prim_type, element_count, element_count); - hair_batch_cache_fill_segments_indices(hair, verts_per_hair, &elb); + curves_batch_cache_fill_segments_indices(curves, verts_per_hair, &elb); cache->final[subdiv].proc_hairs[thickness_res - 1] = GPU_batch_create_ex( prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX); @@ -341,9 +351,9 @@ bool hair_ensure_procedural_data(Object *object, int thickness_res) { bool need_ft_update = false; - Hair *hair = static_cast<Hair *>(object->data); + Curves *curves = static_cast<Curves *>(object->data); - HairBatchCache *cache = hair_batch_cache_get(hair); + HairBatchCache *cache = curves_batch_cache_get(curves); *r_hair_cache = &cache->hair; const int steps = 2; /* TODO: don't hard-code? */ @@ -351,29 +361,29 @@ bool hair_ensure_procedural_data(Object *object, /* Refreshed on combing and simulation. */ if ((*r_hair_cache)->proc_point_buf == nullptr) { - ensure_seg_pt_count(hair, &cache->hair); - hair_batch_cache_ensure_procedural_pos(hair, &cache->hair, gpu_material); + ensure_seg_pt_count(curves, &cache->hair); + curves_batch_cache_ensure_procedural_pos(curves, &cache->hair, gpu_material); need_ft_update = true; } /* Refreshed if active layer or custom data changes. */ if ((*r_hair_cache)->strand_tex == nullptr) { - hair_batch_cache_ensure_procedural_strand_data(hair, &cache->hair); + curves_batch_cache_ensure_procedural_strand_data(curves, &cache->hair); } /* Refreshed only on subdiv count change. */ if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) { - hair_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv); + curves_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv); need_ft_update = true; } if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) { - hair_batch_cache_ensure_procedural_indices(hair, &cache->hair, thickness_res, subdiv); + curves_batch_cache_ensure_procedural_indices(curves, &cache->hair, thickness_res, subdiv); } return need_ft_update; } -int DRW_hair_material_count_get(Hair *hair) +int DRW_curves_material_count_get(Curves *curves) { - return max_ii(1, hair->totcol); + return max_ii(1, curves->totcol); } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index f57921d058c..e7e0e97499f 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -505,8 +505,9 @@ static bool custom_data_match_attribute(const CustomData *custom_data, int *r_layer_index, int *r_type) { - const int possible_attribute_types[6] = { + const int possible_attribute_types[7] = { CD_PROP_BOOL, + CD_PROP_INT8, CD_PROP_INT32, CD_PROP_FLOAT, CD_PROP_FLOAT2, @@ -655,6 +656,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, break; } case CD_PROP_BOOL: + case CD_PROP_INT8: case CD_PROP_INT32: case CD_PROP_FLOAT: case CD_PROP_FLOAT2: diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index a24a3a5a3a7..4a8670a9ee2 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -999,7 +999,7 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache, cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); - // Build patch coordinates for all the face dots + /* Build patch coordinates for all the face dots. */ cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(), mesh_eval->totpoly); CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data( @@ -1760,7 +1760,7 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache, int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start")); int *subdiv_polygon_offset = cache->subdiv_polygon_offset; - // TODO: parallel_reduce? + /* TODO: parallel_reduce? */ for (int i = 0; i < mesh_eval->totpoly; i++) { const MPoly *mpoly = &mesh_eval->mpoly[i]; const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads : diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 65afc5ed3d8..82b830f6799 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -431,7 +431,7 @@ bool DRW_object_is_flat(Object *ob, int *r_axis) OB_SURF, OB_FONT, OB_MBALL, - OB_HAIR, + OB_CURVES, OB_POINTCLOUD, OB_VOLUME)) { /* Non-meshes object cannot be considered as flat. */ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 1249004eda0..039fae43329 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -35,11 +35,11 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_curves.h" #include "BKE_duplilist.h" #include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_hair.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mball.h" @@ -2948,8 +2948,8 @@ void DRW_engines_register(void) BKE_gpencil_batch_cache_dirty_tag_cb = DRW_gpencil_batch_cache_dirty_tag; BKE_gpencil_batch_cache_free_cb = DRW_gpencil_batch_cache_free; - BKE_hair_batch_cache_dirty_tag_cb = DRW_hair_batch_cache_dirty_tag; - BKE_hair_batch_cache_free_cb = DRW_hair_batch_cache_free; + BKE_curves_batch_cache_dirty_tag_cb = DRW_curves_batch_cache_dirty_tag; + BKE_curves_batch_cache_free_cb = DRW_curves_batch_cache_free; BKE_pointcloud_batch_cache_dirty_tag_cb = DRW_pointcloud_batch_cache_dirty_tag; BKE_pointcloud_batch_cache_free_cb = DRW_pointcloud_batch_cache_free; diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index d27eb8be9e0..73fd157426c 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -205,8 +205,10 @@ typedef enum { /* Compute Commands. */ DRW_CMD_COMPUTE = 8, + DRW_CMD_COMPUTE_REF = 9, /* Other Commands */ + DRW_CMD_BARRIER = 11, DRW_CMD_CLEAR = 12, DRW_CMD_DRWSTATE = 13, DRW_CMD_STENCIL = 14, @@ -249,6 +251,14 @@ typedef struct DRWCommandCompute { int groups_z_len; } DRWCommandCompute; +typedef struct DRWCommandComputeRef { + int *groups_ref; +} DRWCommandComputeRef; + +typedef struct DRWCommandBarrier { + eGPUBarrier type; +} DRWCommandBarrier; + typedef struct DRWCommandDrawProcedural { GPUBatch *batch; DRWResourceHandle handle; @@ -286,6 +296,8 @@ typedef union DRWCommand { DRWCommandDrawInstanceRange instance_range; DRWCommandDrawProcedural procedural; DRWCommandCompute compute; + DRWCommandComputeRef compute_ref; + DRWCommandBarrier barrier; DRWCommandSetMutableState state; DRWCommandSetStencil stencil; DRWCommandSetSelectID select_id; @@ -300,7 +312,7 @@ struct DRWCallBuffer { }; /** Used by #DRWUniform.type */ -/* TODO(jbakker): rename to DRW_RESOURCE/DRWResourceType. */ +/* TODO(@jbakker): rename to DRW_RESOURCE/DRWResourceType. */ typedef enum { DRW_UNIFORM_INT = 0, DRW_UNIFORM_INT_COPY, @@ -314,6 +326,7 @@ typedef enum { DRW_UNIFORM_BLOCK_REF, DRW_UNIFORM_TFEEDBACK_TARGET, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, + DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF, /** Per drawcall uniforms/UBO */ DRW_UNIFORM_BLOCK_OBMATS, DRW_UNIFORM_BLOCK_OBINFOS, @@ -345,6 +358,11 @@ struct DRWUniform { GPUUniformBuf *block; GPUUniformBuf **block_ref; }; + /* DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE */ + union { + GPUVertBuf *vertbuf; + GPUVertBuf **vertbuf_ref; + }; /* DRW_UNIFORM_FLOAT_COPY */ float fvalue[4]; /* DRW_UNIFORM_INT_COPY */ @@ -529,7 +547,7 @@ typedef struct DRWData { struct GHash *obattrs_ubo_pool; uint ubo_len; /** Texture pool to reuse temp texture across engines. */ - /* TODO(fclem) the pool could be shared even between viewports. */ + /* TODO(@fclem): The pool could be shared even between view-ports. */ struct DRWTexturePool *texture_pool; /** Per stereo view data. Contains engine data and default framebuffers. */ struct DRWViewData *view_data[2]; @@ -549,7 +567,7 @@ typedef struct DupliKey { typedef struct DRWManager { /* TODO: clean up this struct a bit. */ /* Cache generation */ - /* TODO(fclem) Rename to data. */ + /* TODO(@fclem): Rename to data. */ DRWData *vmempool; /** Active view data structure for one of the 2 stereo view. Not related to DRWView. */ struct DRWViewData *view_data_active; @@ -572,7 +590,7 @@ typedef struct DRWManager { struct ID *dupli_origin_data; /** Hash-map: #DupliKey -> void pointer for each enabled engine. */ struct GHash *dupli_ghash; - /** TODO(fclem): try to remove usage of this. */ + /** TODO(@fclem): try to remove usage of this. */ DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE]; /* Dupli data for the current dupli for each enabled engine. */ void **dupli_datas; @@ -615,7 +633,7 @@ typedef struct DRWManager { DRWView *view_active; DRWView *view_previous; uint primary_view_ct; - /** TODO(fclem): Remove this. Only here to support + /** TODO(@fclem): Remove this. Only here to support * shaders without common_view_lib.glsl */ DRWViewUboStorage view_storage_cpy; @@ -640,7 +658,7 @@ typedef struct DRWManager { GPUDrawList *draw_list; struct { - /* TODO(fclem): optimize: use chunks. */ + /* TODO(@fclem): optimize: use chunks. */ DRWDebugLine *lines; DRWDebugSphere *spheres; } debug; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index a4d5d6f3c31..3f299e878c4 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -283,19 +283,45 @@ void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, G drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_IMAGE_REF, tex, 0, 0, 1); } -void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, - const char *name, - const GPUUniformBuf *ubo) +void DRW_shgroup_uniform_block_ex(DRWShadingGroup *shgroup, + const char *name, + const GPUUniformBuf *ubo DRW_DEBUG_FILE_LINE_ARGS) { BLI_assert(ubo != NULL); int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); + if (loc == -1) { +#ifdef DRW_UNUSED_RESOURCE_TRACKING + printf("%s:%d: Unable to locate binding of shader uniform buffer object: %s.\n", + file, + line, + name); +#else + /* TODO(@fclem): Would be good to have, but eevee has too much of this for the moment. */ + // BLI_assert_msg(0, "Unable to locate binding of shader uniform buffer objects."); +#endif + return; + } drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK, ubo, 0, 0, 1); } -void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup, const char *name, GPUUniformBuf **ubo) +void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUUniformBuf **ubo DRW_DEBUG_FILE_LINE_ARGS) { BLI_assert(ubo != NULL); int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); + if (loc == -1) { +#ifdef DRW_UNUSED_RESOURCE_TRACKING + printf("%s:%d: Unable to locate binding of shader uniform buffer object: %s.\n", + file, + line, + name); +#else + /* TODO(@fclem): Would be good to have, but eevee has too much of this for the moment. */ + // BLI_assert_msg(0, "Unable to locate binding of shader uniform buffer objects."); +#endif + return; + } drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, 0, 0, 1); } @@ -447,19 +473,46 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, } } -void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup, - const char *name, - GPUVertBuf *vertex_buffer) +void DRW_shgroup_vertex_buffer_ex(DRWShadingGroup *shgroup, + const char *name, + GPUVertBuf *vertex_buffer DRW_DEBUG_FILE_LINE_ARGS) { int location = GPU_shader_get_ssbo(shgroup->shader, name); if (location == -1) { +#ifdef DRW_UNUSED_RESOURCE_TRACKING + printf("%s:%d: Unable to locate binding of shader storage buffer object: %s.\n", + file, + line, + name); +#else BLI_assert_msg(0, "Unable to locate binding of shader storage buffer objects."); +#endif return; } drw_shgroup_uniform_create_ex( shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, vertex_buffer, 0, 0, 1); } +void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup, + const char *name, + GPUVertBuf **vertex_buffer DRW_DEBUG_FILE_LINE_ARGS) +{ + int location = GPU_shader_get_ssbo(shgroup->shader, name); + if (location == -1) { +#ifdef DRW_UNUSED_RESOURCE_TRACKING + printf("%s:%d: Unable to locate binding of shader storage buffer object: %s.\n", + file, + line, + name); +#else + BLI_assert_msg(0, "Unable to locate binding of shader storage buffer objects."); +#endif + return; + } + drw_shgroup_uniform_create_ex( + shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF, vertex_buffer, 0, 0, 1); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -730,6 +783,18 @@ static void drw_command_compute(DRWShadingGroup *shgroup, cmd->groups_z_len = groups_z_len; } +static void drw_command_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3]) +{ + DRWCommandComputeRef *cmd = drw_command_create(shgroup, DRW_CMD_COMPUTE_REF); + cmd->groups_ref = groups_ref; +} + +static void drw_command_barrier(DRWShadingGroup *shgroup, eGPUBarrier type) +{ + DRWCommandBarrier *cmd = drw_command_create(shgroup, DRW_CMD_BARRIER); + cmd->type = type; +} + static void drw_command_draw_procedural(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, @@ -816,7 +881,7 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, culling->user_data = user_data; } if (bypass_culling) { - /* NOTE this will disable culling for the whole object. */ + /* NOTE: this will disable culling for the whole object. */ culling->bsphere.radius = -1.0f; } } @@ -855,6 +920,20 @@ void DRW_shgroup_call_compute(DRWShadingGroup *shgroup, drw_command_compute(shgroup, groups_x_len, groups_y_len, groups_z_len); } +void DRW_shgroup_call_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3]) +{ + BLI_assert(GPU_compute_shader_support()); + + drw_command_compute_ref(shgroup, groups_ref); +} + +void DRW_shgroup_barrier(DRWShadingGroup *shgroup, eGPUBarrier type) +{ + BLI_assert(GPU_compute_shader_support()); + + drw_command_barrier(shgroup, type); +} + static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, @@ -1248,7 +1327,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK); int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID); - /* TODO(fclem) Will take the place of the above after the GPUShaderCreateInfo port. */ + /* TODO(@fclem): Will take the place of the above after the GPUShaderCreateInfo port. */ if (view_ubo_location == -1) { view_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_DRW_VIEW); } diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 2095a8483d6..a579403975f 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -662,8 +662,11 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, ((GPUVertBuf *)uni->pvalue)); break; + case DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF: + GPU_vertbuf_bind_as_ssbo(*uni->vertbuf_ref, uni->location); + break; case DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE: - GPU_vertbuf_bind_as_ssbo((GPUVertBuf *)uni->pvalue, uni->location); + GPU_vertbuf_bind_as_ssbo(uni->vertbuf, uni->location); break; /* Legacy/Fallback support. */ case DRW_UNIFORM_BASE_INSTANCE: @@ -1049,6 +1052,15 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) cmd->compute.groups_y_len, cmd->compute.groups_z_len); break; + case DRW_CMD_COMPUTE_REF: + GPU_compute_dispatch(shgroup->shader, + cmd->compute_ref.groups_ref[0], + cmd->compute_ref.groups_ref[1], + cmd->compute_ref.groups_ref[2]); + break; + case DRW_CMD_BARRIER: + GPU_memory_barrier(cmd->barrier.type); + break; } } diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 35350417ca8..fba8f91b2f6 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -1,6 +1,6 @@ #ifndef GPU_SHADER -# include "gpu_shader_shared_utils.h" +# include "GPU_shader_shared_utils.h" #endif #define DRW_SHADER_SHARED_H @@ -23,7 +23,7 @@ struct ViewInfos { }; BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16) -/* TODO(fclem) Mass rename. */ +/* TODO(@fclem): Mass rename. */ #define ViewProjectionMatrix drw_view.persmat #define ViewProjectionMatrixInverse drw_view.persinv #define ViewMatrix drw_view.viewmat diff --git a/source/blender/draw/intern/draw_view_data.h b/source/blender/draw/intern/draw_view_data.h index b37e48c11e8..98ada5a59cb 100644 --- a/source/blender/draw/intern/draw_view_data.h +++ b/source/blender/draw/intern/draw_view_data.h @@ -35,7 +35,7 @@ struct DRWRegisteredDrawEngine; struct DrawEngineType; struct GPUViewport; -/* NOTE these structs are only here for reading the actual lists from the engine. +/* NOTE: these structs are only here for reading the actual lists from the engine. * The actual length of them is stored in a ViewportEngineData_Info. * The length of 1 is just here to avoid compiler warning. */ typedef struct FramebufferList { 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 b846da3f016..b27633405b9 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 @@ -99,9 +99,10 @@ static uint gpu_component_size_for_attribute_type(CustomDataType type) { switch (type) { case CD_PROP_BOOL: + case CD_PROP_INT8: case CD_PROP_INT32: case CD_PROP_FLOAT: { - /* TODO(kevindietrich) : should be 1 when scalar attributes conversion is handled by us. See + /* TODO(@kevindietrich): should be 1 when scalar attributes conversion is handled by us. See * comment #extract_attr_init. */ return 3; } @@ -317,7 +318,7 @@ static void extract_attr_init(const MeshRenderData *mr, init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len)); - /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by + /* 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. */ @@ -326,6 +327,10 @@ static void extract_attr_init(const MeshRenderData *mr, extract_attr_generic<bool, float3>(mr, vbo, request); break; } + case CD_PROP_INT8: { + extract_attr_generic<int8_t, float3>(mr, vbo, request); + break; + } case CD_PROP_INT32: { extract_attr_generic<int32_t, float3>(mr, vbo, request); break; @@ -378,6 +383,10 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache, extract_attr_generic<bool, float3>(mr, src_data, request); break; } + case CD_PROP_INT8: { + extract_attr_generic<int8_t, float3>(mr, src_data, request); + break; + } case CD_PROP_INT32: { extract_attr_generic<int32_t, float3>(mr, src_data, request); break; 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 8470a71059f..4185f2f84a2 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 @@ -78,7 +78,7 @@ static void extract_edge_fac_init(const MeshRenderData *mr, data->edge_loop_count = static_cast<uchar *>( MEM_callocN(sizeof(uint32_t) * mr->edge_len, __func__)); - /* HACK(fclem) Detecting the need for edge render. + /* HACK(@fclem): Detecting the need for edge render. * We could have a flag in the mesh instead or check the modifier stack. */ const MEdge *med = mr->medge; for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) { 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 5d2ea923658..11f1515275c 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 @@ -270,7 +270,7 @@ static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache const MVert *coarse_verts = coarse_mesh->mvert; uint offset = subdiv_cache->num_subdiv_loops; - /* TODO(kevindietrich) : replace this when compressed normals are supported. */ + /* TODO(@kevindietrich): replace this when compressed normals are supported. */ struct SubdivPosNorLoop { float pos[3]; float nor[3]; diff --git a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl index bf59972fbaa..599d875c500 100644 --- a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl +++ b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl @@ -51,7 +51,7 @@ /*============================================================================ FXAA QUALITY - TUNING KNOBS ------------------------------------------------------------------------------ -NOTE the other tuning knobs are now in the shader function inputs! +NOTE: the other tuning knobs are now in the shader function inputs! ============================================================================*/ #ifndef FXAA_QUALITY__PRESET /* diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl index 9dd86c35ee4..e6538d80111 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl @@ -101,7 +101,7 @@ uint get_index(uint i) * the format. */ struct PosNorLoop { float x, y, z; - /* TODO(kevindietrich) : figure how to compress properly as GLSL does not have char/short types, + /* TODO(@kevindietrich): figure how to compress properly as GLSL does not have char/short types, * bit operations get tricky. */ float nx, ny, nz; float flag; diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index d4d18b95238..2ac157ad208 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -1,5 +1,5 @@ /* Temporary until we fully make the switch. */ -#ifndef DRW_SHADER_SHARED_H +#ifndef USE_GPU_SHADER_CREATE_INFO # define DRW_RESOURCE_CHUNK_LEN 512 @@ -24,7 +24,13 @@ layout(std140) uniform viewBlock vec4 CameraTexCoFactors; }; -#endif /* DRW_SHADER_SHARED_H */ +#endif /* USE_GPU_SHADER_CREATE_INFO */ + +#ifdef USE_GPU_SHADER_CREATE_INFO +# ifndef DRW_RESOURCE_CHUNK_LEN +# error "Missing draw_view additional create info on shader create info" +# endif +#endif #define ViewNear (ViewVecs[0].w) #define ViewFar (ViewVecs[1].w) diff --git a/source/blender/draw/intern/shaders/draw_hair_refine_info.hh b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh index b41be7d8605..bdfc26b7dcd 100644 --- a/source/blender/draw/intern/shaders/draw_hair_refine_info.hh +++ b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh @@ -25,7 +25,7 @@ GPU_SHADER_CREATE_INFO(draw_hair_refine_compute) .local_group_size(1, 1) - .storage_buf(0, Qualifier::WRITE_ONLY, "vec4", "posTime[]") + .storage_buf(0, Qualifier::WRITE, "vec4", "posTime[]") .sampler(0, ImageType::FLOAT_BUFFER, "hairPointBuffer") .sampler(1, ImageType::UINT_BUFFER, "hairStrandBuffer") .sampler(2, ImageType::UINT_BUFFER, "hairStrandSegBuffer") diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index 0a25059ffed..f9dcf291f95 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -30,7 +30,7 @@ GPU_SHADER_CREATE_INFO(draw_resource_id_uniform) /** * Declare a resource handle that identify a unique object. - * Requires draw_resource_id[_constant]. + * Requires draw_resource_id[_uniform]. */ GPU_SHADER_CREATE_INFO(draw_resource_handle) .define("resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)") @@ -83,7 +83,7 @@ GPU_SHADER_CREATE_INFO(draw_hair) .sampler(15, ImageType::FLOAT_BUFFER, "hairPointBuffer") .sampler(14, ImageType::UINT_BUFFER, "hairStrandBuffer") .sampler(13, ImageType::UINT_BUFFER, "hairStrandSegBuffer") - /* TODO(fclem) Pack thoses into one UBO. */ + /* TODO(@fclem): Pack these into one UBO. */ .push_constant(Type::INT, "hairStrandsRes") .push_constant(Type::INT, "hairThicknessRes") .push_constant(Type::FLOAT, "hairRadRoot") diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index 6fa4d94df3a..0baac40660d 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -60,10 +60,6 @@ set(LIB bf_blenlib ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 2eaa42ee578..a697fd2fc96 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -35,8 +35,8 @@ #include "DNA_armature_types.h" #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" +#include "DNA_curves_types.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_light_types.h" @@ -700,8 +700,8 @@ static int acf_object_icon(bAnimListElem *ale) return ICON_OUTLINER_OB_FONT; case OB_SURF: return ICON_OUTLINER_OB_SURFACE; - case OB_HAIR: - return ICON_OUTLINER_OB_HAIR; + case OB_CURVES: + return ICON_OUTLINER_OB_CURVES; case OB_POINTCLOUD: return ICON_OUTLINER_OB_POINTCLOUD; case OB_VOLUME: @@ -2813,15 +2813,15 @@ static bAnimChannelType ACF_DSSPK = { /* Hair Expander ------------------------------------------- */ /* TODO: just get this from RNA? */ -static int acf_dshair_icon(bAnimListElem *UNUSED(ale)) +static int acf_dscurves_icon(bAnimListElem *UNUSED(ale)) { - return ICON_HAIR_DATA; + return ICON_CURVES_DATA; } /* Get the appropriate flag(s) for the setting when it is valid. */ -static int acf_dshair_setting_flag(bAnimContext *UNUSED(ac), - eAnimChannel_Settings setting, - bool *neg) +static int acf_dscurves_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { /* clear extra return data first */ *neg = false; @@ -2846,22 +2846,24 @@ static int acf_dshair_setting_flag(bAnimContext *UNUSED(ac), } /* get pointer to the setting */ -static void *acf_dshair_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dscurves_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - Hair *hair = (Hair *)ale->data; + Curves *curves = (Curves *)ale->data; /* clear extra return data first */ *type = 0; switch (setting) { case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(hair->flag, type); + return GET_ACF_FLAG_PTR(curves->flag, type); case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (hair->adt) { - return GET_ACF_FLAG_PTR(hair->adt->flag, type); + if (curves->adt) { + return GET_ACF_FLAG_PTR(curves->adt->flag, type); } return NULL; @@ -2870,9 +2872,9 @@ static void *acf_dshair_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings se } } -/* hair expander type define */ +/* Curves expander type define */ static bAnimChannelType ACF_DSHAIR = { - "Hair Expander", /* type name */ + "Curves Expander", /* type name */ ACHANNEL_ROLE_EXPANDER, /* role */ acf_generic_dataexpand_color, /* backdrop color */ @@ -2882,11 +2884,11 @@ static bAnimChannelType ACF_DSHAIR = { acf_generic_idblock_name, /* name */ acf_generic_idblock_name_prop, /* name prop */ - acf_dshair_icon, /* icon */ + acf_dscurves_icon, /* icon */ acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dshair_setting_flag, /* flag for setting */ - acf_dshair_setting_ptr /* pointer for setting */ + acf_dscurves_setting_flag, /* flag for setting */ + acf_dscurves_setting_ptr /* pointer for setting */ }; /* PointCloud Expander ------------------------------------------- */ @@ -3418,7 +3420,7 @@ static void acf_gpd_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), /* TODO: just get this from RNA? */ static int acf_gpd_icon(bAnimListElem *UNUSED(ale)) { - return ICON_GREASEPENCIL; + return ICON_OUTLINER_OB_GREASEPENCIL; } /* check if some setting exists for this channel */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index c1a09b9d21f..3307385b84a 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -47,8 +47,8 @@ #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" +#include "DNA_curves_types.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_layer_types.h" @@ -791,10 +791,10 @@ static bAnimListElem *make_new_animlistelem(void *data, break; } case ANIMTYPE_DSHAIR: { - Hair *hair = (Hair *)data; - AnimData *adt = hair->adt; + Curves *curves = (Curves *)data; + AnimData *adt = curves->adt; - ale->flag = FILTER_HAIR_OBJD(hair); + ale->flag = FILTER_CURVES_OBJD(curves); ale->key_data = (adt) ? adt->action : NULL; ale->datatype = ALE_ACT; @@ -2616,16 +2616,16 @@ static size_t animdata_filter_ds_obdata( expanded = FILTER_SPK_OBJD(spk); break; } - case OB_HAIR: /* ---------- Hair ----------- */ + case OB_CURVES: /* ---------- Curves ----------- */ { - Hair *hair = (Hair *)ob->data; + Curves *curves = (Curves *)ob->data; if (ads->filterflag2 & ADS_FILTER_NOHAIR) { return 0; } type = ANIMTYPE_DSHAIR; - expanded = FILTER_HAIR_OBJD(hair); + expanded = FILTER_CURVES_OBJD(curves); break; } case OB_POINTCLOUD: /* ---------- PointCloud ----------- */ diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h index fb7b6b8983a..9029c451290 100644 --- a/source/blender/editors/animation/anim_intern.h +++ b/source/blender/editors/animation/anim_intern.h @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung + * The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung. * This is a new part of Blender (with some old code) */ diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index aff5803f037..c8ca27c64a3 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -63,9 +63,5 @@ set(LIB bf_blenlib ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_armature "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 02ecfdb4ea6..e1d4b5fec73 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Operators and API's for creating bones */ /** \file * \ingroup edarmature + * Operators and API's for creating bones. */ #include "DNA_anim_types.h" @@ -581,8 +581,6 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob, { /* This code assumes that bRotLimitConstraint and bLocLimitConstraint have the same fields in * the same memory locations. */ - BLI_assert(sizeof(bLocLimitConstraint) == sizeof(bRotLimitConstraint)); - bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data; float local_mat[4][4], imat[4][4]; @@ -798,6 +796,13 @@ static void updateDuplicateTransformConstraintSettings(Object *ob, trans->to_min_rot[i] = temp_vec[i]; } } + + if (trans->from == TRANS_ROTATION && trans->map[1] == Y) { + /* Y Rot to Y Rot: Flip and invert */ + trans->to_max_rot[1] = -trans->to_min_rot[1]; + trans->to_min_rot[1] = -temp_vec[1]; + } + break; } /* convert back to the settings space */ @@ -854,14 +859,28 @@ static void updateDuplicateCustomBoneShapes(bContext *C, EditBone *dup_bone, Obj Main *bmain = CTX_data_main(C); char name_flip[MAX_ID_NAME - 2]; + /* Invert the X location */ + pchan->custom_translation[0] *= -1; + /* Invert the Y rotation */ + pchan->custom_rotation_euler[1] *= -1; + /* Invert the Z rotation */ + pchan->custom_rotation_euler[2] *= -1; + /* Skip the first two chars in the object name as those are used to store object type */ BLI_string_flip_side_name(name_flip, pchan->custom->id.name + 2, false, sizeof(name_flip)); Object *shape_ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip); + /* If name_flip doesn't exist, BKE_libblock_find_name() returns pchan->custom (best match) */ + shape_ob = shape_ob == pchan->custom ? NULL : shape_ob; + if (shape_ob != NULL) { /* A flipped shape object exists, use it! */ pchan->custom = shape_ob; } + else { + /* Flip shape */ + pchan->custom_scale_xyz[0] *= -1; + } } } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index b709980cabe..0094783e50f 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Armature EditMode tools - transforms, chain based editing, and other settings */ /** \file * \ingroup edarmature + * Armature EditMode tools - transforms, chain based editing, and other settings. */ #include "DNA_armature_types.h" diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 252cf806e34..aaeac29b7d0 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -27,6 +27,7 @@ struct wmOperatorType; struct Base; +struct GPUSelectResult; struct Object; struct Scene; struct bContext; @@ -323,21 +324,21 @@ struct Bone *ED_armature_pick_bone(struct bContext *C, struct EditBone *ED_armature_pick_ebone_from_selectbuffer(struct Base **bases, uint bases_len, - const uint *buffer, + const struct GPUSelectResult *buffer, short hits, bool findunsel, bool do_nearest, struct Base **r_base); struct bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(struct Base **bases, uint bases_len, - const uint *buffer, + const struct GPUSelectResult *buffer, short hits, bool findunsel, bool do_nearest, struct Base **r_base); struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases, uint bases_len, - const uint *buffer, + const struct GPUSelectResult *buffer, short hits, bool findunsel, bool do_nearest, diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 750c64d74a7..c45c6297d86 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Operators and API's for renaming bones both in and out of Edit Mode */ /** \file * \ingroup edarmature + * Operators and API's for renaming bones both in and out of Edit Mode. * * This file contains functions/API's for renaming bones and/or working with them. */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index eebe8a447f7..17d25aec198 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Operators for relations between bones and for transferring bones between armature objects */ /** \file * \ingroup edarmature + * Operators for relations between bones and for transferring bones between armature objects. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 5e4cb813064..111989f1d86 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * API's and Operators for selecting armature bones in EditMode */ /** \file * \ingroup edarmature + * API's and Operators for selecting armature bones in EditMode. */ #include "MEM_guardedalloc.h" @@ -55,6 +55,8 @@ #include "DEG_depsgraph.h" +#include "GPU_select.h" + #include "armature_intern.h" /* utility macros for storing a temp int in the bone (selection flag) */ @@ -67,10 +69,10 @@ Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases, uint bases_len, - int hit, + const uint select_id, EditBone **r_ebone) { - const uint hit_object = hit & 0xFFFF; + const uint hit_object = select_id & 0xFFFF; Base *base = NULL; EditBone *ebone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ @@ -81,7 +83,7 @@ Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases, } } if (base != NULL) { - const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + const uint hit_bone = (select_id & ~BONESEL_ANY) >> 16; bArmature *arm = base->object->data; ebone = BLI_findlink(arm->edbo, hit_bone); } @@ -91,10 +93,10 @@ Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases, Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects, uint objects_len, - int hit, + const uint select_id, EditBone **r_ebone) { - const uint hit_object = hit & 0xFFFF; + const uint hit_object = select_id & 0xFFFF; Object *ob = NULL; EditBone *ebone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ @@ -105,7 +107,7 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects, } } if (ob != NULL) { - const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + const uint hit_bone = (select_id & ~BONESEL_ANY) >> 16; bArmature *arm = ob->data; ebone = BLI_findlink(arm->edbo, hit_bone); } @@ -115,10 +117,10 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects, Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases, uint bases_len, - int hit, + const uint select_id, bPoseChannel **r_pchan) { - const uint hit_object = hit & 0xFFFF; + const uint hit_object = select_id & 0xFFFF; Base *base = NULL; bPoseChannel *pchan = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ @@ -130,7 +132,7 @@ Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases, } if (base != NULL) { if (base->object->pose != NULL) { - const uint hit_bone = (hit & ~BONESEL_ANY) >> 16; + const uint hit_bone = (select_id & ~BONESEL_ANY) >> 16; /* pchan may be NULL. */ pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone); } @@ -141,11 +143,11 @@ Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases, Base *ED_armature_base_and_bone_from_select_buffer(Base **bases, uint bases_len, - int hit, + const uint select_id, Bone **r_bone) { bPoseChannel *pchan = NULL; - Base *base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hit, &pchan); + Base *base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, select_id, &pchan); *r_bone = pchan ? pchan->bone : NULL; return base; } @@ -166,8 +168,8 @@ Base *ED_armature_base_and_bone_from_select_buffer(Base **bases, static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode, Base **bases, uint bases_len, - const uint *buffer, - short hits, + const GPUSelectResult *buffer, + const short hits, bool findunsel, bool do_nearest, Base **r_base) @@ -181,7 +183,7 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode int minsel = 0xffffffff, minunsel = 0xffffffff; for (short i = 0; i < hits; i++) { - hitresult = buffer[3 + (i * 4)]; + hitresult = buffer[i].id; if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */ Base *base = NULL; @@ -221,10 +223,10 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode if (data) { if (sel) { if (do_nearest) { - if (minsel > buffer[4 * i + 1]) { + if (minsel > buffer[i].depth) { firstSel = data; firstSel_base = base; - minsel = buffer[4 * i + 1]; + minsel = buffer[i].depth; } } else { @@ -237,10 +239,10 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode } else { if (do_nearest) { - if (minunsel > buffer[4 * i + 1]) { + if (minunsel > buffer[i].depth) { firstunSel = data; firstunSel_base = base; - minunsel = buffer[4 * i + 1]; + minunsel = buffer[i].depth; } } else { @@ -268,8 +270,8 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode EditBone *ED_armature_pick_ebone_from_selectbuffer(Base **bases, uint bases_len, - const uint *buffer, - short hits, + const GPUSelectResult *buffer, + const short hits, bool findunsel, bool do_nearest, Base **r_base) @@ -281,8 +283,8 @@ EditBone *ED_armature_pick_ebone_from_selectbuffer(Base **bases, bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(Base **bases, uint bases_len, - const uint *buffer, - short hits, + const GPUSelectResult *buffer, + const short hits, bool findunsel, bool do_nearest, Base **r_base) @@ -294,8 +296,8 @@ bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(Base **bases, Bone *ED_armature_pick_bone_from_selectbuffer(Base **bases, uint bases_len, - const uint *buffer, - short hits, + const GPUSelectResult *buffer, + const short hits, bool findunsel, bool do_nearest, Base **r_base) @@ -327,7 +329,7 @@ static void *ed_armature_pick_bone_impl( Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; rcti rect; - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; short hits; ED_view3d_viewcontext_init(C, &vc, depsgraph); @@ -340,7 +342,7 @@ static void *ed_armature_pick_bone_impl( hits = view3d_opengl_select_with_id_filter(&vc, buffer, - MAXPICKBUF, + ARRAY_SIZE(buffer), &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP, @@ -636,15 +638,15 @@ void ARMATURE_OT_select_linked_pick(wmOperatorType *ot) * \{ */ /* utility function for get_nearest_editbonepoint */ -static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12) +static int selectbuffer_ret_hits_12(GPUSelectResult *UNUSED(buffer), const int hits12) { return hits12; } -static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5) +static int selectbuffer_ret_hits_5(GPUSelectResult *buffer, const int hits12, const int hits5) { - const int ofs = 4 * hits12; - memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint)); + const int ofs = hits12; + memcpy(buffer, buffer + ofs, hits5 * sizeof(*buffer)); return hits5; } @@ -653,7 +655,7 @@ static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hit static EditBone *get_nearest_editbonepoint( ViewContext *vc, bool findunsel, bool use_cycle, Base **r_base, int *r_selmask) { - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; struct { uint hitresult; Base *base; @@ -692,7 +694,7 @@ static EditBone *get_nearest_editbonepoint( rcti rect; BLI_rcti_init_pt_radius(&rect, vc->mval, 12); const int hits12 = view3d_opengl_select_with_id_filter( - vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter, select_id_ignore); + vc, buffer, ARRAY_SIZE(buffer), &rect, select_mode, select_filter, select_id_ignore); if (hits12 == 1) { hits = selectbuffer_ret_hits_12(buffer, hits12); @@ -701,10 +703,15 @@ static EditBone *get_nearest_editbonepoint( else if (hits12 > 0) { int ofs; - ofs = 4 * hits12; + ofs = hits12; BLI_rcti_init_pt_radius(&rect, vc->mval, 5); - const int hits5 = view3d_opengl_select_with_id_filter( - vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter, select_id_ignore); + const int hits5 = view3d_opengl_select_with_id_filter(vc, + buffer + ofs, + ARRAY_SIZE(buffer) - ofs, + &rect, + select_mode, + select_filter, + select_id_ignore); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); @@ -732,7 +739,7 @@ cache_end: /* See if there are any selected bones in this group */ if (hits > 0) { if (hits == 1) { - result_bias.hitresult = buffer[3]; + result_bias.hitresult = buffer->id; result_bias.base = ED_armature_base_and_ebone_from_select_buffer( bases, bases_len, result_bias.hitresult, &result_bias.ebone); } @@ -771,7 +778,7 @@ cache_end: } for (int i = 0; i < hits; i++) { - const uint hitresult = buffer[3 + (i * 4)]; + const uint hitresult = buffer[i].id; Base *base = NULL; EditBone *ebone; diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index ec5c665402b..9ef198f442c 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -15,12 +15,12 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * API's for creating vertex groups from bones - * - Interfaces with heat weighting in meshlaplacian */ /** \file * \ingroup edarmature + * API's for creating vertex groups from bones + * - Interfaces with heat weighting in meshlaplacian. */ #include "DNA_armature_types.h" diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 14f47a84286..b3b6c37cf61 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -12,11 +12,11 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * meshlaplacian.c: Algorithms using the mesh laplacian. */ /** \file * \ingroup edarmature + * Algorithms using the mesh laplacian. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h index 7e7b64c7510..f024b17f1cc 100644 --- a/source/blender/editors/armature/meshlaplacian.h +++ b/source/blender/editors/armature/meshlaplacian.h @@ -12,12 +12,11 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * BIF_meshlaplacian.h: Algorithms using the mesh laplacian. */ /** \file * \ingroup edarmature + * BIF_meshlaplacian.h: Algorithms using the mesh laplacian. */ #pragma once diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 8bd6c9f54fd..5db4a4b6eaa 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Pose Mode API's and Operators for Pose Mode armatures */ /** \file * \ingroup edarmature + * Pose Mode API's and Operators for Pose Mode armatures. */ #include "MEM_guardedalloc.h" @@ -149,36 +149,6 @@ bool ED_object_posemode_exit(bContext *C, Object *ob) return ok; } -/* if a selected or active bone is protected, throw error (only if warn == 1) and return 1 */ -/* only_selected == 1: the active bone is allowed to be protected */ -#if 0 /* UNUSED 2.5 */ -static bool pose_has_protected_selected(Object *ob, short warn) -{ - /* check protection */ - if (ob->proxy) { - bPoseChannel *pchan; - bArmature *arm = ob->data; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone && BKE_pose_is_layer_visible(arm, pchan)) { - if (pchan->bone->layer & arm->layer_protected) { - if (pchan->bone->flag & BONE_SELECTED) { - break; - } - } - } - } - if (pchan) { - if (warn) { - error("Cannot change Proxy protected bones"); - } - return 1; - } - } - return 0; -} -#endif - /* ********************************************** */ /* Motion Paths */ @@ -1056,10 +1026,6 @@ static int pose_hide_exec(bContext *C, wmOperator *op) Object *ob_iter = objects[ob_index]; bArmature *arm = ob_iter->data; - if (ob_iter->proxy != NULL) { - BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected"); - } - bool changed = bone_looper(ob_iter, arm->bonebase.first, hide_select_p, hide_pose_bone_fn) != 0; if (changed) { diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 38d15d8b880..10ffa3fcae2 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2008 Blender Foundation * All rights reserved. - * Implementation of Bone Groups operators and editing API's */ /** \file * \ingroup edarmature + * Implementation of Bone Groups operators and editing API's. */ #include <string.h> @@ -62,8 +62,8 @@ static bool pose_group_poll(bContext *C) } Object *obpose = ED_pose_object_from_context(C); - if ((obpose->proxy != NULL) || (obpose->proxy_group != NULL) || ID_IS_OVERRIDE_LIBRARY(obpose)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit bone groups for proxies or library overrides"); + if (ID_IS_OVERRIDE_LIBRARY(obpose)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit bone groups for library overrides"); return false; } diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 0b889149f9d..f41c3657431 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -240,8 +240,8 @@ void ED_armature_pose_select_pick_bone(ViewLayer *view_layer, bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, View3D *v3d, Base *base, - const uint *buffer, - short hits, + const struct GPUSelectResult *buffer, + const short hits, bool extend, bool deselect, bool toggle, diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt index 086fab4ab47..d91102528e5 100644 --- a/source/blender/editors/asset/CMakeLists.txt +++ b/source/blender/editors/asset/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../blentranslation ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index c075ae390d9..fa0946ffe3d 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -41,6 +41,7 @@ #include "WM_api.h" /* XXX uses private header of file-space. */ +#include "../space_file/file_indexer.h" #include "../space_file/filelist.h" #include "ED_asset_handle.h" @@ -170,7 +171,8 @@ void AssetList::setup() "", ""); - filelist_setindexer(files, &file_indexer_asset); + const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing); + filelist_setindexer(files, use_asset_indexer ? &file_indexer_asset : &file_indexer_noop); char path[FILE_MAXDIR] = ""; if (user_library) { diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index f7755aa9fea..0469f14487d 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -39,6 +39,8 @@ /* XXX needs access to the file list, should all be done via the asset system in future. */ #include "ED_fileselect.h" +#include "BLT_translation.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -342,8 +344,8 @@ static bool asset_clear_poll(bContext *C) IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_context(C); if (!ctx_stats.has_asset) { - const char *msg_single = "Data-block is not marked as asset"; - const char *msg_multiple = "No data-block selected that is marked as asset"; + const char *msg_single = TIP_("Data-block is not marked as asset"); + const char *msg_multiple = TIP_("No data-block selected that is marked as asset"); CTX_wm_operator_poll_msg_set(C, ctx_stats.is_single ? msg_single : msg_multiple); return false; } @@ -365,8 +367,8 @@ static char *asset_clear_get_description(struct bContext *UNUSED(C), } return BLI_strdup( - "Delete all asset metadata, turning the selected asset data-blocks back into normal " - "data-blocks, and set Fake User to ensure the data-blocks will still be saved"); + TIP_("Delete all asset metadata, turning the selected asset data-blocks back into normal " + "data-blocks, and set Fake User to ensure the data-blocks will still be saved")); } static void ASSET_OT_clear(wmOperatorType *ot) diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt index 877c2d99102..0ac572c0422 100644 --- a/source/blender/editors/curve/CMakeLists.txt +++ b/source/blender/editors/curve/CMakeLists.txt @@ -51,9 +51,5 @@ set(LIB extern_curve_fit_nd ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_curve "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c index 3635ceb8f13..3871c1de77a 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c @@ -91,7 +91,7 @@ static void gizmo_calc_rect_view_scale(const wmGizmo *gz, const float dims[3], f static void gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[3], float margin[3]) { - const float handle_size = 0.15f; + const float handle_size = 9.0f; /* XXX, the scale isn't taking offset into account, we need to calculate scale per handle! */ // handle_size *= gz->scale_final; @@ -178,7 +178,7 @@ static void cage3d_draw_box_interaction(const RegionView3D *rv3d, float co_test[3]; mul_v3_m4v3(co_test, matrix_final, co); float rad_scale[3]; - mul_v3_v3fl(rad_scale, rad, ED_view3d_pixel_size(rv3d, co_test) * 60); + mul_v3_v3fl(rad_scale, rad, ED_view3d_pixel_size(rv3d, co_test)); { uint pos = GPU_vertformat_attr_add( @@ -255,7 +255,7 @@ static void cage3d_draw_circle_handles(const RegionView3D *rv3d, const float margin[3], const float color[3], bool solid, - float scale) + const float handle_scale) { uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); const float rad[3] = {margin[0] / 3, margin[1] / 3, margin[2] / 3}; @@ -274,7 +274,7 @@ static void cage3d_draw_circle_handles(const RegionView3D *rv3d, float co_test[3]; mul_v3_m4v3(co_test, matrix_final, co); float rad_scale[3]; - mul_v3_v3fl(rad_scale, rad, ED_view3d_pixel_size(rv3d, co_test) * scale); + mul_v3_v3fl(rad_scale, rad, ED_view3d_pixel_size(rv3d, co_test) * handle_scale); imm_draw_point_aspect_3d(pos, co, rad_scale, solid); } } @@ -381,7 +381,8 @@ static void gizmo_cage3d_draw_intern( } if (show) { - cage3d_draw_box_interaction(rv3d, matrix_final, gz->color, gz->highlight_part, size_real, margin); + cage3d_draw_box_interaction( + rv3d, matrix_final, gz->color, gz->highlight_part, size_real, margin); } } else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) { @@ -395,10 +396,10 @@ static void gizmo_cage3d_draw_intern( cage3d_draw_circle_wire( size_real, margin, color, transform_flag, draw_options, gz->line_width); - /* corner gizmos */ + /* Corner gizmos (draw the outer & inner so there is a visible outline). */ GPU_polygon_smooth(true); - cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, black, true, 60); - cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, color, true, 40); + cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, black, true, 1.0f); + cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, color, true, 1.0f / 1.5f); GPU_polygon_smooth(false); GPU_blend(GPU_BLEND_NONE); diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index bff7310e9f7..93d17598181 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -86,9 +86,5 @@ if(WITH_POTRACE) add_definitions(-DWITH_POTRACE) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_gpencil "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index e75e9314659..042fe5d3806 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2008/2018, Blender Foundation + * The Original Code is Copyright (C) 2008-2018, Blender Foundation * This is a new part of Blender */ diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index bf414851aed..8e7a0083ded 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2008, Blender Foundation * This is a new part of Blender - * Operator for converting Grease Pencil data to geometry */ /** \file * \ingroup edgpencil + * Operator for converting Grease Pencil data to geometry. */ #include <math.h> diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index afb786da8c6..dda36cf78d9 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2008, Blender Foundation * This is a new part of Blender - * Operators for editing Grease Pencil strokes */ /** \file * \ingroup edgpencil + * Operators for editing Grease Pencil strokes. */ #include <math.h> @@ -4635,7 +4635,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) } } - /* Separate the entrie stroke. */ + /* Separate the entire stroke. */ if (all_points_selected) { /* deselect old stroke */ gps->flag &= ~GP_STROKE_SELECT; diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c index 2d7497357f2..5002623fbb1 100644 --- a/source/blender/editors/gpencil/gpencil_edit_curve.c +++ b/source/blender/editors/gpencil/gpencil_edit_curve.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2008, Blender Foundation * This is a new part of Blender - * Operators for editing Grease Pencil strokes */ /** \file * \ingroup edgpencil + * Operators for editing Grease Pencil strokes. */ #include <math.h> diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 2023ae5fe27..2d88461fb15 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2016, Blender Foundation * This is a new part of Blender - * Operators for interpolating new Grease Pencil frames from existing strokes */ /** \file * \ingroup edgpencil + * Operators for interpolating new Grease Pencil frames from existing strokes. */ #include <math.h> diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 925c2e1cd7f..884167d7496 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2019, Blender Foundation. * This is a new part of Blender - * Operators for merge Grease Pencil strokes */ /** \file * \ingroup edgpencil + * Operators for merge Grease Pencil strokes. */ #include <stdio.h> diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c index efe29e852f2..adf76e79c2a 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.c +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2008, Blender Foundation * This is a new part of Blender - * Operator for converting Grease Pencil data to geometry */ /** \file * \ingroup edgpencil + * Operator for converting Grease Pencil data to geometry. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index 45842c28dff..d9706c281ca 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2018, Blender Foundation, * This is a new part of Blender - * Use deprecated data to convert old 2.7x files */ /** \file * \ingroup edgpencil + * Use deprecated data to convert old 2.7x files. */ /* Allow using deprecated functionality. */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 79dda480a0a..082deab823b 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -56,6 +56,7 @@ #include "BKE_gpencil.h" #include "BKE_gpencil_curve.h" #include "BKE_gpencil_geom.h" +#include "BKE_gpencil_update_cache.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -1341,6 +1342,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) } gpencil_update_cache(p->gpd); + BKE_gpencil_tag_full_update(p->gpd, gpl, p->gpf, NULL); } /* --- 'Eraser' for 'Paint' Tool ------ */ @@ -2108,6 +2110,9 @@ static void gpencil_session_cleanup(tGPsdata *p) gpd->runtime.sbuffer_used = 0; gpd->runtime.sbuffer_size = 0; gpd->runtime.sbuffer_sflag = 0; + /* This update is required for update-on-write because the sbuffer data is not longer overwritten + * by a copy-on-write. */ + ED_gpencil_sbuffer_update_eval(gpd, p->ob_eval); p->inittime = 0.0; } @@ -2136,6 +2141,7 @@ static void gpencil_paint_initstroke(tGPsdata *p, p->gpl = BKE_gpencil_layer_active_get(p->gpd); if (p->gpl == NULL) { p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true, false); + BKE_gpencil_tag_full_update(p->gpd, NULL, NULL, NULL); changed = true; if (p->custom_color[3]) { copy_v3_v3(p->gpl->color, p->custom_color); @@ -2218,10 +2224,15 @@ static void gpencil_paint_initstroke(tGPsdata *p, } bool need_tag = p->gpl->actframe == NULL; + bGPDframe *actframe = p->gpl->actframe; + p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode); /* Only if there wasn't an active frame, need update. */ if (need_tag) { - DEG_id_tag_update(&p->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + DEG_id_tag_update(&p->gpd->id, ID_RECALC_GEOMETRY); + } + if (actframe != p->gpl->actframe) { + BKE_gpencil_tag_full_update(p->gpd, p->gpl, NULL, NULL); } if (p->gpf == NULL) { diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 2715491414a..fa31dfffbc1 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2017, Blender Foundation * This is a new part of Blender - * Operators for creating new Grease Pencil primitives (boxes, circles, ...) */ /** \file * \ingroup edgpencil + * Operators for creating new Grease Pencil primitives (boxes, circles, ...). */ #include <math.h> diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 50c7202599a..66b7f260f28 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2015, Blender Foundation * This is a new part of Blender - * Brush based operators for editing Grease Pencil strokes */ /** \file * \ingroup edgpencil + * Brush based operators for editing Grease Pencil strokes. */ #include <math.h> @@ -56,6 +56,7 @@ #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_update_cache.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_object_deform.h" @@ -297,6 +298,8 @@ static void gpencil_update_geometry(bGPdata *gpd) return; } + bool changed = false; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if ((gpl->actframe != gpf) && ((gpf->flag & GP_FRAME_SELECT) == 0)) { @@ -306,13 +309,17 @@ static void gpencil_update_geometry(bGPdata *gpd) LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->flag & GP_STROKE_TAG) { BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_tag_full_update(gpd, gpl, gpf, gps); gps->flag &= ~GP_STROKE_TAG; + changed = true; } } } } - DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + if (changed) { + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } } /* ************************************************ */ @@ -1351,8 +1358,9 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso */ if (IS_AUTOKEY_ON(scene) && (gpf->framenum != cfra)) { BKE_gpencil_frame_addcopy(gpl, cfra); + BKE_gpencil_tag_full_update(gpd, gpl, NULL, NULL); /* Need tag to recalculate evaluated data to avoid crashes. */ - DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } } @@ -1696,6 +1704,9 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C, /* Delay a full recalculation for other frames. */ gpencil_recalc_geometry_tag(gps_active); } + bGPDlayer *gpl_active = (gpl->runtime.gpl_orig) ? gpl->runtime.gpl_orig : gpl; + bGPDframe *gpf_active = (gpf->runtime.gpf_orig) ? gpf->runtime.gpf_orig : gpf; + BKE_gpencil_tag_full_update(gpd, gpl_active, gpf_active, gps_active); } } diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 891bd3ca5ec..d9f4cc87afc 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2015, Blender Foundation * This is a new part of Blender - * Brush based operators for editing Grease Pencil strokes */ /** \file * \ingroup edgpencil + * Brush based operators for editing Grease Pencil strokes. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index 05304f9914f..2c16894354e 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2015, Blender Foundation * This is a new part of Blender - * Brush based operators for editing Grease Pencil strokes */ /** \file * \ingroup edgpencil + * Brush based operators for editing Grease Pencil strokes. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index 15f99d83f6d..fe4ab648581 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2015, Blender Foundation * This is a new part of Blender - * Brush based operators for editing Grease Pencil strokes */ /** \file * \ingroup edgpencil + * Brush based operators for editing Grease Pencil strokes. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 3294316f880..04a892ab411 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -378,7 +378,7 @@ typedef enum eAnimFilter_Flags { #define FILTER_MESH_OBJD(me) (CHECK_TYPE_INLINE(me, Mesh *), ((me->flag & ME_DS_EXPAND))) #define FILTER_LATTICE_OBJD(lt) (CHECK_TYPE_INLINE(lt, Lattice *), ((lt->flag & LT_DS_EXPAND))) #define FILTER_SPK_OBJD(spk) (CHECK_TYPE_INLINE(spk, Speaker *), ((spk->flag & SPK_DS_EXPAND))) -#define FILTER_HAIR_OBJD(ha) (CHECK_TYPE_INLINE(ha, Hair *), ((ha->flag & HA_DS_EXPAND))) +#define FILTER_CURVES_OBJD(ha) (CHECK_TYPE_INLINE(ha, Curves *), ((ha->flag & HA_DS_EXPAND))) #define FILTER_POINTS_OBJD(pt) (CHECK_TYPE_INLINE(pt, PointCloud *), ((pt->flag & PT_DS_EXPAND))) #define FILTER_VOLUME_OBJD(vo) (CHECK_TYPE_INLINE(vo, Volume *), ((vo->flag & VO_DS_EXPAND))) #define FILTER_SIMULATION_OBJD(sim) \ diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 11b7c85ec58..0521b39ca1a 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -35,6 +35,7 @@ struct Base; struct Bone; struct Depsgraph; struct EditBone; +struct GPUSelectResult; struct ListBase; struct Main; struct Mesh; @@ -157,22 +158,22 @@ int ED_armature_join_objects_exec(struct bContext *C, struct wmOperator *op); struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases, uint bases_len, - int hit, + unsigned int select_id, struct EditBone **r_ebone); struct Object *ED_armature_object_and_ebone_from_select_buffer(struct Object **objects, uint objects_len, - int hit, + unsigned int select_id, struct EditBone **r_ebone); struct Base *ED_armature_base_and_pchan_from_select_buffer(struct Base **bases, uint bases_len, - int hit, + unsigned int select_id, struct bPoseChannel **r_pchan); /** * For callers that don't need the pose channel. */ struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases, uint bases_len, - int hit, + unsigned int select_id, struct Bone **r_bone); bool ED_armature_edit_deselect_all(struct Object *obedit); bool ED_armature_edit_deselect_all_visible(struct Object *obedit); @@ -334,7 +335,7 @@ void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer, bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer, struct View3D *v3d, struct Base *base, - const unsigned int *buffer, + const struct GPUSelectResult *buffer, short hits, bool extend, bool deselect, diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 8d89555c732..22a6bdb27ba 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -14,7 +14,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2008, Blender Foundation - * This is a new part of Blender (with some old code) */ /** \file diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 181b6848ac7..08f4648d02b 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -57,7 +57,7 @@ typedef enum { #define NODE_EDGE_PAN_DELAY 0.5f #define NODE_EDGE_PAN_ZOOM_INFLUENCE 0.5f -/* space_node.c */ +/* space_node.cc */ void ED_node_cursor_location_get(const struct SpaceNode *snode, float value[2]); void ED_node_cursor_location_set(struct SpaceNode *snode, const float value[2]); @@ -76,7 +76,7 @@ struct bNodeTree *ED_node_tree_get(struct SpaceNode *snode, int level); void ED_node_set_active_viewer_key(struct SpaceNode *snode); -/* drawnode.c */ +/* drawnode.cc */ void ED_node_init_butfuncs(void); void ED_init_custom_node_type(struct bNodeType *ntype); @@ -103,7 +103,7 @@ void ED_node_tag_update_id(struct ID *id); float ED_node_grid_size(void); -/* node_relationships.c */ +/* node_relationships.cc */ /** * Test == 0, clear all intersect flags. @@ -114,7 +114,7 @@ void ED_node_link_intersect_test(struct ScrArea *area, int test); */ void ED_node_link_insert(struct Main *bmain, struct ScrArea *area); -/* node_edit.c */ +/* node_edit.cc */ void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo); bool ED_node_is_compositor(struct SpaceNode *snode); @@ -175,11 +175,12 @@ void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner); -/* node_ops.c */ +/* node_ops.cc */ void ED_operatormacros_node(void); -/* node_view.c */ +/* node_view.cc */ + /** * Returns mouse position in image space. */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 0398c209c68..3bbffc3b7c9 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -41,6 +41,7 @@ struct Camera; struct CustomData_MeshMasks; struct Depsgraph; struct EditBone; +struct GPUSelectResult; struct ID; struct MVert; struct Main; @@ -871,9 +872,14 @@ bool ED_view3d_autodist_simple(struct ARegion *region, bool ED_view3d_depth_read_cached_seg( const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth); -/* select */ +/** + * The default value for the maximum number of elements that can be selected at once + * using view-port selection. + * + * \note in many cases this defines the size of fixed-size stack buffers, + * so take care increasing this value. + */ #define MAXPICKELEMS 2500 -#define MAXPICKBUF (4 * MAXPICKELEMS) typedef enum { /* all elements in the region, ignore depth */ @@ -912,21 +918,21 @@ void view3d_opengl_select_cache_end(void); * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection. */ int view3d_opengl_select_ex(struct ViewContext *vc, - unsigned int *buffer, - unsigned int bufsize, + struct GPUSelectResult *buffer, + unsigned int buffer_len, const struct rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter, bool do_material_slot_selection); int view3d_opengl_select(struct ViewContext *vc, - unsigned int *buffer, - unsigned int bufsize, + struct GPUSelectResult *buffer, + unsigned int buffer_len, const struct rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter); int view3d_opengl_select_with_id_filter(struct ViewContext *vc, - unsigned int *buffer, - unsigned int bufsize, + struct GPUSelectResult *buffer, + unsigned int buffer_len, const struct rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter, diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 4cf606bf98d..05353de2f92 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -752,9 +752,9 @@ DEF_ICON_BLANK(257) DEF_ICON_BLANK(257b) /* ADDITIONAL OBJECT TYPES */ -DEF_ICON_OBJECT(OUTLINER_OB_HAIR) -DEF_ICON_OBJECT_DATA(OUTLINER_DATA_HAIR) -DEF_ICON_OBJECT_DATA(HAIR_DATA) +DEF_ICON_OBJECT(OUTLINER_OB_CURVES) +DEF_ICON_OBJECT_DATA(OUTLINER_DATA_CURVES) +DEF_ICON_OBJECT_DATA(CURVES_DATA) DEF_ICON_OBJECT(OUTLINER_OB_POINTCLOUD) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_POINTCLOUD) DEF_ICON_OBJECT_DATA(POINTCLOUD_DATA) @@ -840,7 +840,7 @@ DEF_ICON(MATPLANE) DEF_ICON(MATSPHERE) DEF_ICON(MATCUBE) DEF_ICON(MONKEY) -DEF_ICON(HAIR) +DEF_ICON(CURVES) DEF_ICON(ALIASED) DEF_ICON(ANTIALIASED) DEF_ICON(MAT_SPHERE_SKY) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 3796fa51499..ae4c2ff16fd 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1370,6 +1370,8 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, /* for passing inputs to ButO buttons */ struct PointerRNA *UI_but_operator_ptr_get(uiBut *but); +struct bContextStore *UI_but_context_get(const uiBut *but); + void UI_but_unit_type_set(uiBut *but, int unit_type); int UI_but_unit_type_get(const uiBut *but); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index a3f39e1286e..0a28b1cafe1 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -15,12 +15,12 @@ * * The Original Code is Copyright (C) 2008 Blender Foundation. * All rights reserved. - * Generic 2d view with should allow drawing grids, - * panning, zooming, scrolling, .. */ /** \file * \ingroup editorui + * Generic 2D view with should allow drawing grids, + * panning, zooming, scrolling, .. etc. */ #pragma once diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 636281ba373..2292bf759b7 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -5928,6 +5928,11 @@ PointerRNA *UI_but_operator_ptr_get(uiBut *but) return but->opptr; } +bContextStore *UI_but_context_get(const uiBut *but) +{ + return but->context; +} + void UI_but_unit_type_set(uiBut *but, const int unit_type) { but->unit_type = (uchar)(RNA_SUBTYPE_UNIT_VALUE(unit_type)); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index fd03cc5e12c..6fa94730365 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -25,6 +25,7 @@ #include "DNA_space_types.h" #include "BLI_math_color.h" +#include "BLI_math_vector.h" #include "BKE_context.h" #include "BKE_screen.h" @@ -107,7 +108,7 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf) /** \name Generic Shared Functions * \{ */ -static void eyedropper_draw_cursor_text_ex(const int x, const int y, const char *name) +static void eyedropper_draw_cursor_text_ex(const int xy[2], const char *name) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; @@ -119,7 +120,7 @@ static void eyedropper_draw_cursor_text_ex(const int x, const int y, const char rgba_uchar_to_float(col_fg, wcol->text); rgba_uchar_to_float(col_bg, wcol->inner); - UI_fontstyle_draw_simple_backdrop(fstyle, x, y + U.widget_unit, name, col_fg, col_bg); + UI_fontstyle_draw_simple_backdrop(fstyle, xy[0], xy[1] + U.widget_unit, name, col_fg, col_bg); } void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name) @@ -128,19 +129,16 @@ void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const cha return; } - const int x = window->eventstate->xy[0]; - const int y = window->eventstate->xy[1]; - - eyedropper_draw_cursor_text_ex(x, y, name); + eyedropper_draw_cursor_text_ex(window->eventstate->xy, name); } -void eyedropper_draw_cursor_text_region(const int x, const int y, const char *name) +void eyedropper_draw_cursor_text_region(const int xy[2], const char *name) { if (name[0] == '\0') { return; } - eyedropper_draw_cursor_text_ex(x, y, name); + eyedropper_draw_cursor_text_ex(xy, name); } uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event) @@ -173,8 +171,7 @@ void datadropper_win_area_find( } } else if (mval != r_mval) { - r_mval[0] = mval[0]; - r_mval[1] = mval[1]; + copy_v2_v2_int(r_mval, mval); } } diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 05840175fab..b5eed2534a3 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -254,8 +254,10 @@ static bool eyedropper_cryptomatte_sample_image_fl(const bNode *node, return success; } -static bool eyedropper_cryptomatte_sample_fl( - bContext *C, Eyedropper *eye, int mx, int my, float r_col[3]) +static bool eyedropper_cryptomatte_sample_fl(bContext *C, + Eyedropper *eye, + const int m_xy[2], + float r_col[3]) { bNode *node = eye->crypto_node; NodeCryptomatte *crypto = node ? ((NodeCryptomatte *)node->storage) : NULL; @@ -265,17 +267,17 @@ static bool eyedropper_cryptomatte_sample_fl( } bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my}); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, m_xy); if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) { return false; } - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, m_xy); if (!region) { return false; } - int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; + int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin}; float fpos[2] = {-1.0f, -1.0}; switch (area->spacetype) { case SPACE_IMAGE: { @@ -324,7 +326,7 @@ static bool eyedropper_cryptomatte_sample_fl( return false; } -void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) +void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]) { /* we could use some clever */ Main *bmain = CTX_data_main(C); @@ -332,10 +334,10 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) const char *display_device = CTX_data_scene(C)->display_settings.display_device; struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); + int mval[2]; wmWindow *win; ScrArea *area; - int mval[2] = {mx, my}; - datadropper_win_area_find(C, mval, mval, &win, &area); + datadropper_win_area_find(C, m_xy, mval, &win, &area); if (area) { if (area->spacetype == SPACE_IMAGE) { @@ -406,17 +408,17 @@ static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3 RNA_property_update(C, &eye->ptr, eye->prop); } -static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) +static void eyedropper_color_sample(bContext *C, Eyedropper *eye, const int m_xy[2]) { /* Accumulate color. */ float col[3]; if (eye->crypto_node) { - if (!eyedropper_cryptomatte_sample_fl(C, eye, mx, my, col)) { + if (!eyedropper_cryptomatte_sample_fl(C, eye, m_xy, col)) { return; } } else { - eyedropper_color_sample_fl(C, mx, my, col); + eyedropper_color_sample_fl(C, m_xy, col); } if (!eye->crypto_node) { @@ -439,13 +441,13 @@ static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my eyedropper_color_set(C, eye, accum_col); } -static void eyedropper_color_sample_text_update(bContext *C, Eyedropper *eye, int mx, int my) +static void eyedropper_color_sample_text_update(bContext *C, Eyedropper *eye, const int m_xy[2]) { float col[3]; eye->sample_text[0] = '\0'; if (eye->cryptomatte_session) { - if (eyedropper_cryptomatte_sample_fl(C, eye, mx, my, col)) { + if (eyedropper_cryptomatte_sample_fl(C, eye, m_xy, col)) { BKE_cryptomatte_find_name( eye->cryptomatte_session, col[0], eye->sample_text, sizeof(eye->sample_text)); eye->sample_text[sizeof(eye->sample_text) - 1] = '\0'; @@ -476,7 +478,7 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) case EYE_MODAL_SAMPLE_CONFIRM: { const bool is_undo = eye->is_undo; if (eye->accum_tot == 0) { - eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]); + eyedropper_color_sample(C, eye, event->xy); } eyedropper_exit(C, op); /* Could support finished & undo-skip. */ @@ -485,23 +487,23 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) case EYE_MODAL_SAMPLE_BEGIN: /* enable accum and make first sample */ eye->accum_start = true; - eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]); + eyedropper_color_sample(C, eye, event->xy); break; case EYE_MODAL_SAMPLE_RESET: eye->accum_tot = 0; zero_v3(eye->accum_col); - eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]); + eyedropper_color_sample(C, eye, event->xy); break; } } else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { if (eye->accum_start) { /* button is pressed so keep sampling */ - eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]); + eyedropper_color_sample(C, eye, event->xy); } if (eye->draw_handle_sample_text) { - eyedropper_color_sample_text_update(C, eye, event->xy[0], event->xy[1]); + eyedropper_color_sample_text_update(C, eye, event->xy); ED_region_tag_redraw(CTX_wm_region(C)); } } diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c index 22320282766..05ed4ecf601 100644 --- a/source/blender/editors/interface/interface_eyedropper_colorband.c +++ b/source/blender/editors/interface/interface_eyedropper_colorband.c @@ -58,7 +58,7 @@ typedef struct Colorband_RNAUpdateCb { } Colorband_RNAUpdateCb; typedef struct EyedropperColorband { - int last_x, last_y; + int event_xy_last[2]; /* Alpha is currently fixed at 1.0, may support in future. */ float (*color_buffer)[4]; int color_buffer_alloc; @@ -142,13 +142,12 @@ static bool eyedropper_colorband_init(bContext *C, wmOperator *op) static void eyedropper_colorband_sample_point(bContext *C, EyedropperColorband *eye, - int mx, - int my) + const int m_xy[2]) { - if (eye->last_x != mx || eye->last_y != my) { + if (eye->event_xy_last[0] != m_xy[0] || eye->event_xy_last[1] != m_xy[1]) { float col[4]; col[3] = 1.0f; /* TODO: sample alpha */ - eyedropper_color_sample_fl(C, mx, my, col); + eyedropper_color_sample_fl(C, m_xy, col); if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) { eye->color_buffer_alloc *= 2; eye->color_buffer = MEM_reallocN(eye->color_buffer, @@ -156,8 +155,7 @@ static void eyedropper_colorband_sample_point(bContext *C, } copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col); eye->color_buffer_len += 1; - eye->last_x = mx; - eye->last_y = my; + copy_v2_v2_int(eye->event_xy_last, m_xy); eye->is_set = true; } } @@ -167,21 +165,20 @@ static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata) struct EyedropperColorband_Context *data = userdata; bContext *C = data->context; EyedropperColorband *eye = data->eye; - eyedropper_colorband_sample_point(C, eye, mx, my); + const int cursor[2] = {mx, my}; + eyedropper_colorband_sample_point(C, eye, cursor); return true; } static void eyedropper_colorband_sample_segment(bContext *C, EyedropperColorband *eye, - int mx, - int my) + const int m_xy[2]) { /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i * to interpolate between the reported coordinates */ struct EyedropperColorband_Context userdata = {C, eye}; - const int p1[2] = {eye->last_x, eye->last_y}; - const int p2[2] = {mx, my}; - BLI_bitmap_draw_2d_line_v2v2i(p1, p2, eyedropper_colorband_sample_callback, &userdata); + BLI_bitmap_draw_2d_line_v2v2i( + eye->event_xy_last, m_xy, eyedropper_colorband_sample_callback, &userdata); } static void eyedropper_colorband_exit(bContext *C, wmOperator *op) @@ -233,7 +230,7 @@ static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED; case EYE_MODAL_SAMPLE_CONFIRM: { const bool is_undo = eye->is_undo; - eyedropper_colorband_sample_segment(C, eye, event->xy[0], event->xy[1]); + eyedropper_colorband_sample_segment(C, eye, event->xy); eyedropper_colorband_apply(C, op); eyedropper_colorband_exit(C, op); /* Could support finished & undo-skip. */ @@ -242,10 +239,9 @@ static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent case EYE_MODAL_SAMPLE_BEGIN: /* enable accum and make first sample */ eye->sample_start = true; - eyedropper_colorband_sample_point(C, eye, event->xy[0], event->xy[1]); + eyedropper_colorband_sample_point(C, eye, event->xy); eyedropper_colorband_apply(C, op); - eye->last_x = event->xy[0]; - eye->last_y = event->xy[1]; + copy_v2_v2_int(eye->event_xy_last, event->xy); break; case EYE_MODAL_SAMPLE_RESET: break; @@ -253,7 +249,7 @@ static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent } else if (event->type == MOUSEMOVE) { if (eye->sample_start) { - eyedropper_colorband_sample_segment(C, eye, event->xy[0], event->xy[1]); + eyedropper_colorband_sample_segment(C, eye, event->xy); eyedropper_colorband_apply(C, op); } } @@ -280,7 +276,7 @@ static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const w } break; case EYE_MODAL_POINT_SAMPLE: - eyedropper_colorband_sample_point(C, eye, event->xy[0], event->xy[1]); + eyedropper_colorband_sample_point(C, eye, event->xy); eyedropper_colorband_apply(C, op); if (eye->color_buffer_len == MAXCOLORBAND) { eyedropper_colorband_exit(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index cf53ef0ec75..812011101e8 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -32,6 +32,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "BLI_math_vector.h" #include "BLI_string.h" #include "BLT_translation.h" @@ -80,7 +81,7 @@ static void datadropper_draw_cb(const struct bContext *UNUSED(C), void *arg) { DataDropper *ddr = arg; - eyedropper_draw_cursor_text_region(UNPACK2(ddr->name_pos), ddr->name); + eyedropper_draw_cursor_text_region(ddr->name_pos, ddr->name); } static int datadropper_init(bContext *C, wmOperator *op) @@ -152,7 +153,7 @@ static void datadropper_exit(bContext *C, wmOperator *op) * \brief get the ID from the 3D view or outliner. */ static void datadropper_id_sample_pt( - bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, int mx, int my, ID **r_id) + bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, const int m_xy[2], ID **r_id) { wmWindow *win_prev = CTX_wm_window(C); ScrArea *area_prev = CTX_wm_area(C); @@ -162,9 +163,9 @@ static void datadropper_id_sample_pt( if (area) { if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, m_xy); if (region) { - const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; + const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin}; Base *base; CTX_wm_window_set(C, win); @@ -205,8 +206,7 @@ static void datadropper_id_sample_pt( *r_id = id; } - ddr->name_pos[0] = mval[0]; - ddr->name_pos[1] = mval[1]; + copy_v2_v2_int(ddr->name_pos, mval); } } } @@ -234,17 +234,16 @@ static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) } /* single point sample & set */ -static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my) +static bool datadropper_id_sample(bContext *C, DataDropper *ddr, const int m_xy[2]) { ID *id = NULL; + int mval[2]; wmWindow *win; ScrArea *area; + datadropper_win_area_find(C, m_xy, mval, &win, &area); - int mval[] = {mx, my}; - datadropper_win_area_find(C, mval, mval, &win, &area); - - datadropper_id_sample_pt(C, win, area, ddr, mval[0], mval[1], &id); + datadropper_id_sample_pt(C, win, area, ddr, mval, &id); return datadropper_id_set(C, ddr, id); } @@ -292,7 +291,7 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; case EYE_MODAL_SAMPLE_CONFIRM: { const bool is_undo = ddr->is_undo; - const bool success = datadropper_id_sample(C, ddr, event->xy[0], event->xy[1]); + const bool success = datadropper_id_sample(C, ddr, event->xy); datadropper_exit(C, op); if (success) { /* Could support finished & undo-skip. */ @@ -306,16 +305,15 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event) else if (event->type == MOUSEMOVE) { ID *id = NULL; + int mval[2]; wmWindow *win; ScrArea *area; - - int mval[] = {event->xy[0], event->xy[1]}; - datadropper_win_area_find(C, mval, mval, &win, &area); + datadropper_win_area_find(C, event->xy, mval, &win, &area); /* Set the region for eyedropper cursor text drawing */ datadropper_set_draw_callback_region(area, ddr); - datadropper_id_sample_pt(C, win, area, ddr, mval[0], mval[1], &id); + datadropper_id_sample_pt(C, win, area, ddr, mval, &id); } return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index 8c6b0ac9cfe..b11001c4bf2 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -81,7 +81,7 @@ static void depthdropper_draw_cb(const struct bContext *UNUSED(C), void *arg) { DepthDropper *ddr = arg; - eyedropper_draw_cursor_text_region(UNPACK2(ddr->name_pos), ddr->name); + eyedropper_draw_cursor_text_region(ddr->name_pos, ddr->name); } static int depthdropper_init(bContext *C, wmOperator *op) @@ -152,12 +152,14 @@ static void depthdropper_exit(bContext *C, wmOperator *op) /** * \brief get the ID from the screen. */ -static void depthdropper_depth_sample_pt( - bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth) +static void depthdropper_depth_sample_pt(bContext *C, + DepthDropper *ddr, + const int m_xy[2], + float *r_depth) { /* we could use some clever */ bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my}); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, m_xy); Scene *scene = CTX_data_scene(C); ScrArea *area_prev = CTX_wm_area(C); @@ -167,14 +169,14 @@ static void depthdropper_depth_sample_pt( if (area) { if (area->spacetype == SPACE_VIEW3D) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, m_xy); if (region) { struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); View3D *v3d = area->spacedata.first; RegionView3D *rv3d = region->regiondata; /* weak, we could pass in some reference point */ const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; - const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; + const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin}; copy_v2_v2_int(ddr->name_pos, mval); float co[3]; @@ -234,19 +236,19 @@ static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr) } /* single point sample & set */ -static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my) +static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, const int m_xy[2]) { float depth = -1.0f; if (depth != -1.0f) { - depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + depthdropper_depth_sample_pt(C, ddr, m_xy, &depth); depthdropper_depth_set(C, ddr, depth); } } -static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my) +static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2]) { float depth = -1.0f; - depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + depthdropper_depth_sample_pt(C, ddr, m_xy, &depth); if (depth != -1.0f) { ddr->accum_depth += depth; ddr->accum_tot++; @@ -276,7 +278,7 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) case EYE_MODAL_SAMPLE_CONFIRM: { const bool is_undo = ddr->is_undo; if (ddr->accum_tot == 0) { - depthdropper_depth_sample(C, ddr, event->xy[0], event->xy[1]); + depthdropper_depth_sample(C, ddr, event->xy); } else { depthdropper_depth_set_accum(C, ddr); @@ -288,12 +290,12 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) case EYE_MODAL_SAMPLE_BEGIN: /* enable accum and make first sample */ ddr->accum_start = true; - depthdropper_depth_sample_accum(C, ddr, event->xy[0], event->xy[1]); + depthdropper_depth_sample_accum(C, ddr, event->xy); break; case EYE_MODAL_SAMPLE_RESET: ddr->accum_tot = 0; ddr->accum_depth = 0.0f; - depthdropper_depth_sample_accum(C, ddr, event->xy[0], event->xy[1]); + depthdropper_depth_sample_accum(C, ddr, event->xy); depthdropper_depth_set_accum(C, ddr); break; } @@ -301,7 +303,7 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) else if (event->type == MOUSEMOVE) { if (ddr->accum_start) { /* button is pressed so keep sampling */ - depthdropper_depth_sample_accum(C, ddr, event->xy[0], event->xy[1]); + depthdropper_depth_sample_accum(C, ddr, event->xy); depthdropper_depth_set_accum(C, ddr); } } diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c index d76ff84bcad..c1d49406818 100644 --- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c +++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c @@ -265,9 +265,9 @@ static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, Eyed } /* Sample the color below cursor. */ -static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, int mx, int my) +static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, const int m_xy[2]) { - eyedropper_color_sample_fl(C, mx, my, eye->color); + eyedropper_color_sample_fl(C, m_xy, eye->color); } /* Cancel operator. */ @@ -292,7 +292,7 @@ static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent * return OPERATOR_CANCELLED; } case EYE_MODAL_SAMPLE_CONFIRM: { - eyedropper_gpencil_color_sample(C, eye, event->xy[0], event->xy[1]); + eyedropper_gpencil_color_sample(C, eye, event->xy); /* Create material. */ eyedropper_gpencil_color_set(C, event, eye); @@ -309,7 +309,7 @@ static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent * } case MOUSEMOVE: case INBETWEEN_MOUSEMOVE: { - eyedropper_gpencil_color_sample(C, eye, event->xy[0], event->xy[1]); + eyedropper_gpencil_color_sample(C, eye, event->xy); break; } default: { diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h index ec448ef9b9f..335ee520791 100644 --- a/source/blender/editors/interface/interface_eyedropper_intern.h +++ b/source/blender/editors/interface/interface_eyedropper_intern.h @@ -25,7 +25,7 @@ /* interface_eyedropper.c */ void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name); -void eyedropper_draw_cursor_text_region(int x, int y, const char *name); +void eyedropper_draw_cursor_text_region(const int xy[2], const char *name); /** * Utility to retrieve a button representing a RNA property that is currently under the cursor. * @@ -51,7 +51,7 @@ void datadropper_win_area_find(const struct bContext *C, * * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking. */ -void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]); +void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]); /* Used for most eye-dropper operators. */ enum { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 905fd452b6c..a171160d020 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3957,7 +3957,14 @@ static void ui_do_but_textedit( ui_textedit_delete_selection(but, data); } if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) { - ui_textedit_insert_buf(but, data, ime_data->str_result, ime_data->result_len); + if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) && + strcmp(ime_data->str_result, "\xE3\x80\x82") == 0) { + /* Convert Ideographic Full Stop (U+3002) to decimal point when entering numbers. */ + ui_textedit_insert_ascii(but, data, '.'); + } + else { + ui_textedit_insert_buf(but, data, ime_data->str_result, ime_data->result_len); + } } } else if (event->type == WM_IME_COMPOSITE_END) { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index c0d6b8a1a6c..d7d3288a68d 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -2335,8 +2335,8 @@ int UI_icon_from_idcode(const int idcode) return ICON_TEXT; case ID_VF: return ICON_FONT_DATA; - case ID_HA: - return ICON_HAIR_DATA; + case ID_CV: + return ICON_CURVES_DATA; case ID_PT: return ICON_POINTCLOUD_DATA; case ID_VO: diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 33c6e382f50..260e3dabc25 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -2073,8 +2073,9 @@ static void UI_OT_tree_view_drop(wmOperatorType *ot) /** \name UI Tree-View Item Rename Operator * * General purpose renaming operator for tree-views. Thanks to this, to add a rename button to - * context menus for example, tree-view API users don't have to implement own renaming operators - * with the same logic as they already have for their #ui::AbstractTreeViewItem::rename() override. + * context menus for example, tree-view API users don't have to implement their own renaming + * operators with the same logic as they already have for their #ui::AbstractTreeViewItem::rename() + * override. * * \{ */ diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 44942d508ca..bf3fa6e62d4 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -39,9 +39,8 @@ #include "BKE_global.h" #include "BLF_api.h" -#ifdef WITH_INTERNATIONAL -# include "BLT_translation.h" -#endif + +#include "BLT_translation.h" #include "UI_interface.h" @@ -454,15 +453,6 @@ void uiStyleInit(void) printf("%s: error, no fonts available\n", __func__); } } - else { - /* ? just for speed to initialize? - * Yes, this build the glyph cache and create - * the texture. - */ - BLF_size(font->blf_id, 11.0f * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 12.0f * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 14.0f * U.pixelsize, U.dpi); - } } if (style == NULL) { @@ -486,8 +476,6 @@ void uiStyleInit(void) blf_mono_font = BLF_load_mono_default(unique); } - BLF_size(blf_mono_font, 12.0f * U.pixelsize, 72); - /* Set default flags based on UI preferences (not render fonts) */ { const int flag_disable = (BLF_MONOCHROME | BLF_HINTING_NONE | BLF_HINTING_SLIGHT | @@ -530,8 +518,6 @@ void uiStyleInit(void) const bool unique = true; blf_mono_font_render = BLF_load_mono_default(unique); } - - BLF_size(blf_mono_font_render, 12.0f * U.pixelsize, 72); } void UI_fontstyle_set(const uiFontStyle *fs) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 8330f8c0db7..03d0cba5ec8 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -667,6 +667,13 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) /* Assign new pointer, takes care of updates/notifiers */ RNA_id_pointer_create(override_id, &idptr); + /* Insert into override hierarchy if possible. */ + ID *owner_id = template_ui->ptr.owner_id; + if (owner_id != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) { + override_id->override_library->hierarchy_root = + owner_id->override_library->hierarchy_root; + owner_id->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY; + } } undo_push_label = "Make Library Override"; } @@ -792,8 +799,8 @@ static const char *template_id_browse_tip(const StructRNA *type) return N_("Browse Workspace to be linked"); case ID_LP: return N_("Browse LightProbe to be linked"); - case ID_HA: - return N_("Browse Hair Data to be linked"); + case ID_CV: + return N_("Browse Hair Curves Data to be linked"); case ID_PT: return N_("Browse Point Cloud Data to be linked"); case ID_VO: @@ -874,7 +881,7 @@ static uiBut *template_id_def_new_but(uiBlock *block, BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, BLT_I18NCONTEXT_ID_WORKSPACE, BLT_I18NCONTEXT_ID_LIGHTPROBE, - BLT_I18NCONTEXT_ID_HAIR, + BLT_I18NCONTEXT_ID_CURVES, BLT_I18NCONTEXT_ID_POINTCLOUD, BLT_I18NCONTEXT_ID_VOLUME, BLT_I18NCONTEXT_ID_SIMULATION, ); @@ -2672,18 +2679,6 @@ static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con) { - bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); - short proxy_protected, xco = 0, yco = 0; - // int rb_col; // UNUSED - - /* determine whether constraint is proxy protected or not */ - if (BKE_constraints_proxylocked_owner(ob, pchan)) { - proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0; - } - else { - proxy_protected = 0; - } - /* unless button has own callback, it adds this callback to button */ uiBlock *block = uiLayoutGetBlock(layout); UI_block_func_set(block, constraint_active_func, ob, con); @@ -2708,72 +2703,23 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co uiLayout *row = uiLayoutRow(layout, true); - if (proxy_protected == 0) { - uiItemR(row, &ptr, "name", 0, "", ICON_NONE); - } - else { - uiItemL(row, IFACE_(con->name), ICON_NONE); - } + uiItemR(row, &ptr, "name", 0, "", ICON_NONE); - /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */ - if (proxy_protected) { - UI_block_emboss_set(block, UI_EMBOSS_NONE); + /* Enabled eye icon. */ + uiItemR(row, &ptr, "enabled", 0, "", ICON_NONE); - /* draw a ghost icon (for proxy) and also a lock beside it, - * to show that constraint is "proxy locked" */ - uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_GHOST_ENABLED, - xco + 12.2f * UI_UNIT_X, - yco, - 0.95f * UI_UNIT_X, - 0.95f * UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Proxy Protected")); - uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LOCKED, - xco + 13.1f * UI_UNIT_X, - yco, - 0.95f * UI_UNIT_X, - 0.95f * UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Proxy Protected")); - - UI_block_emboss_set(block, UI_EMBOSS); - } - else { - /* Enabled eye icon. */ - uiItemR(row, &ptr, "enabled", 0, "", ICON_NONE); - - /* Extra operators menu. */ - uiItemMenuF(row, "", ICON_DOWNARROW_HLT, constraint_ops_extra_draw, con); + /* Extra operators menu. */ + uiItemMenuF(row, "", ICON_DOWNARROW_HLT, constraint_ops_extra_draw, con); - /* Close 'button' - emboss calls here disable drawing of 'button' behind X */ - sub = uiLayoutRow(row, false); - uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); - uiLayoutSetOperatorContext(sub, WM_OP_INVOKE_DEFAULT); - uiItemO(sub, "", ICON_X, "CONSTRAINT_OT_delete"); - } + /* Close 'button' - emboss calls here disable drawing of 'button' behind X */ + sub = uiLayoutRow(row, false); + uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); + uiLayoutSetOperatorContext(sub, WM_OP_INVOKE_DEFAULT); + uiItemO(sub, "", ICON_X, "CONSTRAINT_OT_delete"); /* Some extra padding at the end, so the 'x' icon isn't too close to drag button. */ uiItemS(layout); - /* Set but-locks for protected settings (magic numbers are used here!) */ - if (proxy_protected) { - UI_block_lock_set(block, true, TIP_("Cannot edit Proxy-Protected Constraint")); - } - /* clear any locks set up for proxies/lib-linking */ UI_block_lock_clear(block); } diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index cb1c3cedf8e..5db16354124 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -84,10 +84,6 @@ if(WITH_USD) add_definitions(-DWITH_USD) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_PUGIXML) add_definitions(-DWITH_PUGIXML) endif() diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 4ad2e57d266..0fb64c8a46b 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -78,10 +78,6 @@ set(LIB bf_windowmanager ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 7e05209f79e..8383492e459 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -32,6 +32,7 @@ #include "BLI_math.h" #include "BLI_math_bits.h" #include "BLI_rand.h" +#include "BLI_string.h" #include "BLI_utildefines_stack.h" #include "BKE_context.h" @@ -55,6 +56,8 @@ #include "ED_transform.h" #include "ED_view3d.h" +#include "BLT_translation.h" + #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -1389,6 +1392,37 @@ static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *e return edbm_select_mode_exec(C, op); } +static char *edbm_select_mode_get_description(struct bContext *UNUSED(C), + struct wmOperatorType *UNUSED(op), + struct PointerRNA *values) +{ + const int type = RNA_enum_get(values, "type"); + + /* Because the special behavior for shift and ctrl click depend on user input, they may be + * incorrect if the operator is used from a script or from a special button. So only return the + * specialized descriptions if only the "type" is set, which conveys that the operator is meant + * to be used with the logic in the `invoke` method. */ + if (RNA_struct_property_is_set(values, "type") && + !RNA_struct_property_is_set(values, "use_extend") && + !RNA_struct_property_is_set(values, "use_expand") && + !RNA_struct_property_is_set(values, "action")) { + switch (type) { + case SCE_SELECT_VERTEX: + return BLI_strdup(TIP_( + "Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection")); + case SCE_SELECT_EDGE: + return BLI_strdup( + TIP_("Edge select - Shift-Click for multiple modes, " + "Ctrl-Click expands/contracts selection depending on the current mode")); + case SCE_SELECT_FACE: + return BLI_strdup( + TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection")); + } + } + + return NULL; +} + void MESH_OT_select_mode(wmOperatorType *ot) { PropertyRNA *prop; @@ -1409,6 +1443,7 @@ void MESH_OT_select_mode(wmOperatorType *ot) ot->invoke = edbm_select_mode_invoke; ot->exec = edbm_select_mode_exec; ot->poll = ED_operator_editmesh; + ot->get_description = edbm_select_mode_get_description; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 949b12f9a65..5ea3c0d7b32 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -68,6 +68,7 @@ static const EnumPropertyItem prop_similar_types[] = { {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""}, {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""}, {SIMVERT_EDGE, "EDGE", 0, "Amount of Connecting Edges", ""}, + {SIMVERT_CREASE, "VCREASE", 0, "Vertex Crease", ""}, {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""}, {SIMEDGE_DIR, "DIR", 0, "Direction", ""}, @@ -1009,12 +1010,16 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } KDTree_3d *tree_3d = NULL; + KDTree_1d *tree_1d = NULL; GSet *gset = NULL; switch (type) { case SIMVERT_NORMAL: tree_3d = BLI_kdtree_3d_new(tot_verts_selected_all); break; + case SIMVERT_CREASE: + tree_1d = BLI_kdtree_1d_new(tot_verts_selected_all); + break; case SIMVERT_EDGE: case SIMVERT_FACE: gset = BLI_gset_ptr_new("Select similar vertex: edge/face"); @@ -1025,6 +1030,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } int normal_tree_index = 0; + int tree_1d_index = 0; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(ob); @@ -1050,6 +1056,12 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } defbase_selected = BLI_BITMAP_NEW(defbase_len, __func__); } + else if (type == SIMVERT_CREASE) { + if (!CustomData_has_layer(&bm->vdata, CD_CREASE)) { + BLI_kdtree_1d_insert(tree_1d, tree_1d_index++, (float[1]){0.0f}); + continue; + } + } BMVert *vert; /* Mesh vertex. */ BMIter iter; /* Selected verts iterator. */ @@ -1085,6 +1097,11 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } break; } + case SIMVERT_CREASE: { + const float *value = CustomData_bmesh_get(&bm->vdata, vert->head.data, CD_CREASE); + BLI_kdtree_1d_insert(tree_1d, tree_1d_index++, value); + break; + } } } } @@ -1113,6 +1130,10 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } /* Remove duplicated entries. */ + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } if (tree_3d != NULL) { BLI_kdtree_3d_deduplicate(tree_3d); BLI_kdtree_3d_balance(tree_3d); @@ -1124,6 +1145,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(ob); BMesh *bm = em->bm; bool changed = false; + bool has_crease_layer = false; int cd_dvert_offset = -1; BLI_bitmap *defbase_selected = NULL; int defbase_len = 0; @@ -1158,6 +1180,17 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) continue; } } + else if (type == SIMVERT_CREASE) { + has_crease_layer = CustomData_has_layer(&bm->vdata, CD_CREASE); + if (!has_crease_layer) { + /* Proceed only if we have to select all the vertices that have custom data value of 0.0f. + * In this case we will just select all the vertices. + * Otherwise continue the for loop. */ + if (!ED_select_similar_compare_float_tree(tree_1d, 0.0f, thresh, compare)) { + continue; + } + } + } BMVert *vert; /* Mesh vertex. */ BMIter iter; /* Selected verts iterator. */ @@ -1224,6 +1257,17 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } break; } + case SIMVERT_CREASE: { + if (!has_crease_layer) { + select = true; + break; + } + const float *value = CustomData_bmesh_get(&bm->vdata, vert->head.data, CD_CREASE); + if (ED_select_similar_compare_float_tree(tree_1d, *value, thresh, compare)) { + select = true; + } + break; + } } if (select) { @@ -1249,6 +1293,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); + BLI_kdtree_1d_free(tree_1d); BLI_kdtree_3d_free(tree_3d); if (gset != NULL) { BLI_gset_free(gset, NULL); diff --git a/source/blender/editors/metaball/CMakeLists.txt b/source/blender/editors/metaball/CMakeLists.txt index 4e600dc0277..a247920c305 100644 --- a/source/blender/editors/metaball/CMakeLists.txt +++ b/source/blender/editors/metaball/CMakeLists.txt @@ -20,6 +20,7 @@ set(INC ../../blenkernel ../../blenlib ../../depsgraph + ../../gpu ../../makesdna ../../makesrna ../../render diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index bedb9d4f4f4..51cfc920d1d 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -47,6 +47,8 @@ #include "DEG_depsgraph.h" +#include "GPU_select.h" + #include "ED_mball.h" #include "ED_object.h" #include "ED_screen.h" @@ -756,15 +758,19 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese static MetaElem *startelem = NULL; ViewContext vc; int a, hits; - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; rcti rect; ED_view3d_viewcontext_init(C, &vc, depsgraph); BLI_rcti_init_pt_radius(&rect, mval, 12); - hits = view3d_opengl_select( - &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP); + hits = view3d_opengl_select(&vc, + buffer, + ARRAY_SIZE(buffer), + &rect, + VIEW3D_SELECT_PICK_NEAREST, + VIEW3D_SELECT_FILTER_NOP); FOREACH_BASE_IN_EDIT_MODE_BEGIN (vc.view_layer, vc.v3d, base) { ED_view3d_viewcontext_init_object(&vc, base->object); @@ -789,7 +795,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese ml = startelem; while (ml) { for (a = 0; a < hits; a++) { - int hitresult = buffer[(4 * a) + 3]; + const int hitresult = buffer[a].id; if (hitresult == -1) { continue; } diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 040b5cd5066..df76e605ebb 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -85,14 +85,10 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_SIMULATION_DATABLOCK) add_definitions(-DWITH_POINT_CLOUD) - add_definitions(-DWITH_HAIR_NODES) + add_definitions(-DWITH_NEW_CURVES_TYPE) endif() blender_add_lib(bf_editor_object "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 8a493eb0743..d1deb6824ea 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -62,6 +62,7 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_curves.h" #include "BKE_displist.h" #include "BKE_duplilist.h" #include "BKE_effect.h" @@ -69,7 +70,6 @@ #include "BKE_gpencil_curve.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" -#include "BKE_hair.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_layer.h" @@ -1894,18 +1894,18 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Add Hair Operator +/** \name Add Hair Curves Operator * \{ */ -static bool object_hair_add_poll(bContext *C) +static bool object_hair_curves_add_poll(bContext *C) { - if (!U.experimental.use_new_hair_type) { + if (!U.experimental.use_new_curves_type) { return false; } return ED_operator_objectmode(C); } -static int object_hair_add_exec(bContext *C, wmOperator *op) +static int object_hair_curves_add_exec(bContext *C, wmOperator *op) { ushort local_view_bits; float loc[3], rot[3]; @@ -1913,22 +1913,22 @@ static int object_hair_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - Object *object = ED_object_add_type(C, OB_HAIR, NULL, loc, rot, false, local_view_bits); + Object *object = ED_object_add_type(C, OB_CURVES, NULL, loc, rot, false, local_view_bits); object->dtx |= OB_DRAWBOUNDOX; /* TODO: remove once there is actual drawing. */ return OPERATOR_FINISHED; } -void OBJECT_OT_hair_add(wmOperatorType *ot) +void OBJECT_OT_hair_curves_add(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Hair"; - ot->description = "Add a hair object to the scene"; - ot->idname = "OBJECT_OT_hair_add"; + ot->name = "Add Hair Curves"; + ot->description = "Add a hair curves object to the scene"; + ot->idname = "OBJECT_OT_hair_curves_add"; /* api callbacks */ - ot->exec = object_hair_add_exec; - ot->poll = object_hair_add_poll; + ot->exec = object_hair_curves_add_exec; + ot->poll = object_hair_curves_add_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2347,11 +2347,6 @@ static void make_object_duplilist_real(bContext *C, BKE_animdata_free(&ob_dst->id, true); ob_dst->adt = NULL; - /* Proxies are not to be copied. */ - ob_dst->proxy_from = NULL; - ob_dst->proxy_group = NULL; - ob_dst->proxy = NULL; - ob_dst->parent = NULL; BKE_constraints_free(&ob_dst->constraints); ob_dst->runtime.curve_cache = NULL; @@ -2466,13 +2461,6 @@ static void make_object_duplilist_real(bContext *C, } if (base->object->transflag & OB_DUPLICOLLECTION && base->object->instance_collection) { - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->proxy_group == base->object) { - ob->proxy = NULL; - ob->proxy_from = NULL; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - } base->object->instance_collection = NULL; } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 91a512ae8e9..7ef17689912 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1356,15 +1356,6 @@ void ED_object_constraint_update(Main *bmain, Object *ob) static void object_pose_tag_update(Main *bmain, Object *ob) { BKE_pose_tag_recalc(bmain, ob->pose); /* Checks & sort pose channels. */ - if (ob->proxy && ob->adt) { - /* We need to make use of ugly #POSE_ANIMATION_WORKAROUND here too, - * else anim data are not reloaded after calling `BKE_pose_rebuild()`, - * which causes T43872. - * Note that this is a bit wide here, since we cannot be sure whether there are some locked - * proxy bones or not. - * XXX Temp hack until new depsgraph hopefully solves this. */ - DEG_id_tag_update(&ob->id, ID_RECALC_ANIMATION); - } } void ED_object_constraint_dependency_update(Main *bmain, Object *ob) @@ -2453,12 +2444,6 @@ static int constraint_add_exec( if ((ob->type == OB_ARMATURE) && (pchan)) { BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */ - if (BKE_constraints_proxylocked_owner(ob, pchan) && ob->adt) { - /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, - * else anim data are not reloaded after calling `BKE_pose_rebuild()`, which causes T43872. - * XXX Temp hack until new depsgraph hopefully solves this. */ - DEG_id_tag_update(&ob->id, ID_RECALC_ANIMATION); - } DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); } else { diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 595822de1e7..3744cbee3a4 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -43,6 +43,8 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "BLT_translation.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -610,8 +612,8 @@ static char *data_transfer_get_description(bContext *UNUSED(C), const bool reverse_transfer = RNA_boolean_get(ptr, "use_reverse_transfer"); if (reverse_transfer) { - return BLI_strdup( - "Transfer data layer(s) (weights, edge sharp, etc.) from selected meshes to active one"); + return BLI_strdup(TIP_( + "Transfer data layer(s) (weights, edge sharp, etc.) from selected meshes to active one")); } return NULL; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index d517d68f1fc..ddd44fb9ded 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -65,7 +65,6 @@ void OBJECT_OT_track_set(struct wmOperatorType *ot); void OBJECT_OT_track_clear(struct wmOperatorType *ot); void OBJECT_OT_make_local(struct wmOperatorType *ot); void OBJECT_OT_make_override_library(struct wmOperatorType *ot); -void OBJECT_OT_convert_proxy_to_override(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); @@ -130,7 +129,7 @@ void OBJECT_OT_light_add(struct wmOperatorType *ot); void OBJECT_OT_effector_add(struct wmOperatorType *ot); void OBJECT_OT_camera_add(struct wmOperatorType *ot); void OBJECT_OT_speaker_add(struct wmOperatorType *ot); -void OBJECT_OT_hair_add(struct wmOperatorType *ot); +void OBJECT_OT_hair_curves_add(struct wmOperatorType *ot); void OBJECT_OT_pointcloud_add(struct wmOperatorType *ot); /** * Only used as menu. diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 4ac2a9dca62..af428512cfd 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -53,12 +53,12 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_curves.h" #include "BKE_displist.h" #include "BKE_editmesh.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_gpencil_modifier.h" -#include "BKE_hair.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" @@ -84,6 +84,8 @@ #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" +#include "BLT_translation.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -130,8 +132,8 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object * else if (ob->type == OB_GPENCIL) { BKE_gpencil_modifiers_calc(depsgraph, scene_eval, ob_eval); } - else if (ob->type == OB_HAIR) { - BKE_hair_data_update(depsgraph, scene_eval, ob); + else if (ob->type == OB_CURVES) { + BKE_curves_data_update(depsgraph, scene_eval, ob); } else if (ob->type == OB_POINTCLOUD) { BKE_pointcloud_data_update(depsgraph, scene_eval, ob); @@ -1521,7 +1523,7 @@ static char *modifier_apply_as_shapekey_get_description(struct bContext *UNUSED( bool keep = RNA_boolean_get(values, "keep_modifier"); if (keep) { - return BLI_strdup("Apply modifier as a new shapekey and keep it in the stack"); + return BLI_strdup(TIP_("Apply modifier as a new shapekey and keep it in the stack")); } return NULL; diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index b171da42522..a9a429e7e6f 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -75,7 +75,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_track_clear); WM_operatortype_append(OBJECT_OT_make_local); WM_operatortype_append(OBJECT_OT_make_override_library); - WM_operatortype_append(OBJECT_OT_convert_proxy_to_override); WM_operatortype_append(OBJECT_OT_make_single_user); WM_operatortype_append(OBJECT_OT_make_links_scene); WM_operatortype_append(OBJECT_OT_make_links_data); @@ -106,7 +105,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_light_add); WM_operatortype_append(OBJECT_OT_camera_add); WM_operatortype_append(OBJECT_OT_speaker_add); - WM_operatortype_append(OBJECT_OT_hair_add); + WM_operatortype_append(OBJECT_OT_hair_curves_add); WM_operatortype_append(OBJECT_OT_pointcloud_add); WM_operatortype_append(OBJECT_OT_volume_add); WM_operatortype_append(OBJECT_OT_volume_import); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index a6eb35d49b9..8678bf9bd92 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -63,11 +63,11 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_curves.h" #include "BKE_displist.h" #include "BKE_editmesh.h" #include "BKE_fcurve.h" #include "BKE_gpencil.h" -#include "BKE_hair.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lattice.h" @@ -1872,7 +1872,7 @@ static void single_obdata_users( ob->data, BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS)); break; - case OB_HAIR: + case OB_CURVES: ob->data = ID_NEW_SET( ob->data, BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS)); @@ -2334,7 +2334,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op) BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); const bool success = BKE_lib_override_library_create( - bmain, scene, view_layer, id_root, &obact->id, NULL); + bmain, scene, view_layer, NULL, id_root, &obact->id, NULL); /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ @@ -2419,63 +2419,6 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot) ot->prop = prop; } -static bool convert_proxy_to_override_poll(bContext *C) -{ - Object *obact = CTX_data_active_object(C); - - return obact != NULL && obact->proxy != NULL; -} - -static int convert_proxy_to_override_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - Object *ob_proxy = CTX_data_active_object(C); - Object *ob_proxy_group = ob_proxy->proxy_group; - const bool is_override_instancing_object = ob_proxy_group != NULL; - - const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, view_layer, ob_proxy); - - if (!success) { - BKE_reportf( - op->reports, - RPT_ERROR_INVALID_INPUT, - "Could not create a library override from proxy '%s' (might use already local data?)", - ob_proxy->id.name + 2); - return OPERATOR_CANCELLED; - } - - /* Remove the instance empty from this scene, the items now have an overridden collection - * instead. */ - if (is_override_instancing_object) { - ED_object_base_free_and_unlink(bmain, scene, ob_proxy_group); - } - - DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_WINDOW, NULL); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_convert_proxy_to_override(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Convert Proxy to Override"; - ot->description = "Convert a proxy to a local library override"; - ot->idname = "OBJECT_OT_convert_proxy_to_override"; - - /* api callbacks */ - ot->exec = convert_proxy_to_override_exec; - ot->poll = convert_proxy_to_override_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - /** \} */ /* ------------------------------------------------------------------- */ diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3e74aaeeb10..ed0f7b2fad0 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -39,6 +39,7 @@ #include "BLI_alloca.h" #include "BLI_array.h" +#include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -63,6 +64,8 @@ #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" +#include "BLT_translation.h" + #include "DNA_armature_types.h" #include "RNA_access.h" #include "RNA_define.h" @@ -2464,17 +2467,14 @@ void ED_vgroup_mirror(Object *ob, sel = sel_mirr = true; } - /* tag verts we have used */ - for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) { - mv->flag &= ~ME_VERT_TMP_TAG; - } + BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__); for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) { - if ((mv->flag & ME_VERT_TMP_TAG) == 0) { + if (!BLI_BITMAP_TEST(vert_tag, vidx)) { if ((vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology)) != -1) { if (vidx != vidx_mirr) { mv_mirr = &me->mvert[vidx_mirr]; - if ((mv_mirr->flag & ME_VERT_TMP_TAG) == 0) { + if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) { if (use_vert_sel) { sel = mv->flag & SELECT; @@ -2489,8 +2489,8 @@ void ED_vgroup_mirror(Object *ob, totmirr++; } - mv->flag |= ME_VERT_TMP_TAG; - mv_mirr->flag |= ME_VERT_TMP_TAG; + BLI_BITMAP_ENABLE(vert_tag, vidx); + BLI_BITMAP_ENABLE(vert_tag, vidx_mirr); } } } @@ -2499,6 +2499,8 @@ void ED_vgroup_mirror(Object *ob, } } } + + MEM_freeN(vert_tag); } } else if (ob->type == OB_LATTICE) { @@ -3427,16 +3429,16 @@ static char *vertex_group_lock_description(struct bContext *UNUSED(C), switch (action) { case VGROUP_LOCK: - action_str = "Lock"; + action_str = TIP_("Lock"); break; case VGROUP_UNLOCK: - action_str = "Unlock"; + action_str = TIP_("Unlock"); break; case VGROUP_TOGGLE: - action_str = "Toggle locks of"; + action_str = TIP_("Toggle locks of"); break; case VGROUP_INVERT: - action_str = "Invert locks of"; + action_str = TIP_("Invert locks of"); break; default: return NULL; @@ -3444,34 +3446,34 @@ static char *vertex_group_lock_description(struct bContext *UNUSED(C), switch (mask) { case VGROUP_MASK_ALL: - target_str = "all"; + target_str = TIP_("all"); break; case VGROUP_MASK_SELECTED: - target_str = "selected"; + target_str = TIP_("selected"); break; case VGROUP_MASK_UNSELECTED: - target_str = "unselected"; + target_str = TIP_("unselected"); break; case VGROUP_MASK_INVERT_UNSELECTED: switch (action) { case VGROUP_INVERT: - target_str = "selected"; + target_str = TIP_("selected"); break; case VGROUP_LOCK: - target_str = "selected and unlock unselected"; + target_str = TIP_("selected and unlock unselected"); break; case VGROUP_UNLOCK: - target_str = "selected and lock unselected"; + target_str = TIP_("selected and lock unselected"); break; default: - target_str = "all and invert unselected"; + target_str = TIP_("all and invert unselected"); } break; default: return NULL; } - return BLI_sprintfN("%s %s vertex groups of the active object", action_str, target_str); + return BLI_sprintfN(TIP_("%s %s vertex groups of the active object"), action_str, target_str); } void OBJECT_OT_vertex_group_lock(wmOperatorType *ot) diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt index a607663763e..7c32a2dcf1d 100644 --- a/source/blender/editors/physics/CMakeLists.txt +++ b/source/blender/editors/physics/CMakeLists.txt @@ -60,10 +60,6 @@ if(WITH_MOD_FLUID) add_definitions(-DWITH_FLUID) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_BULLET) list(APPEND INC ../../../../intern/rigidbody diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 1f867c6f1f7..934badd3b6f 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -67,8 +67,4 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_render "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/render/render_internal.cc b/source/blender/editors/render/render_internal.cc index 8e9a052381c..d04e45e4ccb 100644 --- a/source/blender/editors/render/render_internal.cc +++ b/source/blender/editors/render/render_internal.cc @@ -90,7 +90,7 @@ struct RenderJob { Scene *scene; ViewLayer *single_layer; Scene *current_scene; - /* TODO(sergey): Should not be needed once engine will have own + /* TODO(sergey): Should not be needed once engine will have its own * depsgraph and copy-on-write will be implemented. */ Depsgraph *depsgraph; @@ -981,7 +981,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->scene = scene; rj->current_scene = rj->scene; rj->single_layer = single_layer; - /* TODO(sergey): Render engine should be using own depsgraph. + /* TODO(sergey): Render engine should be using its own depsgraph. * * NOTE: Currently is only used by ED_update_for_newframe() at the end of the render, so no * need to ensure evaluation here. */ diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc index 8bd0244c899..fb6742c9fd5 100644 --- a/source/blender/editors/render/render_opengl.cc +++ b/source/blender/editors/render/render_opengl.cc @@ -72,8 +72,11 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" + #include "RE_pipeline.h" +#include "BLT_translation.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -632,7 +635,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data) case ID_MC: /* MovieClip */ case ID_MSK: /* Mask */ case ID_LP: /* LightProbe */ - case ID_HA: /* Hair */ + case ID_CV: /* Curves */ case ID_PT: /* PointCloud */ case ID_VO: /* Volume */ case ID_SIM: /* Simulation */ @@ -1326,12 +1329,12 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C), } if (RNA_boolean_get(ptr, "render_keyed_only")) { - return BLI_strdup( + return BLI_strdup(TIP_( "Render the viewport for the animation range of this scene, but only render keyframes of " - "selected objects"); + "selected objects")); } - return BLI_strdup("Render the viewport for the animation range of this scene"); + return BLI_strdup(TIP_("Render the viewport for the animation range of this scene")); } void RENDER_OT_opengl(wmOperatorType *ot) diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index df078bbd890..c1c75e485f7 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -767,7 +767,7 @@ struct ObjectPreviewData { /* The main for the preview, not of the current file. */ Main *pr_main; /* Copy of the object to create the preview for. The copy is for thread safety (and to insert - * it into an own main). */ + * it into its own main). */ Object *object; /* Current frame. */ int cfra; diff --git a/source/blender/editors/scene/CMakeLists.txt b/source/blender/editors/scene/CMakeLists.txt index cd59f06c6e3..ce0c2062766 100644 --- a/source/blender/editors/scene/CMakeLists.txt +++ b/source/blender/editors/scene/CMakeLists.txt @@ -39,8 +39,5 @@ set(LIB bf_blenlib ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() blender_add_lib(bf_editor_scene "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index d194d0cdbb6..7c5ae4dcd5e 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -57,9 +57,5 @@ set(LIB bf_editor_space_sequencer ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_screen "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 152a5c87c78..4af965621e3 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2608,7 +2608,7 @@ typedef struct RegionMoveData { ARegion *region; ScrArea *area; int bigger, smaller, origval; - int origx, origy; + int orig_xy[2]; int maxsize; AZEdge edge; @@ -2716,8 +2716,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event } rmd->area = sad->sa1; rmd->edge = az->edge; - rmd->origx = event->xy[0]; - rmd->origy = event->xy[1]; + copy_v2_v2_int(rmd->orig_xy, event->xy); rmd->maxsize = area_max_regionsize(rmd->area, rmd->region, rmd->edge); /* if not set we do now, otherwise it uses type */ @@ -2804,7 +2803,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event) (BLI_rcti_size_x(&rmd->region->v2d.mask) + 1); const int snap_size_threshold = (U.widget_unit * 2) / aspect; if (ELEM(rmd->edge, AE_LEFT_TO_TOPRIGHT, AE_RIGHT_TO_TOPLEFT)) { - delta = event->xy[0] - rmd->origx; + delta = event->xy[0] - rmd->orig_xy[0]; if (rmd->edge == AE_LEFT_TO_TOPRIGHT) { delta = -delta; } @@ -2837,7 +2836,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event) } } else { - delta = event->xy[1] - rmd->origy; + delta = event->xy[1] - rmd->orig_xy[1]; if (rmd->edge == AE_BOTTOM_TO_TOPLEFT) { delta = -delta; } @@ -2879,7 +2878,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event) } case LEFTMOUSE: if (event->val == KM_RELEASE) { - if (len_manhattan_v2v2_int(event->xy, &rmd->origx) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) { + if (len_manhattan_v2v2_int(event->xy, rmd->orig_xy) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) { if (rmd->region->flag & RGN_FLAG_HIDDEN) { region_scale_toggle_hidden(C, rmd); } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 4bc9f1e2565..2b16b70d1ef 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Making screendumps. */ /** \file * \ingroup edscr + * Making screenshots of the entire window or sub-regions. */ #include <errno.h> diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index b15b6784d34..907080626e0 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -90,9 +90,5 @@ set(LIB bf_blenlib ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_sculpt_paint "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index da627c6b7db..805d2221f6f 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2010 by Nicholas Bishop * All rights reserved. - * Implements the PBVH node hiding operator */ /** \file * \ingroup edsculpt + * Implements the PBVH node hiding operator. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index a912bb5cf3b..d5aa7647603 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -14,8 +14,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index ca012f20f01..4d23119dd5f 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -14,8 +14,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * The Original Code is: some of this file. */ /** \file @@ -1730,17 +1728,12 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps, normalize_v3(no); } else { -#if 1 /* In case the normalizing per pixel isn't optimal, * we could cache or access from evaluated mesh. */ normal_tri_v3(no, ps->mvert_eval[lt_vtri[0]].co, ps->mvert_eval[lt_vtri[1]].co, ps->mvert_eval[lt_vtri[2]].co); -#else - /* Don't use because some modifiers don't have normal data (subsurf for eg). */ - copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, tri_index, CD_NORMAL)); -#endif } if (UNLIKELY(ps->is_flip_object)) { diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index 46c2acf112a..1234a56853c 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -430,7 +430,7 @@ void PAINT_OT_weight_sample_group(wmOperatorType *ot) /* Group to use (dynamic enum). */ prop = RNA_def_enum( - ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Group", "Vertex group to set as active"); + ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "Vertex group to set as active"); RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 07e26a3d931..ea3d694542c 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2006 by Nicholas Bishop * All rights reserved. - * Implements the Sculpt Mode tools */ /** \file * \ingroup edsculpt + * Implements the Sculpt Mode tools. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c index c2acc361a79..0d2c5641183 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2006 by Nicholas Bishop * All rights reserved. - * Implements the Sculpt Mode tools */ /** \file * \ingroup edsculpt + * Implements the Sculpt Mode tools. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 119d246a770..f50775f8a32 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2006 by Nicholas Bishop * All rights reserved. - * Implements the Sculpt Mode tools */ /** \file * \ingroup edsculpt + * Implements the Sculpt Mode tools. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 8819496c168..0b64d1f8a35 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2006 by Nicholas Bishop * All rights reserved. - * Implements the Sculpt Mode tools */ /** \file * \ingroup edsculpt + * Implements the Sculpt Mode tools. */ #include <stddef.h> diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index e5ca5e4defd..35ad582d4ec 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -13,13 +13,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) Blender Foundation, 2002-2009 + * The Original Code is Copyright (C) 2002-2009, Blender Foundation * All rights reserved. - * UV Sculpt tools */ /** \file * \ingroup edsculpt + * UV Sculpt tools. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 184d715a347..ba4ba04d548 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -658,7 +658,7 @@ static char *actkeys_paste_description(bContext *UNUSED(C), { /* Custom description if the 'flipped' option is used. */ if (RNA_boolean_get(ptr, "flipped")) { - return BLI_strdup("Paste keyframes from mirrored bones if they exist"); + return BLI_strdup(TIP_("Paste keyframes from mirrored bones if they exist")); } /* Use the default description in the other cases. */ diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index f8adba30547..b786cada908 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) Blender Foundation, 2008 + * The Original Code is Copyright (C) 2008, Blender Foundation */ /** \file diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index b5f6874fcfc..14cc03e3120 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -40,10 +40,6 @@ set(SRC set(LIB ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) @@ -52,7 +48,7 @@ endif() if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_SIMULATION_DATABLOCK) add_definitions(-DWITH_POINT_CLOUD) - add_definitions(-DWITH_HAIR_NODES) + add_definitions(-DWITH_NEW_CURVES_TYPE) endif() blender_add_lib(bf_editor_space_buttons "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index f5107cb13fd..b83396b10d9 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -273,8 +273,8 @@ static bool buttons_context_path_data(ButsContextPath *path, int type) if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (ELEM(type, -1, OB_GPENCIL))) { return true; } -#ifdef WITH_HAIR_NODES - if (RNA_struct_is_a(ptr->type, &RNA_Hair) && (ELEM(type, -1, OB_HAIR))) { +#ifdef WITH_NEW_CURVES_TYPE + if (RNA_struct_is_a(ptr->type, &RNA_Curves) && (ELEM(type, -1, OB_CURVES))) { return true; } #endif @@ -314,7 +314,7 @@ static bool buttons_context_path_modifier(ButsContextPath *path) OB_SURF, OB_LATTICE, OB_GPENCIL, - OB_HAIR, + OB_CURVES, OB_POINTCLOUD, OB_VOLUME)) { ModifierData *md = BKE_object_active_modifier(ob); @@ -845,8 +845,8 @@ const char *buttons_context_dir[] = { "line_style", "collection", "gpencil", -#ifdef WITH_HAIR_NODES - "hair", +#ifdef WITH_NEW_CURVES_TYPE + "curves", #endif #ifdef WITH_POINT_CLOUD "pointcloud", @@ -941,9 +941,9 @@ int /*eContextResult*/ buttons_context(const bContext *C, set_pointer_type(path, result, &RNA_LightProbe); return CTX_RESULT_OK; } -#ifdef WITH_HAIR_NODES - if (CTX_data_equals(member, "hair")) { - set_pointer_type(path, result, &RNA_Hair); +#ifdef WITH_NEW_CURVES_TYPE + if (CTX_data_equals(member, "curves")) { + set_pointer_type(path, result, &RNA_Curves); return CTX_RESULT_OK; } #endif diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt index db881dafa6b..8f1a2c3c81e 100644 --- a/source/blender/editors/space_clip/CMakeLists.txt +++ b/source/blender/editors/space_clip/CMakeLists.txt @@ -68,11 +68,6 @@ set(LIB ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - - blender_add_lib(bf_editor_space_clip "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # Needed so we can use dna_type_offsets.h for defaults initialization. diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index cbeb2e6f529..1df0c9c4409 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -92,10 +92,6 @@ if(WITH_IMAGE_HDR) add_definitions(-DWITH_HDR) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 2d31e8030a4..6be17bbd355 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -524,7 +524,7 @@ static int compare_apply_inverted(int val, const struct FileSortData *sort_data) * 2) If not possible (file names match) and both represent local IDs, sort by ID-type. * 3) If not possible and only one is a local ID, place files representing local IDs first. * - * TODO (not actually implemented, but should be): + * TODO: (not actually implemented, but should be): * 4) If no file represents a local ID, sort by file path, so that files higher up the file system * hierarchy are placed first. */ @@ -2783,7 +2783,8 @@ int ED_path_extension_type(const char *path) NULL)) { return FILE_TYPE_TEXT; } - if (BLI_path_extension_check_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) { + if (BLI_path_extension_check_n( + path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", ".woff", ".woff2", NULL)) { return FILE_TYPE_FTFONT; } if (BLI_path_extension_check(path, ".btx")) { diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 14f596ae7bf..e95e3bef8a8 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -745,14 +745,17 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) N_("Fonts"), ICON_FILE_FONT, FS_INSERT_LAST); + fsmenu_add_windows_folder(fsmenu, + FS_CATEGORY_SYSTEM_BOOKMARKS, + &FOLDERID_SkyDrive, + N_("OneDrive"), + ICON_URL, + FS_INSERT_LAST); /* These items are just put in path cache for thumbnail views and if bookmarked. */ fsmenu_add_windows_folder( fsmenu, FS_CATEGORY_OTHER, &FOLDERID_UserProfiles, NULL, ICON_COMMUNITY, FS_INSERT_LAST); - - fsmenu_add_windows_folder( - fsmenu, FS_CATEGORY_OTHER, &FOLDERID_SkyDrive, NULL, ICON_URL, FS_INSERT_LAST); } } #elif defined(__APPLE__) @@ -787,7 +790,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) } /* Get mounted volumes better method OSX 10.6 and higher, see: - * https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html + * https://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFURLRef/Reference/reference.html */ /* We get all volumes sorted including network and do not relay diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt index 2a795dd954c..2e6e6971ce9 100644 --- a/source/blender/editors/space_graph/CMakeLists.txt +++ b/source/blender/editors/space_graph/CMakeLists.txt @@ -61,9 +61,5 @@ if(WITH_AUDASPACE) add_definitions(-DWITH_AUDASPACE) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_space_graph "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 9675901ead3..63de7fb570e 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -586,7 +586,7 @@ static char *graphkeys_paste_description(bContext *UNUSED(C), { /* Custom description if the 'flipped' option is used. */ if (RNA_boolean_get(ptr, "flipped")) { - return BLI_strdup("Paste keyframes from mirrored bones if they exist"); + return BLI_strdup(TIP_("Paste keyframes from mirrored bones if they exist")); } /* Use the default description in the other cases. */ diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index 4b8c983a761..cfaea33605a 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -483,7 +483,7 @@ static char *decimate_desc(bContext *UNUSED(C), wmOperatorType *UNUSED(op), Poin if (RNA_enum_get(ptr, "mode") == DECIM_ERROR) { return BLI_strdup( - "Decimate F-Curves by specifying how much it can deviate from the original curve"); + TIP_("Decimate F-Curves by specifying how much they can deviate from the original curve")); } /* Use default description. */ diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index 7a1bab0ef14..25d0e02ecc0 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -53,10 +53,6 @@ set(LIB bf_editor_uvedit ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_OPENIMAGEIO) add_definitions(-DWITH_OPENIMAGEIO) endif() diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index e81f3b6a490..73993606a14 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -1000,7 +1000,7 @@ void ED_image_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref; - /* NOTE this is actually a confusing case, since it expects a valid context, but only in a + /* NOTE: this is actually a confusing case, since it expects a valid context, but only in a * specific case, see `image_undosys_step_encode` code. We cannot specify * `UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE` though, as it can be called with a NULL context by * current code. */ diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index 144b21fb9b8..fb17a6c9709 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -48,9 +48,5 @@ set(SRC set(LIB ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_space_info "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index 005ae0214cd..a1eacc2bc3a 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -219,7 +219,7 @@ static void stats_object(Object *ob, } break; } - case OB_HAIR: + case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: { break; diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt index 9a94d28c604..5326f1cce2b 100644 --- a/source/blender/editors/space_nla/CMakeLists.txt +++ b/source/blender/editors/space_nla/CMakeLists.txt @@ -47,9 +47,5 @@ set(LIB bf_blenlib ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_space_nla "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 1376dade659..28041c0389f 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1397,8 +1397,11 @@ static void nlaedit_split_strip_actclip( nstrip->actstart = splitaframe; } - /* clear the active flag from the copy */ - nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE; + /* Make sure Sync Length is off. With that setting on, entering and exiting tweak mode would + * effectively undo the split, because both the old and the new strip will be at the length of + * the Action again. */ + strip->flag &= ~NLASTRIP_FLAG_SYNC_LENGTH; + nstrip->flag &= ~(NLASTRIP_FLAG_SYNC_LENGTH | NLASTRIP_FLAG_ACTIVE); /* auto-name the new strip */ BKE_nlastrip_validate_name(adt, nstrip); diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 41d6388c947..15e0d04c8fa 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -63,10 +63,6 @@ set(LIB bf_editor_screen ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_COMPOSITOR) add_definitions(-DWITH_COMPOSITOR) endif() diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 2c47883d831..e290316af1f 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -397,7 +397,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, /* Round the socket location to stop it from jiggling. */ nsock->locx = round(loc.x + NODE_WIDTH(node)); - nsock->locy = round(0.5f * (dy + buty)); + nsock->locy = round(dy - NODE_DYS); dy = buty; if (nsock->next) { @@ -527,7 +527,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, nsock->locx = loc.x; /* Round the socket vertical position to stop it from jiggling. */ - nsock->locy = round(0.5f * (dy + buty)); + nsock->locy = round(dy - NODE_DYS); dy = buty - multi_input_socket_offset * 0.5; if (nsock->next) { @@ -626,7 +626,9 @@ static void node_update_hidden(bNode &node, uiBlock &block) static int node_get_colorid(const bNode &node) { - switch (node.typeinfo->nclass) { + const int nclass = (node.typeinfo->ui_class == nullptr) ? node.typeinfo->nclass : + node.typeinfo->ui_class(&node); + switch (nclass) { case NODE_CLASS_INPUT: return TH_NODE_INPUT; case NODE_CLASS_OUTPUT: diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 95f771cc00b..51825f5bd39 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -109,20 +109,30 @@ enum NodeResizeDirection { }; ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT); +/* Nodes draw without dpi - the view zoom is flexible. */ +#define HIDDEN_RAD (0.75f * U.widget_unit) +#define BASIS_RAD (0.2f * U.widget_unit) +#define NODE_DYS (U.widget_unit / 2) +#define NODE_DY U.widget_unit +#define NODE_SOCKDY (0.1f * U.widget_unit) +#define NODE_WIDTH(node) (node.width * UI_DPI_FAC) +#define NODE_HEIGHT(node) (node.height * UI_DPI_FAC) +#define NODE_MARGIN_X (1.2f * U.widget_unit) +#define NODE_SOCKSIZE (0.25f * U.widget_unit) +#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) +#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) +#define NODE_LINK_RESOL 12 + +/* space_node.cc */ + /** * Transform between View2Ds in the tree path. */ float2 space_node_group_offset(const SpaceNode &snode); -float node_socket_calculate_height(const bNodeSocket &socket); -float2 node_link_calculate_multi_input_position(const float2 &socket_position, - int index, - int total_inputs); - rctf node_frame_rect_inside(const bNode &node); int node_get_resize_cursor(NodeResizeDirection directions); -NodeResizeDirection node_get_resize_direction(const bNode *node, int x, int y); /** * Usual convention here would be #node_socket_get_color(), * but that's already used (for setting a color property socket). @@ -132,6 +142,9 @@ void node_socket_color_get(const bContext &C, PointerRNA &node_ptr, const bNodeSocket &sock, float r_color[4]); + +/* node_draw.cc */ + void node_draw_space(const bContext &C, ARegion ®ion); /** @@ -146,9 +159,13 @@ float2 node_to_view(const bNode &node, const float2 &co); void node_to_updated_rect(const bNode &node, rctf &r_rect); float2 node_from_view(const bNode &node, const float2 &co); +/* node_ops.cc */ + void node_operatortypes(); void node_keymap(wmKeyConfig *keyconf); +/* node_select.cc */ + void node_deselect_all(SpaceNode &snode); void node_socket_select(bNode *node, bNodeSocket &sock); void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node); @@ -167,6 +184,8 @@ void NODE_OT_select_grouped(wmOperatorType *ot); void NODE_OT_select_same_type_step(wmOperatorType *ot); void NODE_OT_find_node(wmOperatorType *ot); +/* node_view.cc */ + bool space_node_view_flag( bContext &C, SpaceNode &snode, ARegion ®ion, int node_flag, int smooth_viewtx); @@ -179,6 +198,10 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot); void NODE_OT_backimage_fit(wmOperatorType *ot); void NODE_OT_backimage_sample(wmOperatorType *ot); +/* drawnode.cc */ + +NodeResizeDirection node_get_resize_direction(const bNode *node, int x, int y); + void nodelink_batch_start(SpaceNode &snode); void nodelink_batch_end(SpaceNode &snode); @@ -217,7 +240,7 @@ void draw_nodespace_back_pix(const bContext &C, SpaceNode &snode, bNodeInstanceKey parent_key); -void node_select_all(ListBase *lb, int action); +/* node_add.cc */ /** * XXX Does some additional initialization on top of #nodeAddNode @@ -234,6 +257,8 @@ void NODE_OT_add_file(wmOperatorType *ot); void NODE_OT_add_mask(wmOperatorType *ot); void NODE_OT_new_node_tree(wmOperatorType *ot); +/* node_group.cc */ + const char *node_group_idname(bContext *C); void NODE_OT_group_make(wmOperatorType *ot); void NODE_OT_group_insert(wmOperatorType *ot); @@ -241,6 +266,8 @@ void NODE_OT_group_ungroup(wmOperatorType *ot); void NODE_OT_group_separate(wmOperatorType *ot); void NODE_OT_group_edit(wmOperatorType *ot); +/* node_relationships.cc */ + void sort_multi_input_socket_links(SpaceNode &snode, bNode &node, bNodeLink *drag_link, @@ -261,6 +288,16 @@ void NODE_OT_link_viewer(wmOperatorType *ot); void NODE_OT_insert_offset(wmOperatorType *ot); +/* node_edit.cc */ + +float2 node_link_calculate_multi_input_position(const float2 &socket_position, + int index, + int total_inputs); + +void node_select_all(ListBase *lb, int action); + +float node_socket_calculate_height(const bNodeSocket &socket); + void snode_set_context(const bContext &C); bool composite_node_active(bContext *C); @@ -316,13 +353,17 @@ void NODE_OT_shader_script_update(wmOperatorType *ot); void NODE_OT_viewer_border(wmOperatorType *ot); void NODE_OT_clear_viewer_border(wmOperatorType *ot); +void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot); +void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot); + +/* node_gizmo.cc */ + void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt); void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt); void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt); void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt); -void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot); -void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot); +/* node_geometry_attribute_search.cc */ void node_geometry_add_attribute_search_button(const bContext &C, const bNodeTree &node_tree, @@ -330,22 +371,12 @@ void node_geometry_add_attribute_search_button(const bContext &C, PointerRNA &socket_ptr, uiLayout &layout); -/* Nodes draw without dpi - the view zoom is flexible. */ -#define HIDDEN_RAD (0.75f * U.widget_unit) -#define BASIS_RAD (0.2f * U.widget_unit) -#define NODE_DYS (U.widget_unit / 2) -#define NODE_DY U.widget_unit -#define NODE_SOCKDY (0.1f * U.widget_unit) -#define NODE_WIDTH(node) (node.width * UI_DPI_FAC) -#define NODE_HEIGHT(node) (node.height * UI_DPI_FAC) -#define NODE_MARGIN_X (1.2f * U.widget_unit) -#define NODE_SOCKSIZE (0.25f * U.widget_unit) -#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) -#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) -#define NODE_LINK_RESOL 12 +/* node_context_path.c */ Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); +/* link_drag_search.cc */ + void invoke_node_link_drag_add_menu(bContext &C, bNode &node, bNodeSocket &socket, diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index bc6db978a4f..d97f48bcb68 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -95,9 +95,5 @@ set(LIB bf_editor_undo ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_space_outliner "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index 5fd7559370f..13c273d1ec9 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -2480,9 +2480,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case TSE_POSE_CHANNEL: data.icon = ICON_BONE_DATA; break; - case TSE_PROXY: - data.icon = ICON_GHOST_ENABLED; - break; case TSE_R_LAYER_BASE: data.icon = ICON_RENDERLAYERS; break; @@ -2635,8 +2632,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case OB_LIGHTPROBE: data.icon = ICON_OUTLINER_OB_LIGHTPROBE; break; - case OB_HAIR: - data.icon = ICON_OUTLINER_OB_HAIR; + case OB_CURVES: + data.icon = ICON_OUTLINER_OB_CURVES; break; case OB_POINTCLOUD: data.icon = ICON_OUTLINER_OB_POINTCLOUD; @@ -2749,8 +2746,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case ID_GR: data.icon = ICON_OUTLINER_COLLECTION; break; - case ID_HA: - data.icon = ICON_OUTLINER_DATA_HAIR; + case ID_CV: + data.icon = ICON_OUTLINER_DATA_CURVES; break; case ID_PT: data.icon = ICON_OUTLINER_DATA_POINTCLOUD; diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh index 9db1d73dc76..efbd8a32716 100644 --- a/source/blender/editors/space_outliner/outliner_intern.hh +++ b/source/blender/editors/space_outliner/outliner_intern.hh @@ -57,10 +57,12 @@ class AbstractTreeDisplay; class AbstractTreeElement; } // namespace blender::ed::outliner +namespace outliner = blender::ed::outliner; + struct SpaceOutliner_Runtime { /** Object to create and manage the tree for a specific display type (View Layers, Scenes, * Blender File, etc.). */ - std::unique_ptr<blender::ed::outliner::AbstractTreeDisplay> tree_display; + std::unique_ptr<outliner::AbstractTreeDisplay> tree_display; /** Pointers to tree-store elements, grouped by `(id, type, nr)` * in hash-table for faster searching. */ @@ -93,11 +95,12 @@ typedef struct TreeElement { struct TreeElement *next, *prev, *parent; /** - * Handle to the new C++ object (a derived type of base #AbstractTreeElement) that should replace - * #TreeElement. Step by step, data should be moved to it and operations based on the type should - * become virtual methods of the class hierarchy. + * The new inheritance based representation of the element (a derived type of base + * #AbstractTreeElement) that should eventually replace #TreeElement. Step by step, data should + * be moved to it and operations based on the type should become virtual methods of the class + * hierarchy. */ - std::unique_ptr<blender::ed::outliner::AbstractTreeElement> type; + std::unique_ptr<outliner::AbstractTreeElement> abstract_element; ListBase subtree; int xs, ys; /* Do selection. */ @@ -142,7 +145,7 @@ typedef struct TreeElementIcon { ID_GD, \ ID_LS, \ ID_LP, \ - ID_HA, \ + ID_CV, \ ID_PT, \ ID_VO, \ ID_SIM) || /* Only in 'blendfile' mode ... :/ */ \ @@ -700,7 +703,7 @@ template<typename TreeElementT> TreeElementT *tree_element_cast(const TreeElemen { static_assert(std::is_base_of_v<AbstractTreeElement, TreeElementT>, "Requested tree-element type must be an AbstractTreeElement"); - return dynamic_cast<TreeElementT *>(te->type.get()); + return dynamic_cast<TreeElementT *>(te->abstract_element.get()); } } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc index ebb4e529b04..f256475c0da 100644 --- a/source/blender/editors/space_outliner/outliner_select.cc +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -1198,7 +1198,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE case ID_AR: case ID_GD: case ID_LP: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: context = BCONTEXT_DATA; diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 03fc4c20fe5..337649834a4 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -29,8 +29,8 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" +#include "DNA_curves_types.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" #include "DNA_material_types.h" @@ -164,7 +164,7 @@ static void get_element_operation_type( case ID_CF: case ID_WS: case ID_LP: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: case ID_SIM: @@ -262,10 +262,10 @@ static void unlink_material_fn(bContext *UNUSED(C), totcol = mb->totcol; matar = mb->mat; } - else if (GS(tsep->id->name) == ID_HA) { - Hair *hair = (Hair *)tsep->id; - totcol = hair->totcol; - matar = hair->mat; + else if (GS(tsep->id->name) == ID_CV) { + Curves *curves = (Curves *)tsep->id; + totcol = curves->totcol; + matar = curves->mat; } else if (GS(tsep->id->name) == ID_PT) { PointCloud *pointcloud = (PointCloud *)tsep->id; @@ -764,38 +764,6 @@ static void id_local_fn(bContext *C, } } -static void object_proxy_to_override_convert_fn(bContext *C, - ReportList *reports, - Scene *UNUSED(scene), - TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) -{ - BLI_assert(TSE_IS_REAL_ID(tselem)); - ID *id_proxy = tselem->id; - BLI_assert(GS(id_proxy->name) == ID_OB); - Object *ob_proxy = (Object *)id_proxy; - Scene *scene = CTX_data_scene(C); - - if (ob_proxy->proxy == nullptr) { - return; - } - - if (!BKE_lib_override_library_proxy_convert( - CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy)) { - BKE_reportf( - reports, - RPT_ERROR_INVALID_INPUT, - "Could not create a library override from proxy '%s' (might use already local data?)", - ob_proxy->id.name + 2); - return; - } - - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_WINDOW, nullptr); -} - struct OutlinerLibOverrideData { bool do_hierarchy; /** @@ -874,8 +842,13 @@ static void id_override_library_create_fn(bContext *C, te->store_elem->id->tag |= LIB_TAG_DOIT; } - success = BKE_lib_override_library_create( - bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr); + success = BKE_lib_override_library_create(bmain, + CTX_data_scene(C), + CTX_data_view_layer(C), + nullptr, + id_root, + id_reference, + nullptr); } else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) { success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr; @@ -1532,7 +1505,6 @@ enum { OL_OP_SELECT_HIERARCHY, OL_OP_REMAP, OL_OP_RENAME, - OL_OP_PROXY_TO_OVERRIDE_CONVERT, }; static const EnumPropertyItem prop_object_op_types[] = { @@ -1545,11 +1517,6 @@ static const EnumPropertyItem prop_object_op_types[] = { "Remap Users", "Make all users of selected data-blocks to use instead a new chosen one"}, {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, - {OL_OP_PROXY_TO_OVERRIDE_CONVERT, - "OBJECT_PROXY_TO_OVERRIDE", - 0, - "Convert Proxy to Override", - "Convert a Proxy object to a full library override, including all its dependencies"}, {0, nullptr, 0, nullptr, nullptr}, }; @@ -1614,15 +1581,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn); str = "Rename Object"; } - else if (event == OL_OP_PROXY_TO_OVERRIDE_CONVERT) { - outliner_do_object_operation(C, - op->reports, - scene, - space_outliner, - &space_outliner->tree, - object_proxy_to_override_convert_fn); - str = "Convert Proxy to Override"; - } else { BLI_assert(0); return OPERATOR_CANCELLED; @@ -1794,7 +1752,6 @@ enum eOutlinerIdOpTypes { OUTLINER_IDOP_LOCAL, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, - OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY, @@ -1836,11 +1793,6 @@ static const EnumPropertyItem prop_id_op_types[] = { 0, "Make Library Override Hierarchy", "Make a local override of this linked data-block, and its hierarchy of dependencies"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT, - "OVERRIDE_LIBRARY_PROXY_CONVERT", - 0, - "Convert Proxy to Override", - "Convert a Proxy object to a full library override, including all its dependencies"}, {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, "OVERRIDE_LIBRARY_RESET", 0, @@ -1913,16 +1865,6 @@ static bool outliner_id_operation_item_poll(bContext *C, return true; } return false; - case OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT: { - if (GS(tselem->id->name) == ID_OB) { - Object *ob = (Object *)tselem->id; - - if ((ob != nullptr) && (ob->proxy != nullptr)) { - return true; - } - } - return false; - } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: @@ -2099,16 +2041,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Overridden Data Hierarchy"); break; } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_PROXY_CONVERT: { - outliner_do_object_operation(C, - op->reports, - scene, - space_outliner, - &space_outliner->tree, - object_proxy_to_override_convert_fn); - ED_undo_push(C, "Convert Proxy to Override"); - break; - } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: { OutlinerLibOverrideData override_data{}; outliner_do_libdata_operation(C, diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index eb885eba20d..60f5437ad88 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -32,9 +32,9 @@ #include "DNA_camera_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" +#include "DNA_curves_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_lightprobe_types.h" @@ -217,7 +217,7 @@ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree) if (element->flag & TE_FREE_NAME) { MEM_freeN((void *)element->name); } - element->type = nullptr; + element->abstract_element = nullptr; MEM_delete(element); } @@ -302,10 +302,6 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, /* FIXME: add a special type for this. */ outliner_add_element(space_outliner, &te->subtree, ob->poselib, te, TSE_SOME_ID, 0); - if (ob->proxy && !ID_IS_LINKED(ob)) { - outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0); - } - outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { @@ -777,10 +773,10 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } break; } - case ID_HA: { - Hair *hair = (Hair *)id; - if (outliner_animdata_test(hair->adt)) { - outliner_add_element(space_outliner, &te->subtree, hair, te, TSE_ANIM_DATA, 0); + case ID_CV: { + Curves *curves = (Curves *)id; + if (outliner_animdata_test(curves->adt)) { + outliner_add_element(space_outliner, &te->subtree, curves, te, TSE_ANIM_DATA, 0); } break; } @@ -860,10 +856,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, te->parent = parent; te->index = index; /* For data arrays. */ - /* New C++ based type handle. Only some support this, eventually this should replace - * `TreeElement` entirely. */ - te->type = AbstractTreeElement::createFromType(type, *te, idv); - if (te->type) { + /* New inheritance based element representation. Not all element types support this yet, + * eventually it should replace #TreeElement entirely. */ + te->abstract_element = AbstractTreeElement::createFromType(type, *te, idv); + if (te->abstract_element) { /* Element types ported to the new design are expected to have their name set at this point! */ BLI_assert(te->name != nullptr); } @@ -887,12 +883,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* pass */ } else if (type == TSE_SOME_ID) { - if (!te->type) { + if (!te->abstract_element) { BLI_assert_msg(0, "Expected this ID type to be ported to new Outliner tree-element design"); } } else if (ELEM(type, TSE_LIBRARY_OVERRIDE_BASE, TSE_LIBRARY_OVERRIDE)) { - if (!te->type) { + if (!te->abstract_element) { BLI_assert_msg(0, "Expected override types to be ported to new Outliner tree-element design"); } @@ -903,20 +899,20 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* The new type design sets the name already, don't override that here. We need to figure out * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */ - if (!te->type) { + if (!te->abstract_element) { te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ } te->idcode = GS(id->name); } - if (te->type && te->type->isExpandValid()) { - tree_element_expand(*te->type, *space_outliner); + if (te->abstract_element && te->abstract_element->isExpandValid()) { + tree_element_expand(*te->abstract_element, *space_outliner); } else if (type == TSE_SOME_ID) { /* ID types not (fully) ported to new design yet. */ - if (te->type->expandPoll(*space_outliner)) { + if (te->abstract_element->expandPoll(*space_outliner)) { outliner_add_id_contents(space_outliner, te, tselem, id); - te->type->postExpand(*space_outliner); + te->abstract_element->postExpand(*space_outliner); } } else if (ELEM(type, diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc index afbbd171cf4..3289cb8ac76 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -69,7 +69,7 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t case ID_LP: case ID_GD: case ID_WS: - case ID_HA: + case ID_CV: case ID_PT: case ID_VO: case ID_SIM: diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index bf8cf89699d..d93dc0ac0c0 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -70,9 +70,5 @@ if(WITH_AUDASPACE) ) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_space_sequencer "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index aef6b30986d..439a37631e0 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -632,7 +632,7 @@ static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, Sequence *seq_movie, Sequence *seq_sound) { - if (ELEM(NULL, seq_movie, seq_sound) || seq_sound->len <= seq_movie->len) { + if (ELEM(NULL, seq_movie, seq_sound)) { return; } diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index 5d857f62b47..fd341fc9c0d 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Author: Peter Schlaile < peter [at] schlaile [dot] de > + * Copyright 2006-2008 Peter Schlaile < peter [at] schlaile [dot] de > */ /** \file diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 18f383d45fb..357b3e0a8b4 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -554,7 +554,7 @@ static void spreadsheet_footer_region_draw(const bContext *C, ARegion *region) UI_LAYOUT_HEADER, UI_HEADER_OFFSET, region->winy - (region->winy - UI_UNIT_Y) / 2.0f, - region->sizex, + region->winx, 1, 0, style); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index f4b5ff819ed..d9837b7c1a6 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -127,6 +127,28 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); } + if (data.type().is<int8_t>()) { + const int8_t value = data.get<int8_t>(real_index); + const std::string value_str = std::to_string(value); + uiBut *but = uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_NONE, + value_str.c_str(), + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + /* Right-align Integers. */ + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); + UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); + } else if (data.type().is<float>()) { const float value = data.get<float>(real_index); std::stringstream ss; diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index abd7620ea2b..a85c69caa50 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -61,8 +61,5 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() blender_add_lib(bf_editor_space_text "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 8fb55ed9b46..27941b881b8 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -79,10 +79,8 @@ static void text_font_end(const TextDrawContext *UNUSED(tdc)) static int text_font_draw(const TextDrawContext *tdc, int x, int y, const char *str) { - int columns; - BLF_position(tdc->font_id, x, y, 0); - columns = BLF_draw_mono(tdc->font_id, str, BLF_DRAW_STR_DUMMY_MAX, tdc->cwidth_px); + const int columns = BLF_draw_mono(tdc->font_id, str, BLF_DRAW_STR_DUMMY_MAX, tdc->cwidth_px); return tdc->cwidth_px * columns; } @@ -90,18 +88,17 @@ static int text_font_draw(const TextDrawContext *tdc, int x, int y, const char * static int text_font_draw_character(const TextDrawContext *tdc, int x, int y, char c) { BLF_position(tdc->font_id, x, y, 0); - BLF_draw(tdc->font_id, &c, 1); + BLF_draw_mono(tdc->font_id, &c, 1, tdc->cwidth_px); return tdc->cwidth_px; } -static int text_font_draw_character_utf8(const TextDrawContext *tdc, int x, int y, const char *c) +static int text_font_draw_character_utf8( + const TextDrawContext *tdc, int x, int y, const char *c, const int c_len) { - int columns; - - const size_t len = BLI_str_utf8_size_safe(c); + BLI_assert(c_len == BLI_str_utf8_size_safe(c)); BLF_position(tdc->font_id, x, y, 0); - columns = BLF_draw_mono(tdc->font_id, c, len, tdc->cwidth_px); + const int columns = BLF_draw_mono(tdc->font_id, c, c_len, tdc->cwidth_px); return tdc->cwidth_px * columns; } @@ -463,13 +460,15 @@ static int text_draw_wrapped(const SpaceText *st, } /* Draw the visible portion of text on the overshot line */ - for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) { + for (a = fstart, ma = mstart; ma < mend; a++) { if (use_syntax) { if (fmt_prev != format[a]) { format_draw_color(tdc, fmt_prev = format[a]); } } - x += text_font_draw_character_utf8(tdc, x, y, str + ma); + const int c_len = BLI_str_utf8_size_safe(str + ma); + x += text_font_draw_character_utf8(tdc, x, y, str + ma, c_len); + ma += c_len; fpos++; } y -= TXT_LINE_HEIGHT(st); @@ -491,15 +490,16 @@ static int text_draw_wrapped(const SpaceText *st, } /* Draw the remaining text */ - for (a = fstart, ma = mstart; str[ma] && y > clip_min_y; - a++, ma += BLI_str_utf8_size_safe(str + ma)) { + for (a = fstart, ma = mstart; str[ma] && y > clip_min_y; a++) { if (use_syntax) { if (fmt_prev != format[a]) { format_draw_color(tdc, fmt_prev = format[a]); } } - x += text_font_draw_character_utf8(tdc, x, y, str + ma); + const int c_len = BLI_str_utf8_size_safe(str + ma); + x += text_font_draw_character_utf8(tdc, x, y, str + ma, c_len); + ma += c_len; } flatten_string_free(&fs); @@ -559,8 +559,9 @@ static void text_draw(const SpaceText *st, if (format[a] != fmt_prev) { format_draw_color(tdc, fmt_prev = format[a]); } - x += text_font_draw_character_utf8(tdc, x, y, in + str_shift); - str_shift += BLI_str_utf8_size_safe(in + str_shift); + const int c_len = BLI_str_utf8_size_safe(in + str_shift); + x += text_font_draw_character_utf8(tdc, x, y, in + str_shift, c_len); + str_shift += c_len; } } else { diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index d40229332fd..e4c11bc8668 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -30,6 +30,7 @@ #ifdef WIN32 # include "BLI_winstuff.h" #endif +#include "BLI_path_util.h" #include "BKE_context.h" #include "BKE_main.h" @@ -142,16 +143,20 @@ static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot) static int preferences_asset_library_add_exec(bContext *UNUSED(C), wmOperator *op) { - char *directory = RNA_string_get_alloc(op->ptr, "directory", NULL, 0, NULL); + char *path = RNA_string_get_alloc(op->ptr, "directory", NULL, 0, NULL); + char dirname[FILE_MAXFILE]; + + BLI_path_slash_rstrip(path); + BLI_split_file_part(path, dirname, sizeof(dirname)); /* NULL is a valid directory path here. A library without path will be created then. */ - BKE_preferences_asset_library_add(&U, NULL, directory); + BKE_preferences_asset_library_add(&U, dirname, path); U.runtime.is_dirty = true; /* There's no dedicated notifier for the Preferences. */ WM_main_add_notifier(NC_WINDOW, NULL); - MEM_freeN(directory); + MEM_freeN(path); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 19f869ed50b..7e8b013192f 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -60,8 +60,17 @@ set(SRC view3d_gizmo_tool_generic.c view3d_header.c view3d_iterators.c + view3d_navigate.c + view3d_navigate_dolly.c view3d_navigate_fly.c + view3d_navigate_move.c + view3d_navigate_ndof.c + view3d_navigate_roll.c + view3d_navigate_rotate.c + view3d_navigate_smoothview.c view3d_navigate_walk.c + view3d_navigate_zoom.c + view3d_navigate_zoom_border.c view3d_ops.c view3d_placement.c view3d_project.c @@ -71,6 +80,7 @@ set(SRC view3d_view.c view3d_intern.h + view3d_navigate.h ) set(LIB @@ -83,11 +93,6 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() - -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 595ae3d8457..51107499d3f 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -89,6 +89,7 @@ #include "DEG_depsgraph_build.h" #include "view3d_intern.h" /* own include */ +#include "view3d_navigate.h" /* ******************** manage regions ********************* */ diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 243d4033cbc..6edb0a070c0 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1764,7 +1764,8 @@ static void view3d_panel_transform(const bContext *C, Panel *panel) v3d_transform_butsR(col, &obptr); /* Dimensions and editmode are mostly the same check. */ - if (OB_TYPE_SUPPORT_EDITMODE(ob->type) || ELEM(ob->type, OB_VOLUME, OB_HAIR, OB_POINTCLOUD)) { + if (OB_TYPE_SUPPORT_EDITMODE(ob->type) || + ELEM(ob->type, OB_VOLUME, OB_CURVES, OB_POINTCLOUD)) { View3D *v3d = CTX_wm_view3d(C); v3d_object_dimension_buts(NULL, col, v3d, ob); } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index b1f19581543..3f639e8ee1a 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1036,7 +1036,7 @@ static void draw_rotation_guide(const RegionView3D *rv3d) negate_v3_v3(o, rv3d->ofs); GPU_blend(GPU_BLEND_ALPHA); - GPU_depth_mask(false); /* don't overwrite zbuf */ + GPU_depth_mask(false); /* Don't overwrite the Z-buffer. */ GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); @@ -1258,11 +1258,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y /* 6 is the maximum size of the axis roll text. */ /* increase size for unicode languages (Chinese in utf-8...) */ -#ifdef WITH_INTERNATIONAL char tmpstr[96 + 6]; -#else - char tmpstr[32 + 6]; -#endif BLF_enable(font_id, BLF_SHADOW); BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); @@ -1689,9 +1685,9 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph, G.f |= G_FLAG_RENDER_VIEWPORT; { - /* free images which can have changed on frame-change - * warning! can be slow so only free animated images - campbell */ - BKE_image_free_anim_gputextures(G.main); /* XXX :((( */ + /* Free images which can have changed on frame-change. + * WARNING(@campbellbarton): can be slow so only free animated images. */ + BKE_image_free_anim_gputextures(G.main); } GPU_matrix_push_projection(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 80089815284..4c7a7cb4c61 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -23,70 +23,39 @@ * 3D view manipulation/operators. */ -#include <float.h> -#include <math.h> -#include <stdio.h> -#include <string.h> - #include "DNA_armature_types.h" #include "DNA_camera_types.h" -#include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" #include "DNA_world_types.h" #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "BLI_dial_2d.h" #include "BLI_math.h" -#include "BLI_utildefines.h" #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_camera.h" -#include "BKE_context.h" -#include "BKE_gpencil_geom.h" -#include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_object.h" -#include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" -#include "BKE_vfont.h" -#include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" #include "WM_api.h" #include "WM_message.h" -#include "WM_types.h" #include "RNA_access.h" #include "RNA_define.h" -#include "ED_armature.h" -#include "ED_mesh.h" -#include "ED_particle.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" -#include "ED_view3d.h" - -#include "UI_resources.h" - -#include "PIL_time.h" #include "view3d_intern.h" /* own include */ -enum { - HAS_TRANSLATE = (1 << 0), - HAS_ROTATE = (1 << 0), -}; - /* test for unlocked camera view in quad view */ static bool view3d_camera_user_poll(bContext *C) { @@ -115,3052 +84,6 @@ static bool view3d_lock_poll(bContext *C) return false; } -static bool view3d_pan_poll(bContext *C) -{ - if (ED_operator_region_view3d_active(C)) { - const RegionView3D *rv3d = CTX_wm_region_view3d(C); - return !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_LOCATION); - } - return false; -} - -static bool view3d_zoom_or_dolly_poll(bContext *C) -{ - if (ED_operator_region_view3d_active(C)) { - const RegionView3D *rv3d = CTX_wm_region_view3d(C); - return !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ZOOM_AND_DOLLY); - } - return false; -} - -/* -------------------------------------------------------------------- */ -/** \name Generic View Operator Properties - * \{ */ - -enum eV3D_OpPropFlag { - V3D_OP_PROP_MOUSE_CO = (1 << 0), - V3D_OP_PROP_DELTA = (1 << 1), - V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2), - V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3), -}; - -static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag) -{ - if (flag & V3D_OP_PROP_MOUSE_CO) { - PropertyRNA *prop; - prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - } - if (flag & V3D_OP_PROP_DELTA) { - RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - } - if (flag & V3D_OP_PROP_USE_ALL_REGIONS) { - PropertyRNA *prop; - prop = RNA_def_boolean( - ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - } - if (flag & V3D_OP_PROP_USE_MOUSE_INIT) { - WM_operator_properties_use_cursor_init(ot); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Generic View Operator Custom-Data - * \{ */ - -typedef struct ViewOpsData { - /** Context pointers (assigned by #viewops_data_alloc). */ - Main *bmain; - Scene *scene; - ScrArea *area; - ARegion *region; - View3D *v3d; - RegionView3D *rv3d; - Depsgraph *depsgraph; - - /** Needed for continuous zoom. */ - wmTimer *timer; - - /** Viewport state on initialization, don't change afterwards. */ - struct { - float dist; - float camzoom; - float quat[4]; - /** #wmEvent.xy. */ - int event_xy[2]; - /** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set. - * so we can simulate pressing in the middle of the screen. */ - int event_xy_offset[2]; - /** #wmEvent.type that triggered the operator. */ - int event_type; - float ofs[3]; - /** Initial distance to 'ofs'. */ - float zfac; - - /** Trackball rotation only. */ - float trackvec[3]; - /** Dolly only. */ - float mousevec[3]; - - /** - * #RegionView3D.persp set after auto-perspective is applied. - * If we want the value before running the operator, add a separate member. - */ - char persp; - - /** Used for roll */ - Dial *dial; - } init; - - /** Previous state (previous modal event handled). */ - struct { - int event_xy[2]; - /** For operators that use time-steps (continuous zoom). */ - double time; - } prev; - - /** Current state. */ - struct { - /** Working copy of #RegionView3D.viewquat, needed for rotation calculation - * so we can apply snap to the 3D Viewport while keeping the unsnapped rotation - * here to use when snap is disabled and for continued calculation. */ - float viewquat[4]; - } curr; - - float reverse; - bool axis_snap; /* view rotate only */ - - /** Use for orbit selection and auto-dist. */ - float dyn_ofs[3]; - bool use_dyn_ofs; -} ViewOpsData; - -/** - * Size of the sphere being dragged for trackball rotation within the view bounds. - * also affects speed (smaller is faster). - */ -#define TRACKBALLSIZE (1.1f) - -static void calctrackballvec(const rcti *rect, const int event_xy[2], float r_dir[3]) -{ - const float radius = TRACKBALLSIZE; - const float t = radius / (float)M_SQRT2; - const float size[2] = {BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)}; - /* Aspect correct so dragging in a non-square view doesn't squash the direction. - * So diagonal motion rotates the same direction the cursor is moving. */ - const float size_min = min_ff(size[0], size[1]); - const float aspect[2] = {size_min / size[0], size_min / size[1]}; - - /* Normalize x and y. */ - r_dir[0] = (event_xy[0] - BLI_rcti_cent_x(rect)) / ((size[0] * aspect[0]) / 2.0); - r_dir[1] = (event_xy[1] - BLI_rcti_cent_y(rect)) / ((size[1] * aspect[1]) / 2.0); - const float d = len_v2(r_dir); - if (d < t) { - /* Inside sphere. */ - r_dir[2] = sqrtf(square_f(radius) - square_f(d)); - } - else { - /* On hyperbola. */ - r_dir[2] = square_f(t) / d; - } -} - -/** - * Allocate and fill in context pointers for #ViewOpsData - */ -static void viewops_data_alloc(bContext *C, wmOperator *op) -{ - ViewOpsData *vod = MEM_callocN(sizeof(ViewOpsData), "viewops data"); - - /* store data */ - op->customdata = vod; - vod->bmain = CTX_data_main(C); - vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - vod->scene = CTX_data_scene(C); - vod->area = CTX_wm_area(C); - vod->region = CTX_wm_region(C); - vod->v3d = vod->area->spacedata.first; - vod->rv3d = vod->region->regiondata; -} - -void view3d_orbit_apply_dyn_ofs(float r_ofs[3], - const float ofs_old[3], - const float viewquat_old[4], - const float viewquat_new[4], - const float dyn_ofs[3]) -{ - float q[4]; - invert_qt_qt_normalized(q, viewquat_old); - mul_qt_qtqt(q, q, viewquat_new); - - invert_qt_normalized(q); - - sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs); - mul_qt_v3(q, r_ofs); - add_v3_v3(r_ofs, dyn_ofs); -} - -static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) -{ - static float lastofs[3] = {0, 0, 0}; - bool is_set = false; - - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); - View3D *v3d = CTX_wm_view3d(C); - Object *ob_act_eval = OBACT(view_layer_eval); - Object *ob_act = DEG_get_original_object(ob_act_eval); - - if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) && - /* with weight-paint + pose-mode, fall through to using calculateTransformCenter */ - ((ob_act->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob_act)) == 0) { - /* in case of sculpting use last average stroke position as a rotation - * center, in other cases it's not clear what rotation center shall be - * so just rotate around object origin - */ - if (ob_act->mode & - (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { - float stroke[3]; - BKE_paint_stroke_get_average(scene, ob_act_eval, stroke); - copy_v3_v3(lastofs, stroke); - } - else { - copy_v3_v3(lastofs, ob_act_eval->obmat[3]); - } - is_set = true; - } - else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) { - Curve *cu = ob_act_eval->data; - EditFont *ef = cu->editfont; - - zero_v3(lastofs); - for (int i = 0; i < 4; i++) { - add_v2_v2(lastofs, ef->textcurs[i]); - } - mul_v2_fl(lastofs, 1.0f / 4.0f); - - mul_m4_v3(ob_act_eval->obmat, lastofs); - - is_set = true; - } - else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) { - /* object mode use boundbox centers */ - Base *base_eval; - uint tot = 0; - float select_center[3]; - - zero_v3(select_center); - for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) { - if (BASE_SELECTED(v3d, base_eval)) { - /* use the boundbox if we can */ - Object *ob_eval = base_eval->object; - - if (ob_eval->runtime.bb && !(ob_eval->runtime.bb->flag & BOUNDBOX_DIRTY)) { - float cent[3]; - - BKE_boundbox_calc_center_aabb(ob_eval->runtime.bb, cent); - - mul_m4_v3(ob_eval->obmat, cent); - add_v3_v3(select_center, cent); - } - else { - add_v3_v3(select_center, ob_eval->obmat[3]); - } - tot++; - } - } - if (tot) { - mul_v3_fl(select_center, 1.0f / (float)tot); - copy_v3_v3(lastofs, select_center); - is_set = true; - } - } - else { - /* If there's no selection, lastofs is unmodified and last value since static */ - is_set = calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, lastofs, NULL); - } - - copy_v3_v3(r_dyn_ofs, lastofs); - - return is_set; -} - -enum eViewOpsFlag { - /** When enabled, rotate around the selection. */ - VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0), - /** When enabled, use the depth under the cursor for navigation. */ - VIEWOPS_FLAG_DEPTH_NAVIGATE = (1 << 1), - /** - * When enabled run #ED_view3d_persp_ensure this may switch out of camera view - * when orbiting or switch from orthographic to perspective when auto-perspective is enabled. - * Some operations don't require this (view zoom/pan or NDOF where subtle rotation is common - * so we don't want it to trigger auto-perspective). */ - VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2), - /** When set, ignore any options that depend on initial cursor location. */ - VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3), -}; - -static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth) -{ - enum eViewOpsFlag flag = 0; - if (use_select) { - flag |= VIEWOPS_FLAG_ORBIT_SELECT; - } - if (use_depth) { - flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE; - } - - return flag; -} - -static enum eViewOpsFlag viewops_flag_from_prefs(void) -{ - return viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, - (U.uiflag & USER_DEPTH_NAVIGATE) != 0); -} - -/** - * Calculate the values for #ViewOpsData - */ -static void viewops_data_create(bContext *C, - wmOperator *op, - const wmEvent *event, - enum eViewOpsFlag viewops_flag) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ViewOpsData *vod = op->customdata; - RegionView3D *rv3d = vod->rv3d; - - /* Could do this more nicely. */ - if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) { - viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; - } - - /* we need the depth info before changing any viewport options */ - if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { - float fallback_depth_pt[3]; - - view3d_operator_needs_opengl(C); /* needed for zbuf drawing */ - - negate_v3_v3(fallback_depth_pt, rv3d->ofs); - - vod->use_dyn_ofs = ED_view3d_autodist( - depsgraph, vod->region, vod->v3d, event->mval, vod->dyn_ofs, true, fallback_depth_pt); - } - else { - vod->use_dyn_ofs = false; - } - - if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) { - if (ED_view3d_persp_ensure(depsgraph, vod->v3d, vod->region)) { - /* If we're switching from camera view to the perspective one, - * need to tag viewport update, so camera view and borders are properly updated. */ - ED_region_tag_redraw(vod->region); - } - } - - /* set the view from the camera, if view locking is enabled. - * we may want to make this optional but for now its needed always */ - ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d); - - vod->init.persp = rv3d->persp; - vod->init.dist = rv3d->dist; - vod->init.camzoom = rv3d->camzoom; - copy_qt_qt(vod->init.quat, rv3d->viewquat); - copy_v2_v2_int(vod->init.event_xy, event->xy); - copy_v2_v2_int(vod->prev.event_xy, event->xy); - - if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) { - zero_v2_int(vod->init.event_xy_offset); - } - else { - /* Simulate the event starting in the middle of the region. */ - vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->region->winrct) - event->xy[0]; - vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->region->winrct) - event->xy[1]; - } - - vod->init.event_type = event->type; - copy_v3_v3(vod->init.ofs, rv3d->ofs); - - copy_qt_qt(vod->curr.viewquat, rv3d->viewquat); - - if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) { - float ofs[3]; - if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) { - vod->use_dyn_ofs = true; - negate_v3_v3(vod->dyn_ofs, ofs); - viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; - } - } - - if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { - if (vod->use_dyn_ofs) { - if (rv3d->is_persp) { - float my_origin[3]; /* original G.vd->ofs */ - float my_pivot[3]; /* view */ - float dvec[3]; - - /* locals for dist correction */ - float mat[3][3]; - float upvec[3]; - - negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */ - - /* Set the dist value to be the distance from this 3d point this means you'll - * always be able to zoom into it and panning won't go bad when dist was zero. */ - - /* remove dist value */ - upvec[0] = upvec[1] = 0; - upvec[2] = rv3d->dist; - copy_m3_m4(mat, rv3d->viewinv); - - mul_m3_v3(mat, upvec); - sub_v3_v3v3(my_pivot, rv3d->ofs, upvec); - negate_v3(my_pivot); /* ofs is flipped */ - - /* find a new ofs value that is along the view axis - * (rather than the mouse location) */ - closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin); - vod->init.dist = rv3d->dist = len_v3v3(my_pivot, dvec); - - negate_v3_v3(rv3d->ofs, dvec); - } - else { - const float mval_region_mid[2] = {(float)vod->region->winx / 2.0f, - (float)vod->region->winy / 2.0f}; - - ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_region_mid, rv3d->ofs); - negate_v3(rv3d->ofs); - } - negate_v3(vod->dyn_ofs); - copy_v3_v3(vod->init.ofs, rv3d->ofs); - } - } - - /* For dolly */ - ED_view3d_win_to_vector(vod->region, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec); - - { - int event_xy_offset[2]; - add_v2_v2v2_int(event_xy_offset, event->xy, vod->init.event_xy_offset); - - /* For rotation with trackball rotation. */ - calctrackballvec(&vod->region->winrct, event_xy_offset, vod->init.trackvec); - } - - { - float tvec[3]; - negate_v3_v3(tvec, rv3d->ofs); - vod->init.zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); - } - - vod->reverse = 1.0f; - if (rv3d->persmat[2][1] < 0.0f) { - vod->reverse = -1.0f; - } - - rv3d->rflag |= RV3D_NAVIGATING; -} - -static void viewops_data_free(bContext *C, wmOperator *op) -{ - ARegion *region; - if (op->customdata) { - ViewOpsData *vod = op->customdata; - region = vod->region; - vod->rv3d->rflag &= ~RV3D_NAVIGATING; - - if (vod->timer) { - WM_event_remove_timer(CTX_wm_manager(C), vod->timer->win, vod->timer); - } - - if (vod->init.dial) { - MEM_freeN(vod->init.dial); - } - - MEM_freeN(vod); - op->customdata = NULL; - } - else { - region = CTX_wm_region(C); - } - - /* Need to redraw because drawing code uses RV3D_NAVIGATING to draw - * faster while navigation operator runs. */ - ED_region_tag_redraw(region); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Rotate Operator - * \{ */ - -enum { - VIEW_PASS = 0, - VIEW_APPLY, - VIEW_CONFIRM, -}; - -/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ -enum { - VIEW_MODAL_CONFIRM = 1, /* used for all view operations */ - VIEWROT_MODAL_AXIS_SNAP_ENABLE = 2, - VIEWROT_MODAL_AXIS_SNAP_DISABLE = 3, - VIEWROT_MODAL_SWITCH_ZOOM = 4, - VIEWROT_MODAL_SWITCH_MOVE = 5, - VIEWROT_MODAL_SWITCH_ROTATE = 6, -}; - -void viewrotate_modal_keymap(wmKeyConfig *keyconf) -{ - static const EnumPropertyItem modal_items[] = { - {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Axis Snap", ""}, - {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Axis Snap (Off)", ""}, - - {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, - {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, - - {0, NULL, 0, NULL, NULL}, - }; - - wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Rotate Modal"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) { - return; - } - - keymap = WM_modalkeymap_ensure(keyconf, "View3D Rotate Modal", modal_items); - - /* disabled mode switching for now, can re-implement better, later on */ -#if 0 - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); -#endif - - /* assign map to operators */ - WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate"); -} - -static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4]) -{ - if (vod->use_dyn_ofs) { - RegionView3D *rv3d = vod->rv3d; - view3d_orbit_apply_dyn_ofs( - rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs); - } -} - -static void viewrotate_apply_snap(ViewOpsData *vod) -{ - const float axis_limit = DEG2RADF(45 / 3); - - RegionView3D *rv3d = vod->rv3d; - - float viewquat_inv[4]; - float zaxis[3] = {0, 0, 1}; - float zaxis_best[3]; - int x, y, z; - bool found = false; - - invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat); - - mul_qt_v3(viewquat_inv, zaxis); - normalize_v3(zaxis); - - for (x = -1; x < 2; x++) { - for (y = -1; y < 2; y++) { - for (z = -1; z < 2; z++) { - if (x || y || z) { - float zaxis_test[3] = {x, y, z}; - - normalize_v3(zaxis_test); - - if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) { - copy_v3_v3(zaxis_best, zaxis_test); - found = true; - } - } - } - } - } - - if (found) { - - /* find the best roll */ - float quat_roll[4], quat_final[4], quat_best[4], quat_snap[4]; - float viewquat_align[4]; /* viewquat aligned to zaxis_best */ - float viewquat_align_inv[4]; /* viewquat aligned to zaxis_best */ - float best_angle = axis_limit; - int j; - - /* viewquat_align is the original viewquat aligned to the snapped axis - * for testing roll */ - rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis); - normalize_qt(viewquat_align); - mul_qt_qtqt(viewquat_align, vod->curr.viewquat, viewquat_align); - normalize_qt(viewquat_align); - invert_qt_qt_normalized(viewquat_align_inv, viewquat_align); - - vec_to_quat(quat_snap, zaxis_best, OB_NEGZ, OB_POSY); - normalize_qt(quat_snap); - invert_qt_normalized(quat_snap); - - /* check if we can find the roll */ - found = false; - - /* find best roll */ - for (j = 0; j < 8; j++) { - float angle; - float xaxis1[3] = {1, 0, 0}; - float xaxis2[3] = {1, 0, 0}; - float quat_final_inv[4]; - - axis_angle_to_quat(quat_roll, zaxis_best, (float)j * DEG2RADF(45.0f)); - normalize_qt(quat_roll); - - mul_qt_qtqt(quat_final, quat_snap, quat_roll); - normalize_qt(quat_final); - - /* compare 2 vector angles to find the least roll */ - invert_qt_qt_normalized(quat_final_inv, quat_final); - mul_qt_v3(viewquat_align_inv, xaxis1); - mul_qt_v3(quat_final_inv, xaxis2); - angle = angle_v3v3(xaxis1, xaxis2); - - if (angle <= best_angle) { - found = true; - best_angle = angle; - copy_qt_qt(quat_best, quat_final); - } - } - - if (found) { - /* lock 'quat_best' to an axis view if we can */ - ED_view3d_quat_to_axis_view(quat_best, 0.01f, &rv3d->view, &rv3d->view_axis_roll); - if (rv3d->view != RV3D_VIEW_USER) { - ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, quat_best); - } - } - else { - copy_qt_qt(quat_best, viewquat_align); - } - - copy_qt_qt(rv3d->viewquat, quat_best); - - viewrotate_apply_dyn_ofs(vod, rv3d->viewquat); - - if (U.uiflag & USER_AUTOPERSP) { - if (RV3D_VIEW_IS_AXIS(rv3d->view)) { - if (rv3d->persp == RV3D_PERSP) { - rv3d->persp = RV3D_ORTHO; - } - } - } - } - else if (U.uiflag & USER_AUTOPERSP) { - rv3d->persp = vod->init.persp; - } -} - -static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2]) -{ - RegionView3D *rv3d = vod->rv3d; - - rv3d->view = RV3D_VIEW_USER; /* need to reset every time because of view snapping */ - - if (U.flag & USER_TRACKBALL) { - float axis[3], q1[4], dvec[3], newvec[3]; - float angle; - - { - const int event_xy_offset[2] = { - event_xy[0] + vod->init.event_xy_offset[0], - event_xy[1] + vod->init.event_xy_offset[1], - }; - calctrackballvec(&vod->region->winrct, event_xy_offset, newvec); - } - - sub_v3_v3v3(dvec, newvec, vod->init.trackvec); - - angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI; - - /* Before applying the sensitivity this is rotating 1:1, - * where the cursor would match the surface of a sphere in the view. */ - angle *= U.view_rotate_sensitivity_trackball; - - /* Allow for rotation beyond the interval [-pi, pi] */ - angle = angle_wrap_rad(angle); - - /* This relation is used instead of the actual angle between vectors - * so that the angle of rotation is linearly proportional to - * the distance that the mouse is dragged. */ - - cross_v3_v3v3(axis, vod->init.trackvec, newvec); - axis_angle_to_quat(q1, axis, angle); - - mul_qt_qtqt(vod->curr.viewquat, q1, vod->init.quat); - - viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); - } - else { - float quat_local_x[4], quat_global_z[4]; - float m[3][3]; - float m_inv[3][3]; - const float zvec_global[3] = {0.0f, 0.0f, 1.0f}; - float xaxis[3]; - - /* Radians per-pixel. */ - const float sensitivity = U.view_rotate_sensitivity_turntable / U.dpi_fac; - - /* Get the 3x3 matrix and its inverse from the quaternion */ - quat_to_mat3(m, vod->curr.viewquat); - invert_m3_m3(m_inv, m); - - /* Avoid Gimbal Lock - * - * Even though turn-table mode is in use, this can occur when the user exits the camera view - * or when aligning the view to a rotated object. - * - * We have gimbal lock when the user's view is rotated +/- 90 degrees along the view axis. - * In this case the vertical rotation is the same as the sideways turntable motion. - * Making it impossible to get out of the gimbal locked state without resetting the view. - * - * The logic below lets the user exit out of this state without any abrupt 'fix' - * which would be disorienting. - * - * This works by blending two horizons: - * - Rotated-horizon: `cross_v3_v3v3(xaxis, zvec_global, m_inv[2])` - * When only this is used, this turntable rotation works - but it's side-ways - * (as if the entire turn-table has been placed on its side) - * While there is no gimbal lock, it's also awkward to use. - * - Un-rotated-horizon: `m_inv[0]` - * When only this is used, the turntable rotation can have gimbal lock. - * - * The solution used here is to blend between these two values, - * so the severity of the gimbal lock is used to blend the rotated horizon. - * Blending isn't essential, it just makes the transition smoother. - * - * This allows sideways turn-table rotation on a Z axis that isn't world-space Z, - * While up-down turntable rotation eventually corrects gimbal lock. */ -#if 1 - if (len_squared_v3v3(zvec_global, m_inv[2]) > 0.001f) { - float fac; - cross_v3_v3v3(xaxis, zvec_global, m_inv[2]); - if (dot_v3v3(xaxis, m_inv[0]) < 0) { - negate_v3(xaxis); - } - fac = angle_normalized_v3v3(zvec_global, m_inv[2]) / (float)M_PI; - fac = fabsf(fac - 0.5f) * 2; - fac = fac * fac; - interp_v3_v3v3(xaxis, xaxis, m_inv[0], fac); - } - else { - copy_v3_v3(xaxis, m_inv[0]); - } -#else - copy_v3_v3(xaxis, m_inv[0]); -#endif - - /* Determine the direction of the x vector (for rotating up and down) */ - /* This can likely be computed directly from the quaternion. */ - - /* Perform the up/down rotation */ - axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(event_xy[1] - vod->prev.event_xy[1])); - mul_qt_qtqt(quat_local_x, vod->curr.viewquat, quat_local_x); - - /* Perform the orbital rotation */ - axis_angle_to_quat_single( - quat_global_z, 'Z', sensitivity * vod->reverse * (event_xy[0] - vod->prev.event_xy[0])); - mul_qt_qtqt(vod->curr.viewquat, quat_local_x, quat_global_z); - - viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); - } - - /* avoid precision loss over time */ - normalize_qt(vod->curr.viewquat); - - /* use a working copy so view rotation locking doesn't overwrite the locked - * rotation back into the view we calculate with */ - copy_qt_qt(rv3d->viewquat, vod->curr.viewquat); - - /* Check for view snap, - * NOTE: don't apply snap to `vod->viewquat` so the view won't jam up. */ - if (vod->axis_snap) { - viewrotate_apply_snap(vod); - } - vod->prev.event_xy[0] = event_xy[0]; - vod->prev.event_xy[1] = event_xy[1]; - - ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, rv3d); - - ED_region_tag_redraw(vod->region); -} - -static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod = op->customdata; - short event_code = VIEW_PASS; - bool use_autokey = false; - int ret = OPERATOR_RUNNING_MODAL; - - /* execute the events */ - if (event->type == MOUSEMOVE) { - event_code = VIEW_APPLY; - } - else if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case VIEW_MODAL_CONFIRM: - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_AXIS_SNAP_ENABLE: - vod->axis_snap = true; - event_code = VIEW_APPLY; - break; - case VIEWROT_MODAL_AXIS_SNAP_DISABLE: - vod->rv3d->persp = vod->init.persp; - vod->axis_snap = false; - event_code = VIEW_APPLY; - break; - case VIEWROT_MODAL_SWITCH_ZOOM: - WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_MOVE: - WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - } - } - else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { - event_code = VIEW_CONFIRM; - } - - if (event_code == VIEW_APPLY) { - viewrotate_apply(vod, event->xy); - if (ED_screen_animation_playing(CTX_wm_manager(C))) { - use_autokey = true; - } - } - else if (event_code == VIEW_CONFIRM) { - use_autokey = true; - ret = OPERATOR_FINISHED; - } - - if (use_autokey) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true); - } - - if (ret & OPERATOR_FINISHED) { - viewops_data_free(C, op); - } - - return ret; -} - -static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod; - - const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); - - /* makes op->customdata */ - viewops_data_alloc(C, op); - vod = op->customdata; - - /* poll should check but in some cases fails, see poll func for details */ - if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_ROTATION) { - viewops_data_free(C, op); - return OPERATOR_PASS_THROUGH; - } - - ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); - - viewops_data_create(C, - op, - event, - viewops_flag_from_prefs() | VIEWOPS_FLAG_PERSP_ENSURE | - (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); - - if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) { - /* Rotate direction we keep always same */ - int event_xy[2]; - - if (event->type == MOUSEPAN) { - if (event->is_direction_inverted) { - event_xy[0] = 2 * event->xy[0] - event->prev_xy[0]; - event_xy[1] = 2 * event->xy[1] - event->prev_xy[1]; - } - else { - copy_v2_v2_int(event_xy, event->prev_xy); - } - } - else { - /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ - copy_v2_v2_int(event_xy, event->prev_xy); - } - - viewrotate_apply(vod, event_xy); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; - } - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; -} - -static void viewrotate_cancel(bContext *C, wmOperator *op) -{ - viewops_data_free(C, op); -} - -void VIEW3D_OT_rotate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Rotate View"; - ot->description = "Rotate the view"; - ot->idname = "VIEW3D_OT_rotate"; - - /* api callbacks */ - ot->invoke = viewrotate_invoke; - ot->modal = viewrotate_modal; - ot->poll = ED_operator_region_view3d_active; - ot->cancel = viewrotate_cancel; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; - - view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name NDOF Utility Functions - * \{ */ - -#ifdef WITH_INPUT_NDOF -static bool ndof_has_translate(const wmNDOFMotionData *ndof, - const View3D *v3d, - const RegionView3D *rv3d) -{ - return !is_zero_v3(ndof->tvec) && (!ED_view3d_offset_lock_check(v3d, rv3d)); -} - -static bool ndof_has_rotate(const wmNDOFMotionData *ndof, const RegionView3D *rv3d) -{ - return !is_zero_v3(ndof->rvec) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0); -} - -/** - * \param depth_pt: A point to calculate the depth (in perspective mode) - */ -static float view3d_ndof_pan_speed_calc_ex(RegionView3D *rv3d, const float depth_pt[3]) -{ - float speed = rv3d->pixsize * NDOF_PIXELS_PER_SECOND; - - if (rv3d->is_persp) { - speed *= ED_view3d_calc_zfac(rv3d, depth_pt, NULL); - } - - return speed; -} - -static float view3d_ndof_pan_speed_calc_from_dist(RegionView3D *rv3d, const float dist) -{ - float viewinv[4]; - float tvec[3]; - - BLI_assert(dist >= 0.0f); - - copy_v3_fl3(tvec, 0.0f, 0.0f, dist); - /* rv3d->viewinv isn't always valid */ -# if 0 - mul_mat3_m4_v3(rv3d->viewinv, tvec); -# else - invert_qt_qt_normalized(viewinv, rv3d->viewquat); - mul_qt_v3(viewinv, tvec); -# endif - - return view3d_ndof_pan_speed_calc_ex(rv3d, tvec); -} - -static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d) -{ - float tvec[3]; - negate_v3_v3(tvec, rv3d->ofs); - - return view3d_ndof_pan_speed_calc_ex(rv3d, tvec); -} - -/** - * Zoom and pan in the same function since sometimes zoom is interpreted as dolly (pan forward). - * - * \param has_zoom: zoom, otherwise dolly, - * often `!rv3d->is_persp` since it doesn't make sense to dolly in ortho. - */ -static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, - ScrArea *area, - ARegion *region, - const bool has_translate, - const bool has_zoom) -{ - RegionView3D *rv3d = region->regiondata; - float view_inv[4]; - float pan_vec[3]; - - if (has_translate == false && has_zoom == false) { - return; - } - - WM_event_ndof_pan_get(ndof, pan_vec, false); - - if (has_zoom) { - /* zoom with Z */ - - /* Zoom! - * velocity should be proportional to the linear velocity attained by rotational motion - * of same strength [got that?] proportional to `arclength = radius * angle`. - */ - - pan_vec[2] = 0.0f; - - /* "zoom in" or "translate"? depends on zoom mode in user settings? */ - if (ndof->tvec[2]) { - float zoom_distance = rv3d->dist * ndof->dt * ndof->tvec[2]; - - if (U.ndof_flag & NDOF_ZOOM_INVERT) { - zoom_distance = -zoom_distance; - } - - rv3d->dist += zoom_distance; - } - } - else { - /* dolly with Z */ - - /* all callers must check */ - if (has_translate) { - BLI_assert(ED_view3d_offset_lock_check((View3D *)area->spacedata.first, rv3d) == false); - } - } - - if (has_translate) { - const float speed = view3d_ndof_pan_speed_calc(rv3d); - - mul_v3_fl(pan_vec, speed * ndof->dt); - - /* transform motion from view to world coordinates */ - invert_qt_qt_normalized(view_inv, rv3d->viewquat); - mul_qt_v3(view_inv, pan_vec); - - /* move center of view opposite of hand motion (this is camera mode, not object mode) */ - sub_v3_v3(rv3d->ofs, pan_vec); - - if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(area, region); - } - } -} - -static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, - ScrArea *area, - ARegion *region, - ViewOpsData *vod, - const bool apply_dyn_ofs) -{ - View3D *v3d = area->spacedata.first; - RegionView3D *rv3d = region->regiondata; - - float view_inv[4]; - - BLI_assert((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0); - - ED_view3d_persp_ensure(vod->depsgraph, v3d, region); - - rv3d->view = RV3D_VIEW_USER; - - invert_qt_qt_normalized(view_inv, rv3d->viewquat); - - if (U.ndof_flag & NDOF_TURNTABLE) { - float rot[3]; - - /* Turntable view code adapted for 3D mouse use. */ - float angle, quat[4]; - float xvec[3] = {1, 0, 0}; - - /* only use XY, ignore Z */ - WM_event_ndof_rotate_get(ndof, rot); - - /* Determine the direction of the x vector (for rotating up and down) */ - mul_qt_v3(view_inv, xvec); - - /* Perform the up/down rotation */ - angle = ndof->dt * rot[0]; - axis_angle_to_quat(quat, xvec, angle); - mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); - - /* Perform the orbital rotation */ - angle = ndof->dt * rot[1]; - - /* update the onscreen doo-dad */ - rv3d->rot_angle = angle; - rv3d->rot_axis[0] = 0; - rv3d->rot_axis[1] = 0; - rv3d->rot_axis[2] = 1; - - axis_angle_to_quat_single(quat, 'Z', angle); - mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); - } - else { - float quat[4]; - float axis[3]; - float angle = WM_event_ndof_to_axis_angle(ndof, axis); - - /* transform rotation axis from view to world coordinates */ - mul_qt_v3(view_inv, axis); - - /* update the onscreen doo-dad */ - rv3d->rot_angle = angle; - copy_v3_v3(rv3d->rot_axis, axis); - - axis_angle_to_quat(quat, axis, angle); - - /* apply rotation */ - mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); - } - - if (apply_dyn_ofs) { - viewrotate_apply_dyn_ofs(vod, rv3d->viewquat); - } -} - -void view3d_ndof_fly(const wmNDOFMotionData *ndof, - View3D *v3d, - RegionView3D *rv3d, - const bool use_precision, - const short protectflag, - bool *r_has_translate, - bool *r_has_rotate) -{ - bool has_translate = ndof_has_translate(ndof, v3d, rv3d); - bool has_rotate = ndof_has_rotate(ndof, rv3d); - - float view_inv[4]; - invert_qt_qt_normalized(view_inv, rv3d->viewquat); - - rv3d->rot_angle = 0.0f; /* disable onscreen rotation doo-dad */ - - if (has_translate) { - /* ignore real 'dist' since fly has its own speed settings, - * also its overwritten at this point. */ - float speed = view3d_ndof_pan_speed_calc_from_dist(rv3d, 1.0f); - float trans[3], trans_orig_y; - - if (use_precision) { - speed *= 0.2f; - } - - WM_event_ndof_pan_get(ndof, trans, false); - mul_v3_fl(trans, speed * ndof->dt); - trans_orig_y = trans[1]; - - if (U.ndof_flag & NDOF_FLY_HELICOPTER) { - trans[1] = 0.0f; - } - - /* transform motion from view to world coordinates */ - mul_qt_v3(view_inv, trans); - - if (U.ndof_flag & NDOF_FLY_HELICOPTER) { - /* replace world z component with device y (yes it makes sense) */ - trans[2] = trans_orig_y; - } - - if (rv3d->persp == RV3D_CAMOB) { - /* respect camera position locks */ - if (protectflag & OB_LOCK_LOCX) { - trans[0] = 0.0f; - } - if (protectflag & OB_LOCK_LOCY) { - trans[1] = 0.0f; - } - if (protectflag & OB_LOCK_LOCZ) { - trans[2] = 0.0f; - } - } - - if (!is_zero_v3(trans)) { - /* move center of view opposite of hand motion - * (this is camera mode, not object mode) */ - sub_v3_v3(rv3d->ofs, trans); - has_translate = true; - } - else { - has_translate = false; - } - } - - if (has_rotate) { - const float turn_sensitivity = 1.0f; - - float rotation[4]; - float axis[3]; - float angle = turn_sensitivity * WM_event_ndof_to_axis_angle(ndof, axis); - - if (fabsf(angle) > 0.0001f) { - has_rotate = true; - - if (use_precision) { - angle *= 0.2f; - } - - /* transform rotation axis from view to world coordinates */ - mul_qt_v3(view_inv, axis); - - /* apply rotation to view */ - axis_angle_to_quat(rotation, axis, angle); - mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); - - if (U.ndof_flag & NDOF_LOCK_HORIZON) { - /* force an upright viewpoint - * TODO: make this less... sudden */ - float view_horizon[3] = {1.0f, 0.0f, 0.0f}; /* view +x */ - float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */ - - /* find new inverse since viewquat has changed */ - invert_qt_qt_normalized(view_inv, rv3d->viewquat); - /* could apply reverse rotation to existing view_inv to save a few cycles */ - - /* transform view vectors to world coordinates */ - mul_qt_v3(view_inv, view_horizon); - mul_qt_v3(view_inv, view_direction); - - /* find difference between view & world horizons - * true horizon lives in world xy plane, so look only at difference in z */ - angle = -asinf(view_horizon[2]); - - /* rotate view so view horizon = world horizon */ - axis_angle_to_quat(rotation, view_direction, angle); - mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); - } - - rv3d->view = RV3D_VIEW_USER; - } - else { - has_rotate = false; - } - } - - *r_has_translate = has_translate; - *r_has_rotate = has_rotate; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name NDOF Orbit/Translate Operator - * \{ */ - -static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - if (event->type != NDOF_MOTION) { - return OPERATOR_CANCELLED; - } - - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ViewOpsData *vod; - View3D *v3d; - RegionView3D *rv3d; - char xform_flag = 0; - - const wmNDOFMotionData *ndof = event->customdata; - - viewops_data_alloc(C, op); - viewops_data_create( - C, op, event, viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); - vod = op->customdata; - - ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); - - v3d = vod->v3d; - rv3d = vod->rv3d; - - /* off by default, until changed later this function */ - rv3d->rot_angle = 0.0f; - - ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); - - if (ndof->progress != P_FINISHING) { - const bool has_rotation = ndof_has_rotate(ndof, rv3d); - /* if we can't rotate, fallback to translate (locked axis views) */ - const bool has_translate = ndof_has_translate(ndof, v3d, rv3d) && - (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION); - const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp; - - if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom); - xform_flag |= HAS_TRANSLATE; - } - - if (has_rotation) { - view3d_ndof_orbit(ndof, vod->area, vod->region, vod, true); - xform_flag |= HAS_ROTATE; - } - } - - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - if (xform_flag) { - ED_view3d_camera_lock_autokey( - v3d, rv3d, C, xform_flag & HAS_ROTATE, xform_flag & HAS_TRANSLATE); - } - - ED_region_tag_redraw(vod->region); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "NDOF Orbit View"; - ot->description = "Orbit the view using the 3D mouse"; - ot->idname = "VIEW3D_OT_ndof_orbit"; - - /* api callbacks */ - ot->invoke = ndof_orbit_invoke; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = 0; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name NDOF Orbit/Zoom Operator - * \{ */ - -static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - if (event->type != NDOF_MOTION) { - return OPERATOR_CANCELLED; - } - - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ViewOpsData *vod; - View3D *v3d; - RegionView3D *rv3d; - char xform_flag = 0; - - const wmNDOFMotionData *ndof = event->customdata; - - viewops_data_alloc(C, op); - viewops_data_create( - C, op, event, viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); - - vod = op->customdata; - - ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); - - v3d = vod->v3d; - rv3d = vod->rv3d; - - /* off by default, until changed later this function */ - rv3d->rot_angle = 0.0f; - - ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); - - if (ndof->progress == P_FINISHING) { - /* pass */ - } - else if ((rv3d->persp == RV3D_ORTHO) && RV3D_VIEW_IS_AXIS(rv3d->view)) { - /* if we can't rotate, fallback to translate (locked axis views) */ - const bool has_translate = ndof_has_translate(ndof, v3d, rv3d); - const bool has_zoom = (ndof->tvec[2] != 0.0f) && ED_view3d_offset_lock_check(v3d, rv3d); - - if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, true); - xform_flag |= HAS_TRANSLATE; - } - } - else { - /* NOTE: based on feedback from T67579, users want to have pan and orbit enabled at once. - * It's arguable that orbit shouldn't pan (since we have a pan only operator), - * so if there are users who like to separate orbit/pan operations - it can be a preference. */ - const bool is_orbit_around_pivot = (U.ndof_flag & NDOF_MODE_ORBIT) || - ED_view3d_offset_lock_check(v3d, rv3d); - const bool has_rotation = ndof_has_rotate(ndof, rv3d); - bool has_translate, has_zoom; - - if (is_orbit_around_pivot) { - /* Orbit preference or forced lock (Z zooms). */ - has_translate = !is_zero_v2(ndof->tvec) && ndof_has_translate(ndof, v3d, rv3d); - has_zoom = (ndof->tvec[2] != 0.0f); - } - else { - /* Free preference (Z translates). */ - has_translate = ndof_has_translate(ndof, v3d, rv3d); - has_zoom = false; - } - - /* Rotation first because dynamic offset resets offset otherwise (and disables panning). */ - if (has_rotation) { - const float dist_backup = rv3d->dist; - if (!is_orbit_around_pivot) { - ED_view3d_distance_set(rv3d, 0.0f); - } - view3d_ndof_orbit(ndof, vod->area, vod->region, vod, is_orbit_around_pivot); - xform_flag |= HAS_ROTATE; - if (!is_orbit_around_pivot) { - ED_view3d_distance_set(rv3d, dist_backup); - } - } - - if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom); - xform_flag |= HAS_TRANSLATE; - } - } - - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - if (xform_flag) { - ED_view3d_camera_lock_autokey( - v3d, rv3d, C, xform_flag & HAS_ROTATE, xform_flag & HAS_TRANSLATE); - } - - ED_region_tag_redraw(vod->region); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "NDOF Orbit View with Zoom"; - ot->description = "Orbit and zoom the view using the 3D mouse"; - ot->idname = "VIEW3D_OT_ndof_orbit_zoom"; - - /* api callbacks */ - ot->invoke = ndof_orbit_zoom_invoke; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = 0; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name NDOF Pan/Zoom Operator - * \{ */ - -static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) -{ - if (event->type != NDOF_MOTION) { - return OPERATOR_CANCELLED; - } - - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - const wmNDOFMotionData *ndof = event->customdata; - char xform_flag = 0; - - const bool has_translate = ndof_has_translate(ndof, v3d, rv3d); - const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp; - - /* we're panning here! so erase any leftover rotation from other operators */ - rv3d->rot_angle = 0.0f; - - if (!(has_translate || has_zoom)) { - return OPERATOR_CANCELLED; - } - - ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); - - if (ndof->progress != P_FINISHING) { - ScrArea *area = CTX_wm_area(C); - ARegion *region = CTX_wm_region(C); - - if (has_translate || has_zoom) { - view3d_ndof_pan_zoom(ndof, area, region, has_translate, has_zoom); - xform_flag |= HAS_TRANSLATE; - } - } - - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - if (xform_flag) { - ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, xform_flag & HAS_TRANSLATE); - } - - ED_region_tag_redraw(CTX_wm_region(C)); - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "NDOF Pan View"; - ot->description = "Pan the view with the 3D mouse"; - ot->idname = "VIEW3D_OT_ndof_pan"; - - /* api callbacks */ - ot->invoke = ndof_pan_invoke; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = 0; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name NDOF Transform All Operator - * \{ */ - -/** - * wraps #ndof_orbit_zoom but never restrict to orbit. - */ -static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - /* weak!, but it works */ - const int ndof_flag = U.ndof_flag; - int ret; - - U.ndof_flag &= ~NDOF_MODE_ORBIT; - - ret = ndof_orbit_zoom_invoke(C, op, event); - - U.ndof_flag = ndof_flag; - - return ret; -} - -void VIEW3D_OT_ndof_all(struct wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "NDOF Transform View"; - ot->description = "Pan and rotate the view with the 3D mouse"; - ot->idname = "VIEW3D_OT_ndof_all"; - - /* api callbacks */ - ot->invoke = ndof_all_invoke; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = 0; -} - -#endif /* WITH_INPUT_NDOF */ - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Move (Pan) Operator - * \{ */ - -/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ - -void viewmove_modal_keymap(wmKeyConfig *keyconf) -{ - static const EnumPropertyItem modal_items[] = { - {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, - {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, - - {0, NULL, 0, NULL, NULL}, - }; - - wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Move Modal"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) { - return; - } - - keymap = WM_modalkeymap_ensure(keyconf, "View3D Move Modal", modal_items); - - /* items for modal map */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, EVT_ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); - - /* disabled mode switching for now, can re-implement better, later on */ -#if 0 - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); - WM_modalkeymap_add_item( - keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); -#endif - - /* assign map to operators */ - WM_modalkeymap_assign(keymap, "VIEW3D_OT_move"); -} - -static void viewmove_apply(ViewOpsData *vod, int x, int y) -{ - if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) { - vod->rv3d->ofs_lock[0] -= ((vod->prev.event_xy[0] - x) * 2.0f) / (float)vod->region->winx; - vod->rv3d->ofs_lock[1] -= ((vod->prev.event_xy[1] - y) * 2.0f) / (float)vod->region->winy; - } - else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) { - const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - vod->rv3d->camdx += (vod->prev.event_xy[0] - x) / (vod->region->winx * zoomfac); - vod->rv3d->camdy += (vod->prev.event_xy[1] - y) / (vod->region->winy * zoomfac); - CLAMP(vod->rv3d->camdx, -1.0f, 1.0f); - CLAMP(vod->rv3d->camdy, -1.0f, 1.0f); - } - else { - float dvec[3]; - float mval_f[2]; - - mval_f[0] = x - vod->prev.event_xy[0]; - mval_f[1] = y - vod->prev.event_xy[1]; - ED_view3d_win_to_delta(vod->region, mval_f, dvec, vod->init.zfac); - - add_v3_v3(vod->rv3d->ofs, dvec); - - if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->area, vod->region); - } - } - - vod->prev.event_xy[0] = x; - vod->prev.event_xy[1] = y; - - ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); - - ED_region_tag_redraw(vod->region); -} - -static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - - ViewOpsData *vod = op->customdata; - short event_code = VIEW_PASS; - bool use_autokey = false; - int ret = OPERATOR_RUNNING_MODAL; - - /* execute the events */ - if (event->type == MOUSEMOVE) { - event_code = VIEW_APPLY; - } - else if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case VIEW_MODAL_CONFIRM: - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_ZOOM: - WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_ROTATE: - WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - } - } - else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { - event_code = VIEW_CONFIRM; - } - - if (event_code == VIEW_APPLY) { - viewmove_apply(vod, event->xy[0], event->xy[1]); - if (ED_screen_animation_playing(CTX_wm_manager(C))) { - use_autokey = true; - } - } - else if (event_code == VIEW_CONFIRM) { - use_autokey = true; - ret = OPERATOR_FINISHED; - } - - if (use_autokey) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); - } - - if (ret & OPERATOR_FINISHED) { - viewops_data_free(C, op); - } - - return ret; -} - -static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod; - - const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); - - /* makes op->customdata */ - viewops_data_alloc(C, op); - vod = op->customdata; - if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_LOCATION) { - viewops_data_free(C, op); - return OPERATOR_PASS_THROUGH; - } - - viewops_data_create(C, - op, - event, - (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) | - (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); - - ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); - - if (event->type == MOUSEPAN) { - /* invert it, trackpad scroll follows same principle as 2d windows this way */ - viewmove_apply( - vod, 2 * event->xy[0] - event->prev_xy[0], 2 * event->xy[1] - event->prev_xy[1]); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; - } - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; -} - -static void viewmove_cancel(bContext *C, wmOperator *op) -{ - viewops_data_free(C, op); -} - -void VIEW3D_OT_move(wmOperatorType *ot) -{ - - /* identifiers */ - ot->name = "Pan View"; - ot->description = "Move the view"; - ot->idname = "VIEW3D_OT_move"; - - /* api callbacks */ - ot->invoke = viewmove_invoke; - ot->modal = viewmove_modal; - ot->poll = ED_operator_region_view3d_active; - ot->cancel = viewmove_cancel; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; - - /* properties */ - view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Zoom Operator - * \{ */ - -/* #viewdolly_modal_keymap has an exact copy of this, apply fixes to both. */ -void viewzoom_modal_keymap(wmKeyConfig *keyconf) -{ - static const EnumPropertyItem modal_items[] = { - {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, - {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, - - {0, NULL, 0, NULL, NULL}, - }; - - wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Zoom Modal"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) { - return; - } - - keymap = WM_modalkeymap_ensure(keyconf, "View3D Zoom Modal", modal_items); - - /* disabled mode switching for now, can re-implement better, later on */ -#if 0 - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); -#endif - - /* assign map to operators */ - WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); -} - -/** - * \param zoom_xy: Optionally zoom to window location - * (coords compatible w/ #wmEvent.xy). Use when not NULL. - */ -static void view_zoom_to_window_xy_camera(Scene *scene, - Depsgraph *depsgraph, - View3D *v3d, - ARegion *region, - float dfac, - const int zoom_xy[2]) -{ - RegionView3D *rv3d = region->regiondata; - const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); - const float zoomfac_new = clamp_f( - zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR); - const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new); - - if (zoom_xy != NULL) { - float zoomfac_px; - rctf camera_frame_old; - rctf camera_frame_new; - - const float pt_src[2] = {zoom_xy[0], zoom_xy[1]}; - float pt_dst[2]; - float delta_px[2]; - - ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_old, false); - BLI_rctf_translate(&camera_frame_old, region->winrct.xmin, region->winrct.ymin); - - rv3d->camzoom = camzoom_new; - CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); - - ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_new, false); - BLI_rctf_translate(&camera_frame_new, region->winrct.xmin, region->winrct.ymin); - - BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src); - sub_v2_v2v2(delta_px, pt_dst, pt_src); - - /* translate the camera offset using pixel space delta - * mapped back to the camera (same logic as panning in camera view) */ - zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f; - - rv3d->camdx += delta_px[0] / (region->winx * zoomfac_px); - rv3d->camdy += delta_px[1] / (region->winy * zoomfac_px); - CLAMP(rv3d->camdx, -1.0f, 1.0f); - CLAMP(rv3d->camdy, -1.0f, 1.0f); - } - else { - rv3d->camzoom = camzoom_new; - CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); - } -} - -/** - * \param zoom_xy: Optionally zoom to window location - * (coords compatible w/ #wmEvent.xy). Use when not NULL. - */ -static void view_zoom_to_window_xy_3d(ARegion *region, float dfac, const int zoom_xy[2]) -{ - RegionView3D *rv3d = region->regiondata; - const float dist_new = rv3d->dist * dfac; - - if (zoom_xy != NULL) { - float dvec[3]; - float tvec[3]; - float tpos[3]; - float mval_f[2]; - - float zfac; - - negate_v3_v3(tpos, rv3d->ofs); - - mval_f[0] = (float)(((zoom_xy[0] - region->winrct.xmin) * 2) - region->winx) / 2.0f; - mval_f[1] = (float)(((zoom_xy[1] - region->winrct.ymin) * 2) - region->winy) / 2.0f; - - /* Project cursor position into 3D space */ - zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL); - ED_view3d_win_to_delta(region, mval_f, dvec, zfac); - - /* Calculate view target position for dolly */ - add_v3_v3v3(tvec, tpos, dvec); - negate_v3(tvec); - - /* Offset to target position and dolly */ - copy_v3_v3(rv3d->ofs, tvec); - rv3d->dist = dist_new; - - /* Calculate final offset */ - madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac); - } - else { - rv3d->dist = dist_new; - } -} - -static float viewzoom_scale_value(const rcti *winrct, - const eViewZoom_Style viewzoom, - const bool zoom_invert, - const bool zoom_invert_force, - const int xy_curr[2], - const int xy_init[2], - const float val, - const float val_orig, - double *r_timer_lastdraw) -{ - float zfac; - - if (viewzoom == USER_ZOOM_CONTINUE) { - double time = PIL_check_seconds_timer(); - float time_step = (float)(time - *r_timer_lastdraw); - float fac; - - if (U.uiflag & USER_ZOOM_HORIZ) { - fac = (float)(xy_init[0] - xy_curr[0]); - } - else { - fac = (float)(xy_init[1] - xy_curr[1]); - } - - fac /= U.dpi_fac; - - if (zoom_invert != zoom_invert_force) { - fac = -fac; - } - - zfac = 1.0f + ((fac / 20.0f) * time_step); - *r_timer_lastdraw = time; - } - else if (viewzoom == USER_ZOOM_SCALE) { - /* method which zooms based on how far you move the mouse */ - - const int ctr[2] = { - BLI_rcti_cent_x(winrct), - BLI_rcti_cent_y(winrct), - }; - float len_new = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_curr) / U.dpi_fac); - float len_old = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_init) / U.dpi_fac); - - /* intentionally ignore 'zoom_invert' for scale */ - if (zoom_invert_force) { - SWAP(float, len_new, len_old); - } - - zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val; - } - else { /* USER_ZOOM_DOLLY */ - float len_new = 5 * U.dpi_fac; - float len_old = 5 * U.dpi_fac; - - if (U.uiflag & USER_ZOOM_HORIZ) { - len_new += (winrct->xmax - (xy_curr[0])) / U.dpi_fac; - len_old += (winrct->xmax - (xy_init[0])) / U.dpi_fac; - } - else { - len_new += (winrct->ymax - (xy_curr[1])) / U.dpi_fac; - len_old += (winrct->ymax - (xy_init[1])) / U.dpi_fac; - } - - if (zoom_invert != zoom_invert_force) { - SWAP(float, len_new, len_old); - } - - zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val; - } - - return zfac; -} - -static float viewzoom_scale_value_offset(const rcti *winrct, - const eViewZoom_Style viewzoom, - const bool zoom_invert, - const bool zoom_invert_force, - const int xy_curr[2], - const int xy_init[2], - const int xy_offset[2], - const float val, - const float val_orig, - double *r_timer_lastdraw) -{ - const int xy_curr_offset[2] = { - xy_curr[0] + xy_offset[0], - xy_curr[1] + xy_offset[1], - }; - const int xy_init_offset[2] = { - xy_init[0] + xy_offset[0], - xy_init[1] + xy_offset[1], - }; - return viewzoom_scale_value(winrct, - viewzoom, - zoom_invert, - zoom_invert_force, - xy_curr_offset, - xy_init_offset, - val, - val_orig, - r_timer_lastdraw); -} - -static void viewzoom_apply_camera(ViewOpsData *vod, - const int xy[2], - const eViewZoom_Style viewzoom, - const bool zoom_invert, - const bool zoom_to_pos) -{ - float zfac; - float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f; - float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - - zfac = viewzoom_scale_value_offset(&vod->region->winrct, - viewzoom, - zoom_invert, - true, - xy, - vod->init.event_xy, - vod->init.event_xy_offset, - zoomfac, - zoomfac_prev, - &vod->prev.time); - - if (!ELEM(zfac, 1.0f, 0.0f)) { - /* calculate inverted, then invert again (needed because of camera zoom scaling) */ - zfac = 1.0f / zfac; - view_zoom_to_window_xy_camera(vod->scene, - vod->depsgraph, - vod->v3d, - vod->region, - zfac, - zoom_to_pos ? vod->prev.event_xy : NULL); - } - - ED_region_tag_redraw(vod->region); -} - -static void viewzoom_apply_3d(ViewOpsData *vod, - const int xy[2], - const eViewZoom_Style viewzoom, - const bool zoom_invert, - const bool zoom_to_pos) -{ - float zfac; - float dist_range[2]; - - ED_view3d_dist_range_get(vod->v3d, dist_range); - - zfac = viewzoom_scale_value_offset(&vod->region->winrct, - viewzoom, - zoom_invert, - false, - xy, - vod->init.event_xy, - vod->init.event_xy_offset, - vod->rv3d->dist, - vod->init.dist, - &vod->prev.time); - - if (zfac != 1.0f) { - const float zfac_min = dist_range[0] / vod->rv3d->dist; - const float zfac_max = dist_range[1] / vod->rv3d->dist; - CLAMP(zfac, zfac_min, zfac_max); - - view_zoom_to_window_xy_3d(vod->region, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); - } - - /* these limits were in old code too */ - CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]); - - if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->area, vod->region); - } - - ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); - - ED_region_tag_redraw(vod->region); -} - -static void viewzoom_apply(ViewOpsData *vod, - const int xy[2], - const eViewZoom_Style viewzoom, - const bool zoom_invert, - const bool zoom_to_pos) -{ - if ((vod->rv3d->persp == RV3D_CAMOB) && - (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) { - viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos); - } - else { - viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos); - } -} - -static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod = op->customdata; - short event_code = VIEW_PASS; - bool use_autokey = false; - int ret = OPERATOR_RUNNING_MODAL; - - /* execute the events */ - if (event->type == TIMER && event->customdata == vod->timer) { - /* continuous zoom */ - event_code = VIEW_APPLY; - } - else if (event->type == MOUSEMOVE) { - event_code = VIEW_APPLY; - } - else if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case VIEW_MODAL_CONFIRM: - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_MOVE: - WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_ROTATE: - WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - } - } - else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { - event_code = VIEW_CONFIRM; - } - - if (event_code == VIEW_APPLY) { - const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); - viewzoom_apply(vod, - event->xy, - (eViewZoom_Style)U.viewzoom, - (U.uiflag & USER_ZOOM_INVERT) != 0, - (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); - if (ED_screen_animation_playing(CTX_wm_manager(C))) { - use_autokey = true; - } - } - else if (event_code == VIEW_CONFIRM) { - use_autokey = true; - ret = OPERATOR_FINISHED; - } - - if (use_autokey) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); - } - - if (ret & OPERATOR_FINISHED) { - viewops_data_free(C, op); - } - - return ret; -} - -static int viewzoom_exec(bContext *C, wmOperator *op) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - View3D *v3d; - RegionView3D *rv3d; - ScrArea *area; - ARegion *region; - bool use_cam_zoom; - float dist_range[2]; - - const int delta = RNA_int_get(op->ptr, "delta"); - const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); - - if (op->customdata) { - ViewOpsData *vod = op->customdata; - - area = vod->area; - region = vod->region; - } - else { - area = CTX_wm_area(C); - region = CTX_wm_region(C); - } - - v3d = area->spacedata.first; - rv3d = region->regiondata; - - use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && - !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d)); - - int zoom_xy_buf[2]; - const int *zoom_xy = NULL; - if (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) { - zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : - region->winx / 2; - zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : - region->winy / 2; - zoom_xy = zoom_xy_buf; - } - - ED_view3d_dist_range_get(v3d, dist_range); - - if (delta < 0) { - const float step = 1.2f; - /* this min and max is also in viewmove() */ - if (use_cam_zoom) { - view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy); - } - else { - if (rv3d->dist < dist_range[1]) { - view_zoom_to_window_xy_3d(region, step, zoom_xy); - } - } - } - else { - const float step = 1.0f / 1.2f; - if (use_cam_zoom) { - view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy); - } - else { - if (rv3d->dist > dist_range[0]) { - view_zoom_to_window_xy_3d(region, step, zoom_xy); - } - } - } - - if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(area, region); - } - - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true); - - ED_region_tag_redraw(region); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; -} - -/* viewdolly_invoke() copied this function, changes here may apply there */ -static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod; - - const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); - - /* makes op->customdata */ - viewops_data_alloc(C, op); - viewops_data_create(C, - op, - event, - (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) | - (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); - vod = op->customdata; - - ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); - - /* if one or the other zoom position aren't set, set from event */ - if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) { - RNA_int_set(op->ptr, "mx", event->xy[0]); - RNA_int_set(op->ptr, "my", event->xy[1]); - } - - if (RNA_struct_property_is_set(op->ptr, "delta")) { - viewzoom_exec(C, op); - } - else { - if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) { - - if (U.uiflag & USER_ZOOM_HORIZ) { - vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0]; - } - else { - /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] - - event->prev_xy[0]; - } - viewzoom_apply(vod, - event->prev_xy, - USER_ZOOM_DOLLY, - (U.uiflag & USER_ZOOM_INVERT) != 0, - (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); - - viewops_data_free(C, op); - return OPERATOR_FINISHED; - } - - if (U.viewzoom == USER_ZOOM_CONTINUE) { - /* needs a timer to continue redrawing */ - vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); - vod->prev.time = PIL_check_seconds_timer(); - } - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - return OPERATOR_FINISHED; -} - -static void viewzoom_cancel(bContext *C, wmOperator *op) -{ - viewops_data_free(C, op); -} - -void VIEW3D_OT_zoom(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Zoom View"; - ot->description = "Zoom in/out in the view"; - ot->idname = "VIEW3D_OT_zoom"; - - /* api callbacks */ - ot->invoke = viewzoom_invoke; - ot->exec = viewzoom_exec; - ot->modal = viewzoom_modal; - ot->poll = view3d_zoom_or_dolly_poll; - ot->cancel = viewzoom_cancel; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; - - /* properties */ - view3d_operator_properties_common( - ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Dolly Operator - * - * Like zoom but translates the view offset along the view direction - * which avoids #RegionView3D.dist approaching zero. - * \{ */ - -/* This is an exact copy of #viewzoom_modal_keymap. */ -void viewdolly_modal_keymap(wmKeyConfig *keyconf) -{ - static const EnumPropertyItem modal_items[] = { - {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, - {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, - - {0, NULL, 0, NULL, NULL}, - }; - - wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) { - return; - } - - keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items); - - /* disabled mode switching for now, can re-implement better, later on */ -#if 0 - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); -#endif - - /* assign map to operators */ - WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); -} - -static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) -{ - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (ED_view3d_offset_lock_check(v3d, rv3d)) { - BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked"); - return true; - } - return false; -} - -static void view_dolly_to_vector_3d(ARegion *region, - const float orig_ofs[3], - const float dvec[3], - float dfac) -{ - RegionView3D *rv3d = region->regiondata; - madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac)); -} - -static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const bool zoom_invert) -{ - float zfac = 1.0; - - { - float len1, len2; - - if (U.uiflag & USER_ZOOM_HORIZ) { - len1 = (vod->region->winrct.xmax - xy[0]) + 5; - len2 = (vod->region->winrct.xmax - vod->init.event_xy[0]) + 5; - } - else { - len1 = (vod->region->winrct.ymax - xy[1]) + 5; - len2 = (vod->region->winrct.ymax - vod->init.event_xy[1]) + 5; - } - if (zoom_invert) { - SWAP(float, len1, len2); - } - - zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist); - } - - if (zfac != 1.0f) { - view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, zfac); - } - - if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->area, vod->region); - } - - ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); - - ED_region_tag_redraw(vod->region); -} - -static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod = op->customdata; - short event_code = VIEW_PASS; - bool use_autokey = false; - int ret = OPERATOR_RUNNING_MODAL; - - /* execute the events */ - if (event->type == MOUSEMOVE) { - event_code = VIEW_APPLY; - } - else if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case VIEW_MODAL_CONFIRM: - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_MOVE: - WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_ROTATE: - WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - } - } - else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { - event_code = VIEW_CONFIRM; - } - - if (event_code == VIEW_APPLY) { - viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0); - if (ED_screen_animation_playing(CTX_wm_manager(C))) { - use_autokey = true; - } - } - else if (event_code == VIEW_CONFIRM) { - use_autokey = true; - ret = OPERATOR_FINISHED; - } - - if (use_autokey) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); - } - - if (ret & OPERATOR_FINISHED) { - viewops_data_free(C, op); - } - - return ret; -} - -static int viewdolly_exec(bContext *C, wmOperator *op) -{ - View3D *v3d; - RegionView3D *rv3d; - ScrArea *area; - ARegion *region; - float mousevec[3]; - - const int delta = RNA_int_get(op->ptr, "delta"); - - if (op->customdata) { - ViewOpsData *vod = op->customdata; - - area = vod->area; - region = vod->region; - copy_v3_v3(mousevec, vod->init.mousevec); - } - else { - area = CTX_wm_area(C); - region = CTX_wm_region(C); - negate_v3_v3(mousevec, ((RegionView3D *)region->regiondata)->viewinv[2]); - normalize_v3(mousevec); - } - - v3d = area->spacedata.first; - rv3d = region->regiondata; - - const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); - - /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { - normalize_v3_v3(mousevec, rv3d->viewinv[2]); - negate_v3(mousevec); - } - - view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 1.8f : 0.2f); - - if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(area, region); - } - - ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d); - - ED_region_tag_redraw(region); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; -} - -/* copied from viewzoom_invoke(), changes here may apply there */ -static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod; - - if (viewdolly_offset_lock_check(C, op)) { - return OPERATOR_CANCELLED; - } - - /* makes op->customdata */ - viewops_data_alloc(C, op); - vod = op->customdata; - - /* poll should check but in some cases fails, see poll func for details */ - if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_ROTATION) { - viewops_data_free(C, op); - return OPERATOR_PASS_THROUGH; - } - - ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); - - /* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */ - /* switch from camera view when: */ - if (vod->rv3d->persp != RV3D_PERSP) { - if (vod->rv3d->persp == RV3D_CAMOB) { - /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ED_view3d_persp_switch_from_camera(depsgraph, vod->v3d, vod->rv3d, RV3D_PERSP); - } - else { - vod->rv3d->persp = RV3D_PERSP; - } - ED_region_tag_redraw(vod->region); - } - - const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); - - viewops_data_create(C, - op, - event, - (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) | - (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); - - /* if one or the other zoom position aren't set, set from event */ - if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) { - RNA_int_set(op->ptr, "mx", event->xy[0]); - RNA_int_set(op->ptr, "my", event->xy[1]); - } - - if (RNA_struct_property_is_set(op->ptr, "delta")) { - viewdolly_exec(C, op); - } - else { - /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { - negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); - normalize_v3(vod->init.mousevec); - } - - if (event->type == MOUSEZOOM) { - /* Bypass Zoom invert flag for track pads (pass false always) */ - - if (U.uiflag & USER_ZOOM_HORIZ) { - vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0]; - } - else { - /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] - - event->prev_xy[0]; - } - viewdolly_apply(vod, event->prev_xy, (U.uiflag & USER_ZOOM_INVERT) == 0); - - viewops_data_free(C, op); - return OPERATOR_FINISHED; - } - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; - } - return OPERATOR_FINISHED; -} - -static void viewdolly_cancel(bContext *C, wmOperator *op) -{ - viewops_data_free(C, op); -} - -void VIEW3D_OT_dolly(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Dolly View"; - ot->description = "Dolly in/out in the view"; - ot->idname = "VIEW3D_OT_dolly"; - - /* api callbacks */ - ot->invoke = viewdolly_invoke; - ot->exec = viewdolly_exec; - ot->modal = viewdolly_modal; - ot->poll = ED_operator_region_view3d_active; - ot->cancel = viewdolly_cancel; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; - - /* properties */ - view3d_operator_properties_common( - ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View All Operator - * - * Move & Zoom the view to fit all of its contents. - * \{ */ - -static bool view3d_object_skip_minmax(const View3D *v3d, - const RegionView3D *rv3d, - const Object *ob, - const bool skip_camera, - bool *r_only_center) -{ - BLI_assert(ob->id.orig_id == NULL); - *r_only_center = false; - - if (skip_camera && (ob == v3d->camera)) { - return true; - } - - if ((ob->type == OB_EMPTY) && (ob->empty_drawtype == OB_EMPTY_IMAGE) && - !BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d)) { - *r_only_center = true; - return false; - } - - return false; -} - -static void view3d_object_calc_minmax(Depsgraph *depsgraph, - Scene *scene, - Object *ob_eval, - const bool only_center, - float min[3], - float max[3]) -{ - /* Account for duplis. */ - if (BKE_object_minmax_dupli(depsgraph, scene, ob_eval, min, max, false) == 0) { - /* Use if duplis aren't found. */ - if (only_center) { - minmax_v3v3_v3(min, max, ob_eval->obmat[3]); - } - else { - BKE_object_minmax(ob_eval, min, max, false); - } - } -} - -static void view3d_from_minmax(bContext *C, - View3D *v3d, - ARegion *region, - const float min[3], - const float max[3], - bool ok_dist, - const int smooth_viewtx) -{ - RegionView3D *rv3d = region->regiondata; - float afm[3]; - float size; - - ED_view3d_smooth_view_force_finish(C, v3d, region); - - /* SMOOTHVIEW */ - float new_ofs[3]; - float new_dist; - - sub_v3_v3v3(afm, max, min); - size = max_fff(afm[0], afm[1], afm[2]); - - if (ok_dist) { - char persp; - - if (rv3d->is_persp) { - if (rv3d->persp == RV3D_CAMOB && ED_view3d_camera_lock_check(v3d, rv3d)) { - persp = RV3D_CAMOB; - } - else { - persp = RV3D_PERSP; - } - } - else { /* ortho */ - if (size < 0.0001f) { - /* bounding box was a single point so do not zoom */ - ok_dist = false; - } - else { - /* adjust zoom so it looks nicer */ - persp = RV3D_ORTHO; - } - } - - if (ok_dist) { - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - new_dist = ED_view3d_radius_to_dist( - v3d, region, depsgraph, persp, true, (size / 2) * VIEW3D_MARGIN); - if (rv3d->is_persp) { - /* don't zoom closer than the near clipping plane */ - new_dist = max_ff(new_dist, v3d->clip_start * 1.5f); - } - } - } - - mid_v3_v3v3(new_ofs, min, max); - negate_v3(new_ofs); - - if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) { - rv3d->persp = RV3D_PERSP; - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .camera_old = v3d->camera, - .ofs = new_ofs, - .dist = ok_dist ? &new_dist : NULL, - }); - } - else { - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .ofs = new_ofs, - .dist = ok_dist ? &new_dist : NULL, - }); - } - - /* Smooth-view does view-lock #RV3D_BOXVIEW copy. */ -} - -/** - * Same as #view3d_from_minmax but for all regions (except cameras). - */ -static void view3d_from_minmax_multi(bContext *C, - View3D *v3d, - const float min[3], - const float max[3], - const bool ok_dist, - const int smooth_viewtx) -{ - ScrArea *area = CTX_wm_area(C); - ARegion *region; - for (region = area->regionbase.first; region; region = region->next) { - if (region->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = region->regiondata; - /* when using all regions, don't jump out of camera view, - * but _do_ allow locked cameras to be moved */ - if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { - view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx); - } - } - } -} - -static int view3d_all_exec(bContext *C, wmOperator *op) -{ - ARegion *region = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); - Base *base_eval; - const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions"); - const bool skip_camera = (ED_view3d_camera_lock_check(v3d, region->regiondata) || - /* any one of the regions may be locked */ - (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA)); - const bool center = RNA_boolean_get(op->ptr, "center"); - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - float min[3], max[3]; - bool changed = false; - - if (center) { - /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */ - View3DCursor *cursor = &scene->cursor; - zero_v3(min); - zero_v3(max); - zero_v3(cursor->location); - float mat3[3][3]; - unit_m3(mat3); - BKE_scene_cursor_mat3_to_rot(cursor, mat3, false); - } - else { - INIT_MINMAX(min, max); - } - - for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) { - if (BASE_VISIBLE(v3d, base_eval)) { - bool only_center = false; - Object *ob = DEG_get_original_object(base_eval->object); - if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) { - continue; - } - view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max); - changed = true; - } - } - - if (center) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - WM_msg_publish_rna_prop(mbus, &scene->id, &scene->cursor, View3DCursor, location); - - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - } - - if (!changed) { - ED_region_tag_redraw(region); - /* TODO: should this be cancel? - * I think no, because we always move the cursor, with or without - * object, but in this case there is no change in the scene, - * only the cursor so I choice a ED_region_tag like - * view3d_smooth_view do for the center_cursor. - * See bug T22640. - */ - return OPERATOR_FINISHED; - } - - if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - /* This is an approximation, see function documentation for details. */ - ED_view3d_clipping_clamp_minmax(rv3d, min, max); - } - - if (use_all_regions) { - view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx); - } - else { - view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx); - } - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_view_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Frame All"; - ot->description = "View all objects in scene"; - ot->idname = "VIEW3D_OT_view_all"; - - /* api callbacks */ - ot->exec = view3d_all_exec; - ot->poll = ED_operator_region_view3d_active; - - /* flags */ - ot->flag = 0; - - /* properties */ - view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); - RNA_def_boolean(ot->srna, "center", 0, "Center", ""); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Frame Selected Operator - * - * Move & Zoom the view to fit selected contents. - * \{ */ - -static int viewselected_exec(bContext *C, wmOperator *op) -{ - ARegion *region = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); - Object *ob_eval = OBACT(view_layer_eval); - Object *obedit = CTX_data_edit_object(C); - const bGPdata *gpd_eval = ob_eval && (ob_eval->type == OB_GPENCIL) ? ob_eval->data : NULL; - const bool is_gp_edit = gpd_eval ? GPENCIL_ANY_MODE(gpd_eval) : false; - const bool is_face_map = ((is_gp_edit == false) && region->gizmo_map && - WM_gizmomap_is_any_selected(region->gizmo_map)); - float min[3], max[3]; - bool ok = false, ok_dist = true; - const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions"); - const bool skip_camera = (ED_view3d_camera_lock_check(v3d, region->regiondata) || - /* any one of the regions may be locked */ - (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA)); - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - INIT_MINMAX(min, max); - if (is_face_map) { - ob_eval = NULL; - } - - if (ob_eval && (ob_eval->mode & OB_MODE_WEIGHT_PAINT)) { - /* hard-coded exception, we look for the one selected armature */ - /* this is weak code this way, we should make a generic - * active/selection callback interface once... */ - Base *base_eval; - for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) { - if (BASE_SELECTED_EDITABLE(v3d, base_eval)) { - if (base_eval->object->type == OB_ARMATURE) { - if (base_eval->object->mode & OB_MODE_POSE) { - break; - } - } - } - } - if (base_eval) { - ob_eval = base_eval->object; - } - } - - if (is_gp_edit) { - CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { - /* we're only interested in selected points here... */ - if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) { - ok |= BKE_gpencil_stroke_minmax(gps, true, min, max); - } - if (gps->editcurve != NULL) { - for (int i = 0; i < gps->editcurve->tot_curve_points; i++) { - BezTriple *bezt = &gps->editcurve->curve_points[i].bezt; - if ((bezt->f1 & SELECT)) { - minmax_v3v3_v3(min, max, bezt->vec[0]); - ok = true; - } - if ((bezt->f2 & SELECT)) { - minmax_v3v3_v3(min, max, bezt->vec[1]); - ok = true; - } - if ((bezt->f3 & SELECT)) { - minmax_v3v3_v3(min, max, bezt->vec[2]); - ok = true; - } - } - } - } - CTX_DATA_END; - - if ((ob_eval) && (ok)) { - mul_m4_v3(ob_eval->obmat, min); - mul_m4_v3(ob_eval->obmat, max); - } - } - else if (is_face_map) { - ok = WM_gizmomap_minmax(region->gizmo_map, true, true, min, max); - } - else if (obedit) { - /* only selected */ - FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->type, obedit->mode, ob_eval_iter) { - ok |= ED_view3d_minmax_verts(ob_eval_iter, min, max); - } - FOREACH_OBJECT_IN_MODE_END; - } - else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) { - FOREACH_OBJECT_IN_MODE_BEGIN ( - view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter) { - ok |= BKE_pose_minmax(ob_eval_iter, min, max, true, true); - } - FOREACH_OBJECT_IN_MODE_END; - } - else if (BKE_paint_select_face_test(ob_eval)) { - ok = paintface_minmax(ob_eval, min, max); - } - else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) { - ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max); - } - else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | - OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { - BKE_paint_stroke_get_average(scene, ob_eval, min); - copy_v3_v3(max, min); - ok = true; - ok_dist = 0; /* don't zoom */ - } - else { - Base *base_eval; - for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) { - if (BASE_SELECTED(v3d, base_eval)) { - bool only_center = false; - Object *ob = DEG_get_original_object(base_eval->object); - if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) { - continue; - } - view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max); - ok = 1; - } - } - } - - if (ok == 0) { - return OPERATOR_FINISHED; - } - - if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - /* This is an approximation, see function documentation for details. */ - ED_view3d_clipping_clamp_minmax(rv3d, min, max); - } - - if (use_all_regions) { - view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx); - } - else { - view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx); - } - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_view_selected(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Frame Selected"; - ot->description = "Move the view to the selection center"; - ot->idname = "VIEW3D_OT_view_selected"; - - /* api callbacks */ - ot->exec = viewselected_exec; - ot->poll = view3d_zoom_or_dolly_poll; - - /* flags */ - ot->flag = 0; - - /* properties */ - view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name View Lock Clear Operator * \{ */ @@ -3256,103 +179,6 @@ void VIEW3D_OT_view_lock_to_active(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name View Center Cursor Operator - * \{ */ - -static int viewcenter_cursor_exec(bContext *C, wmOperator *op) -{ - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - Scene *scene = CTX_data_scene(C); - - if (rv3d) { - ARegion *region = CTX_wm_region(C); - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - ED_view3d_smooth_view_force_finish(C, v3d, region); - - /* non camera center */ - float new_ofs[3]; - negate_v3_v3(new_ofs, scene->cursor.location); - ED_view3d_smooth_view( - C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs}); - - /* Smooth view does view-lock #RV3D_BOXVIEW copy. */ - } - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Center View to Cursor"; - ot->description = "Center the view so that the cursor is in the middle of the view"; - ot->idname = "VIEW3D_OT_view_center_cursor"; - - /* api callbacks */ - ot->exec = viewcenter_cursor_exec; - ot->poll = view3d_pan_poll; - - /* flags */ - ot->flag = 0; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Center Pick Operator - * \{ */ - -static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - ARegion *region = CTX_wm_region(C); - - if (rv3d) { - struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - float new_ofs[3]; - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - ED_view3d_smooth_view_force_finish(C, v3d, region); - - view3d_operator_needs_opengl(C); - - if (ED_view3d_autodist(depsgraph, region, v3d, event->mval, new_ofs, false, NULL)) { - /* pass */ - } - else { - /* fallback to simple pan */ - negate_v3_v3(new_ofs, rv3d->ofs); - ED_view3d_win_to_3d_int(v3d, region, new_ofs, event->mval, new_ofs); - } - negate_v3(new_ofs); - ED_view3d_smooth_view( - C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs}); - } - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_view_center_pick(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Center View to Mouse"; - ot->description = "Center the view to the Z-depth position under the mouse cursor"; - ot->idname = "VIEW3D_OT_view_center_pick"; - - /* api callbacks */ - ot->invoke = viewcenter_pick_invoke; - ot->poll = view3d_pan_poll; - - /* flags */ - ot->flag = 0; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Frame Camera Bounds Operator * \{ */ @@ -3591,189 +417,6 @@ void VIEW3D_OT_clear_render_border(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Border Zoom Operator - * \{ */ - -static int view3d_zoom_border_exec(bContext *C, wmOperator *op) -{ - ARegion *region = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - /* Zooms in on a border drawn by the user */ - rcti rect; - float dvec[3], vb[2], xscale, yscale; - float dist_range[2]; - - /* SMOOTHVIEW */ - float new_dist; - float new_ofs[3]; - - /* ZBuffer depth vars */ - float depth_close = FLT_MAX; - float cent[2], p[3]; - - /* NOTE: otherwise opengl won't work. */ - view3d_operator_needs_opengl(C); - - /* get box select values using rna */ - WM_operator_properties_border_to_rcti(op, &rect); - - /* check if zooming in/out view */ - const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out"); - - ED_view3d_dist_range_get(v3d, dist_range); - - ED_view3d_depth_override( - CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); - { - /* avoid allocating the whole depth buffer */ - ViewDepths depth_temp = {0}; - - /* avoid view3d_update_depths() for speed. */ - view3d_depths_rect_create(region, &rect, &depth_temp); - - /* find the closest Z pixel */ - depth_close = view3d_depth_near(&depth_temp); - - MEM_SAFE_FREE(depth_temp.depths); - } - - /* Resize border to the same ratio as the window. */ - { - const float region_aspect = (float)region->winx / (float)region->winy; - if (((float)BLI_rcti_size_x(&rect) / (float)BLI_rcti_size_y(&rect)) < region_aspect) { - BLI_rcti_resize_x(&rect, (int)(BLI_rcti_size_y(&rect) * region_aspect)); - } - else { - BLI_rcti_resize_y(&rect, (int)(BLI_rcti_size_x(&rect) / region_aspect)); - } - } - - cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2; - cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2; - - if (rv3d->is_persp) { - float p_corner[3]; - - /* no depths to use, we can't do anything! */ - if (depth_close == FLT_MAX) { - BKE_report(op->reports, RPT_ERROR, "Depth too large"); - return OPERATOR_CANCELLED; - } - /* convert border to 3d coordinates */ - if ((!ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p)) || - (!ED_view3d_unproject_v3(region, rect.xmin, rect.ymin, depth_close, p_corner))) { - return OPERATOR_CANCELLED; - } - - sub_v3_v3v3(dvec, p, p_corner); - negate_v3_v3(new_ofs, p); - - new_dist = len_v3(dvec); - - /* Account for the lens, without this a narrow lens zooms in too close. */ - new_dist *= (v3d->lens / DEFAULT_SENSOR_WIDTH); - - /* ignore dist_range min */ - dist_range[0] = v3d->clip_start * 1.5f; - } - else { /* orthographic */ - /* find the current window width and height */ - vb[0] = region->winx; - vb[1] = region->winy; - - new_dist = rv3d->dist; - - /* convert the drawn rectangle into 3d space */ - if (depth_close != FLT_MAX && - ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p)) { - negate_v3_v3(new_ofs, p); - } - else { - float mval_f[2]; - float zfac; - - /* We can't use the depth, fallback to the old way that doesn't set the center depth */ - copy_v3_v3(new_ofs, rv3d->ofs); - - { - float tvec[3]; - negate_v3_v3(tvec, new_ofs); - zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); - } - - mval_f[0] = (rect.xmin + rect.xmax - vb[0]) / 2.0f; - mval_f[1] = (rect.ymin + rect.ymax - vb[1]) / 2.0f; - ED_view3d_win_to_delta(region, mval_f, dvec, zfac); - /* center the view to the center of the rectangle */ - sub_v3_v3(new_ofs, dvec); - } - - /* work out the ratios, so that everything selected fits when we zoom */ - xscale = (BLI_rcti_size_x(&rect) / vb[0]); - yscale = (BLI_rcti_size_y(&rect) / vb[1]); - new_dist *= max_ff(xscale, yscale); - } - - if (!zoom_in) { - sub_v3_v3v3(dvec, new_ofs, rv3d->ofs); - new_dist = rv3d->dist * (rv3d->dist / new_dist); - add_v3_v3v3(new_ofs, rv3d->ofs, dvec); - } - - /* clamp after because we may have been zooming out */ - CLAMP(new_dist, dist_range[0], dist_range[1]); - - /* TODO(campbell): 'is_camera_lock' not currently working well. */ - const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d); - if ((rv3d->persp == RV3D_CAMOB) && (is_camera_lock == false)) { - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, RV3D_PERSP); - } - - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .ofs = new_ofs, - .dist = &new_dist, - }); - - if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(CTX_wm_area(C), region); - } - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_zoom_border(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Zoom to Border"; - ot->description = "Zoom in the view to the nearest object contained in the border"; - ot->idname = "VIEW3D_OT_zoom_border"; - - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = view3d_zoom_border_exec; - ot->modal = WM_gesture_box_modal; - ot->cancel = WM_gesture_box_cancel; - - ot->poll = view3d_zoom_or_dolly_poll; - - /* flags */ - ot->flag = 0; - - /* properties */ - WM_operator_properties_gesture_box_zoom(ot); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Set Camera Zoom 1:1 Operator * * Sets the view to 1:1 camera/render-pixel. @@ -3830,838 +473,6 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name View Axis Operator - * \{ */ - -static const EnumPropertyItem prop_view_items[] = { - {RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View from the left"}, - {RV3D_VIEW_RIGHT, "RIGHT", ICON_TRIA_RIGHT, "Right", "View from the right"}, - {RV3D_VIEW_BOTTOM, "BOTTOM", ICON_TRIA_DOWN, "Bottom", "View from the bottom"}, - {RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View from the top"}, - {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View from the front"}, - {RV3D_VIEW_BACK, "BACK", 0, "Back", "View from the back"}, - {0, NULL, 0, NULL, NULL}, -}; - -/* would like to make this a generic function - outside of transform */ - -/** - * \param align_to_quat: When not NULL, set the axis relative to this rotation. - */ -static void axis_set_view(bContext *C, - View3D *v3d, - ARegion *region, - const float quat_[4], - char view, - char view_axis_roll, - int perspo, - const float *align_to_quat, - const int smooth_viewtx) -{ - RegionView3D *rv3d = region->regiondata; /* no NULL check is needed, poll checks */ - float quat[4]; - const short orig_persp = rv3d->persp; - - normalize_qt_qt(quat, quat_); - - if (align_to_quat) { - mul_qt_qtqt(quat, quat, align_to_quat); - rv3d->view = view = RV3D_VIEW_USER; - rv3d->view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; - } - - if (align_to_quat == NULL) { - rv3d->view = view; - rv3d->view_axis_roll = view_axis_roll; - } - - if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) { - ED_region_tag_redraw(region); - return; - } - - if (U.uiflag & USER_AUTOPERSP) { - rv3d->persp = RV3D_VIEW_IS_AXIS(view) ? RV3D_ORTHO : perspo; - } - else if (rv3d->persp == RV3D_CAMOB) { - rv3d->persp = perspo; - } - - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - /* to camera */ - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .camera_old = v3d->camera, - .ofs = rv3d->ofs, - .quat = quat, - }); - } - else if (orig_persp == RV3D_CAMOB && v3d->camera) { - /* from camera */ - float ofs[3], dist; - - copy_v3_v3(ofs, rv3d->ofs); - dist = rv3d->dist; - - /* so we animate _from_ the camera location */ - Object *camera_eval = DEG_get_evaluated_object(CTX_data_ensure_evaluated_depsgraph(C), - v3d->camera); - ED_view3d_from_object(camera_eval, rv3d->ofs, NULL, &rv3d->dist, NULL); - - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .camera_old = camera_eval, - .ofs = ofs, - .quat = quat, - .dist = &dist, - }); - } - else { - /* rotate around selection */ - const float *dyn_ofs_pt = NULL; - float dyn_ofs[3]; - - if (U.uiflag & USER_ORBIT_SELECTION) { - if (view3d_orbit_calc_center(C, dyn_ofs)) { - negate_v3(dyn_ofs); - dyn_ofs_pt = dyn_ofs; - } - } - - /* no camera involved */ - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .quat = quat, - .dyn_ofs = dyn_ofs_pt, - }); - } -} - -static int view_axis_exec(bContext *C, wmOperator *op) -{ - View3D *v3d; - ARegion *region; - RegionView3D *rv3d; - static int perspo = RV3D_PERSP; - int viewnum; - int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - /* no NULL check is needed, poll checks */ - ED_view3d_context_user_region(C, &v3d, ®ion); - rv3d = region->regiondata; - - ED_view3d_smooth_view_force_finish(C, v3d, region); - - viewnum = RNA_enum_get(op->ptr, "type"); - - float align_quat_buf[4]; - float *align_quat = NULL; - - if (RNA_boolean_get(op->ptr, "align_active")) { - /* align to active object */ - Object *obact = CTX_data_active_object(C); - if (obact != NULL) { - float twmat[3][3]; - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - /* same as transform gizmo when normal is set */ - ED_getTransformOrientationMatrix(view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat); - align_quat = align_quat_buf; - mat3_to_quat(align_quat, twmat); - invert_qt_normalized(align_quat); - } - } - - if (RNA_boolean_get(op->ptr, "relative")) { - float quat_rotate[4]; - float quat_test[4]; - - if (viewnum == RV3D_VIEW_LEFT) { - axis_angle_to_quat(quat_rotate, rv3d->viewinv[1], -M_PI / 2.0f); - } - else if (viewnum == RV3D_VIEW_RIGHT) { - axis_angle_to_quat(quat_rotate, rv3d->viewinv[1], M_PI / 2.0f); - } - else if (viewnum == RV3D_VIEW_TOP) { - axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], -M_PI / 2.0f); - } - else if (viewnum == RV3D_VIEW_BOTTOM) { - axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], M_PI / 2.0f); - } - else if (viewnum == RV3D_VIEW_FRONT) { - unit_qt(quat_rotate); - } - else if (viewnum == RV3D_VIEW_BACK) { - axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], M_PI); - } - else { - BLI_assert(0); - } - - mul_qt_qtqt(quat_test, rv3d->viewquat, quat_rotate); - - float angle_best = FLT_MAX; - int view_best = -1; - int view_axis_roll_best = -1; - for (int i = RV3D_VIEW_FRONT; i <= RV3D_VIEW_BOTTOM; i++) { - for (int j = RV3D_VIEW_AXIS_ROLL_0; j <= RV3D_VIEW_AXIS_ROLL_270; j++) { - float quat_axis[4]; - ED_view3d_quat_from_axis_view(i, j, quat_axis); - if (align_quat) { - mul_qt_qtqt(quat_axis, quat_axis, align_quat); - } - const float angle_test = fabsf(angle_signed_qtqt(quat_axis, quat_test)); - if (angle_best > angle_test) { - angle_best = angle_test; - view_best = i; - view_axis_roll_best = j; - } - } - } - if (view_best == -1) { - view_best = RV3D_VIEW_FRONT; - view_axis_roll_best = RV3D_VIEW_AXIS_ROLL_0; - } - - /* Disallow non-upright views in turn-table modes, - * it's too difficult to navigate out of them. */ - if ((U.flag & USER_TRACKBALL) == 0) { - if (!ELEM(view_best, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { - view_axis_roll_best = RV3D_VIEW_AXIS_ROLL_0; - } - } - - viewnum = view_best; - view_axis_roll = view_axis_roll_best; - } - - /* Use this to test if we started out with a camera */ - const int nextperspo = (rv3d->persp == RV3D_CAMOB) ? rv3d->lpersp : perspo; - float quat[4]; - ED_view3d_quat_from_axis_view(viewnum, view_axis_roll, quat); - axis_set_view( - C, v3d, region, quat, viewnum, view_axis_roll, nextperspo, align_quat, smooth_viewtx); - - perspo = rv3d->persp; - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_view_axis(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "View Axis"; - ot->description = "Use a preset viewpoint"; - ot->idname = "VIEW3D_OT_view_axis"; - - /* api callbacks */ - ot->exec = view_axis_exec; - ot->poll = ED_operator_rv3d_user_region_poll; - - /* flags */ - ot->flag = 0; - - ot->prop = RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "Preset viewpoint to use"); - RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean( - ot->srna, "align_active", 0, "Align Active", "Align to the active object's axis"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean( - ot->srna, "relative", 0, "Relative", "Rotate relative to the current orientation"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Camera Operator - * \{ */ - -static int view_camera_exec(bContext *C, wmOperator *op) -{ - View3D *v3d; - ARegion *region; - RegionView3D *rv3d; - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - /* no NULL check is needed, poll checks */ - ED_view3d_context_user_region(C, &v3d, ®ion); - rv3d = region->regiondata; - - ED_view3d_smooth_view_force_finish(C, v3d, region); - - if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Scene *scene = CTX_data_scene(C); - - if (rv3d->persp != RV3D_CAMOB) { - Object *ob = OBACT(view_layer); - - if (!rv3d->smooth_timer) { - /* store settings of current view before allowing overwriting with camera view - * only if we're not currently in a view transition */ - - ED_view3d_lastview_store(rv3d); - } - - /* first get the default camera for the view lock type */ - if (v3d->scenelock) { - /* sets the camera view if available */ - v3d->camera = scene->camera; - } - else { - /* use scene camera if one is not set (even though we're unlocked) */ - if (v3d->camera == NULL) { - v3d->camera = scene->camera; - } - } - - /* if the camera isn't found, check a number of options */ - if (v3d->camera == NULL && ob && ob->type == OB_CAMERA) { - v3d->camera = ob; - } - - if (v3d->camera == NULL) { - v3d->camera = BKE_view_layer_camera_find(view_layer); - } - - /* couldn't find any useful camera, bail out */ - if (v3d->camera == NULL) { - return OPERATOR_CANCELLED; - } - - /* important these don't get out of sync for locked scenes */ - if (v3d->scenelock && scene->camera != v3d->camera) { - scene->camera = v3d->camera; - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - } - - /* finally do snazzy view zooming */ - rv3d->persp = RV3D_CAMOB; - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .camera = v3d->camera, - .ofs = rv3d->ofs, - .quat = rv3d->viewquat, - .dist = &rv3d->dist, - .lens = &v3d->lens, - }); - } - else { - /* return to settings of last view */ - /* does view3d_smooth_view too */ - axis_set_view(C, - v3d, - region, - rv3d->lviewquat, - rv3d->lview, - rv3d->lview_axis_roll, - rv3d->lpersp, - NULL, - smooth_viewtx); - } - } - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_view_camera(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "View Camera"; - ot->description = "Toggle the camera view"; - ot->idname = "VIEW3D_OT_view_camera"; - - /* api callbacks */ - ot->exec = view_camera_exec; - ot->poll = ED_operator_rv3d_user_region_poll; - - /* flags */ - ot->flag = 0; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Orbit Operator - * - * Rotate (orbit) in incremental steps. For interactive orbit see #VIEW3D_OT_rotate. - * \{ */ - -enum { - V3D_VIEW_STEPLEFT = 1, - V3D_VIEW_STEPRIGHT, - V3D_VIEW_STEPDOWN, - V3D_VIEW_STEPUP, -}; - -static const EnumPropertyItem prop_view_orbit_items[] = { - {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the left"}, - {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the right"}, - {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view up"}, - {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view down"}, - {0, NULL, 0, NULL, NULL}, -}; - -static int vieworbit_exec(bContext *C, wmOperator *op) -{ - View3D *v3d; - ARegion *region; - RegionView3D *rv3d; - int orbitdir; - char view_opposite; - PropertyRNA *prop_angle = RNA_struct_find_property(op->ptr, "angle"); - float angle = RNA_property_is_set(op->ptr, prop_angle) ? - RNA_property_float_get(op->ptr, prop_angle) : - DEG2RADF(U.pad_rot_angle); - - /* no NULL check is needed, poll checks */ - v3d = CTX_wm_view3d(C); - region = CTX_wm_region(C); - rv3d = region->regiondata; - - /* support for switching to the opposite view (even when in locked views) */ - view_opposite = (fabsf(angle) == (float)M_PI) ? ED_view3d_axis_view_opposite(rv3d->view) : - RV3D_VIEW_USER; - orbitdir = RNA_enum_get(op->ptr, "type"); - - if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) && (view_opposite == RV3D_VIEW_USER)) { - /* no NULL check is needed, poll checks */ - ED_view3d_context_user_region(C, &v3d, ®ion); - rv3d = region->regiondata; - } - - ED_view3d_smooth_view_force_finish(C, v3d, region); - - if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0 || (view_opposite != RV3D_VIEW_USER)) { - if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { - int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - float quat_mul[4]; - float quat_new[4]; - - if (view_opposite == RV3D_VIEW_USER) { - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ED_view3d_persp_ensure(depsgraph, v3d, region); - } - - if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) { - if (orbitdir == V3D_VIEW_STEPRIGHT) { - angle = -angle; - } - - /* z-axis */ - axis_angle_to_quat_single(quat_mul, 'Z', angle); - } - else { - - if (orbitdir == V3D_VIEW_STEPDOWN) { - angle = -angle; - } - - /* horizontal axis */ - axis_angle_to_quat(quat_mul, rv3d->viewinv[0], angle); - } - - mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul); - - /* avoid precision loss over time */ - normalize_qt(quat_new); - - if (view_opposite != RV3D_VIEW_USER) { - rv3d->view = view_opposite; - /* avoid float in-precision, just get a new orientation */ - ED_view3d_quat_from_axis_view(view_opposite, rv3d->view_axis_roll, quat_new); - } - else { - rv3d->view = RV3D_VIEW_USER; - } - - float dyn_ofs[3], *dyn_ofs_pt = NULL; - - if (U.uiflag & USER_ORBIT_SELECTION) { - if (view3d_orbit_calc_center(C, dyn_ofs)) { - negate_v3(dyn_ofs); - dyn_ofs_pt = dyn_ofs; - } - } - - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .quat = quat_new, - .dyn_ofs = dyn_ofs_pt, - }); - - return OPERATOR_FINISHED; - } - } - - return OPERATOR_CANCELLED; -} - -void VIEW3D_OT_view_orbit(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "View Orbit"; - ot->description = "Orbit the view"; - ot->idname = "VIEW3D_OT_view_orbit"; - - /* api callbacks */ - ot->exec = vieworbit_exec; - ot->poll = ED_operator_rv3d_user_region_poll; - - /* flags */ - ot->flag = 0; - - /* properties */ - prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - ot->prop = RNA_def_enum( - ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit"); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Roll Operator - * \{ */ - -static void view_roll_angle( - ARegion *region, float quat[4], const float orig_quat[4], const float dvec[3], float angle) -{ - RegionView3D *rv3d = region->regiondata; - float quat_mul[4]; - - /* camera axis */ - axis_angle_normalized_to_quat(quat_mul, dvec, angle); - - mul_qt_qtqt(quat, orig_quat, quat_mul); - - /* avoid precision loss over time */ - normalize_qt(quat); - - rv3d->view = RV3D_VIEW_USER; -} - -static void viewroll_apply(ViewOpsData *vod, int x, int y) -{ - float angle = BLI_dial_angle(vod->init.dial, (const float[2]){x, y}); - - if (angle != 0.0f) { - view_roll_angle(vod->region, vod->rv3d->viewquat, vod->init.quat, vod->init.mousevec, angle); - } - - if (vod->use_dyn_ofs) { - view3d_orbit_apply_dyn_ofs( - vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs); - } - - if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { - view3d_boxview_sync(vod->area, vod->region); - } - - ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); - - ED_region_tag_redraw(vod->region); -} - -static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod = op->customdata; - short event_code = VIEW_PASS; - bool use_autokey = false; - int ret = OPERATOR_RUNNING_MODAL; - - /* execute the events */ - if (event->type == MOUSEMOVE) { - event_code = VIEW_APPLY; - } - else if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case VIEW_MODAL_CONFIRM: - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_MOVE: - WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - case VIEWROT_MODAL_SWITCH_ROTATE: - WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); - event_code = VIEW_CONFIRM; - break; - } - } - else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) { - /* Note this does not remove auto-keys on locked cameras. */ - copy_qt_qt(vod->rv3d->viewquat, vod->init.quat); - ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); - viewops_data_free(C, op); - return OPERATOR_CANCELLED; - } - else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { - event_code = VIEW_CONFIRM; - } - - if (event_code == VIEW_APPLY) { - viewroll_apply(vod, event->xy[0], event->xy[1]); - if (ED_screen_animation_playing(CTX_wm_manager(C))) { - use_autokey = true; - } - } - else if (event_code == VIEW_CONFIRM) { - use_autokey = true; - ret = OPERATOR_FINISHED; - } - - if (use_autokey) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false); - } - - if (ret & OPERATOR_FINISHED) { - viewops_data_free(C, op); - } - - return ret; -} - -static const EnumPropertyItem prop_view_roll_items[] = { - {0, "ANGLE", 0, "Roll Angle", "Roll the view using an angle value"}, - {V3D_VIEW_STEPLEFT, "LEFT", 0, "Roll Left", "Roll the view around to the left"}, - {V3D_VIEW_STEPRIGHT, "RIGHT", 0, "Roll Right", "Roll the view around to the right"}, - {0, NULL, 0, NULL, NULL}, -}; - -static int viewroll_exec(bContext *C, wmOperator *op) -{ - View3D *v3d; - RegionView3D *rv3d; - ARegion *region; - - if (op->customdata) { - ViewOpsData *vod = op->customdata; - region = vod->region; - v3d = vod->v3d; - } - else { - ED_view3d_context_user_region(C, &v3d, ®ion); - } - - rv3d = region->regiondata; - if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { - - ED_view3d_smooth_view_force_finish(C, v3d, region); - - int type = RNA_enum_get(op->ptr, "type"); - float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF(U.pad_rot_angle); - float mousevec[3]; - float quat_new[4]; - - const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - - if (type == V3D_VIEW_STEPLEFT) { - angle = -angle; - } - - normalize_v3_v3(mousevec, rv3d->viewinv[2]); - negate_v3(mousevec); - view_roll_angle(region, quat_new, rv3d->viewquat, mousevec, angle); - - const float *dyn_ofs_pt = NULL; - float dyn_ofs[3]; - if (U.uiflag & USER_ORBIT_SELECTION) { - if (view3d_orbit_calc_center(C, dyn_ofs)) { - negate_v3(dyn_ofs); - dyn_ofs_pt = dyn_ofs; - } - } - - ED_view3d_smooth_view(C, - v3d, - region, - smooth_viewtx, - &(const V3D_SmoothParams){ - .quat = quat_new, - .dyn_ofs = dyn_ofs_pt, - }); - - viewops_data_free(C, op); - return OPERATOR_FINISHED; - } - - viewops_data_free(C, op); - return OPERATOR_CANCELLED; -} - -static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ViewOpsData *vod; - - bool use_angle = RNA_enum_get(op->ptr, "type") != 0; - - if (use_angle || RNA_struct_property_is_set(op->ptr, "angle")) { - viewroll_exec(C, op); - } - else { - /* makes op->customdata */ - viewops_data_alloc(C, op); - viewops_data_create(C, op, event, viewops_flag_from_prefs()); - vod = op->customdata; - vod->init.dial = BLI_dial_init((const float[2]){BLI_rcti_cent_x(&vod->region->winrct), - BLI_rcti_cent_y(&vod->region->winrct)}, - FLT_EPSILON); - - ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); - - /* overwrite the mouse vector with the view direction */ - normalize_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); - negate_v3(vod->init.mousevec); - - if (event->type == MOUSEROTATE) { - vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0]; - viewroll_apply(vod, event->prev_xy[0], event->prev_xy[1]); - - viewops_data_free(C, op); - return OPERATOR_FINISHED; - } - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; - } - return OPERATOR_FINISHED; -} - -static void viewroll_cancel(bContext *C, wmOperator *op) -{ - viewops_data_free(C, op); -} - -void VIEW3D_OT_view_roll(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "View Roll"; - ot->description = "Roll the view"; - ot->idname = "VIEW3D_OT_view_roll"; - - /* api callbacks */ - ot->invoke = viewroll_invoke; - ot->exec = viewroll_exec; - ot->modal = viewroll_modal; - ot->poll = ED_operator_rv3d_user_region_poll; - ot->cancel = viewroll_cancel; - - /* flags */ - ot->flag = 0; - - /* properties */ - ot->prop = prop = RNA_def_float( - ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_enum(ot->srna, - "type", - prop_view_roll_items, - 0, - "Roll Angle Source", - "How roll angle is calculated"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); -} - -enum { - V3D_VIEW_PANLEFT = 1, - V3D_VIEW_PANRIGHT, - V3D_VIEW_PANDOWN, - V3D_VIEW_PANUP, -}; - -static const EnumPropertyItem prop_view_pan_items[] = { - {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the left"}, - {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the right"}, - {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view up"}, - {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view down"}, - {0, NULL, 0, NULL, NULL}, -}; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name View Pan Operator - * - * Move (pan) in incremental steps. For interactive pan see #VIEW3D_OT_move. - * \{ */ - -static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - int x = 0, y = 0; - int pandir = RNA_enum_get(op->ptr, "type"); - - if (pandir == V3D_VIEW_PANRIGHT) { - x = -32; - } - else if (pandir == V3D_VIEW_PANLEFT) { - x = 32; - } - else if (pandir == V3D_VIEW_PANUP) { - y = -25; - } - else if (pandir == V3D_VIEW_PANDOWN) { - y = 25; - } - - viewops_data_alloc(C, op); - viewops_data_create(C, op, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT)); - ViewOpsData *vod = op->customdata; - - viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_view_pan(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Pan View Direction"; - ot->description = "Pan the view in a given direction"; - ot->idname = "VIEW3D_OT_view_pan"; - - /* api callbacks */ - ot->invoke = viewpan_invoke; - ot->poll = view3d_pan_poll; - - /* flags */ - ot->flag = 0; - - /* Properties */ - ot->prop = RNA_def_enum( - ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan"); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name View Toggle Perspective/Orthographic Operator * \{ */ diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 607ca110d0f..7f872c9b1af 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -52,8 +52,6 @@ #include "view3d_intern.h" -static void do_view3d_header_buttons(bContext *C, void *arg, int event); - #define B_SEL_VERT 110 #define B_SEL_EDGE 111 #define B_SEL_FACE 112 @@ -98,101 +96,45 @@ void VIEW3D_OT_toggle_matcap_flip(wmOperatorType *ot) /** \name UI Templates * \{ */ -static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) -{ - wmWindow *win = CTX_wm_window(C); - const int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift; - - /* watch it: if area->win does not exist, check that when calling direct drawing routines */ - - switch (event) { - case B_SEL_VERT: - if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_VERTEX, -1, shift, ctrl)) { - ED_undo_push(C, "Selectmode Set: Vertex"); - } - break; - case B_SEL_EDGE: - if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_EDGE, -1, shift, ctrl)) { - ED_undo_push(C, "Selectmode Set: Edge"); - } - break; - case B_SEL_FACE: - if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_FACE, -1, shift, ctrl)) { - ED_undo_push(C, "Selectmode Set: Face"); - } - break; - default: - break; - } -} - void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C) { Object *obedit = CTX_data_edit_object(C); - uiBlock *block = uiLayoutGetBlock(layout); - - UI_block_func_handle_set(block, do_view3d_header_buttons, NULL); - - if (obedit && (obedit->type == OB_MESH)) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - uiLayout *row; - uiBut *but; - - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - but = uiDefIconButBitS( - block, - UI_BTYPE_TOGGLE, - SCE_SELECT_VERTEX, - B_SEL_VERT, - ICON_VERTEXSEL, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - &em->selectmode, - 1.0, - 0.0, - 0, - 0, - TIP_("Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection")); - UI_but_flag_disable(but, UI_BUT_UNDO); - but = uiDefIconButBitS( - block, - UI_BTYPE_TOGGLE, - SCE_SELECT_EDGE, - B_SEL_EDGE, - ICON_EDGESEL, - 0, - 0, - ceilf(UI_UNIT_X - U.pixelsize), - UI_UNIT_Y, - &em->selectmode, - 1.0, - 0.0, - 0, - 0, - TIP_("Edge select - Shift-Click for multiple modes, " - "Ctrl-Click expands/contracts selection depending on the current mode")); - UI_but_flag_disable(but, UI_BUT_UNDO); - but = uiDefIconButBitS( - block, - UI_BTYPE_TOGGLE, - SCE_SELECT_FACE, - B_SEL_FACE, - ICON_FACESEL, - 0, - 0, - ceilf(UI_UNIT_X - U.pixelsize), - UI_UNIT_Y, - &em->selectmode, - 1.0, - 0.0, - 0, - 0, - TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection")); - UI_but_flag_disable(but, UI_BUT_UNDO); + if (!obedit || obedit->type != OB_MESH) { + return; } + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + uiLayout *row = uiLayoutRow(layout, true); + + PointerRNA op_ptr; + wmOperatorType *ot = WM_operatortype_find("MESH_OT_select_mode", true); + uiItemFullO_ptr(row, + ot, + "", + ICON_VERTEXSEL, + NULL, + WM_OP_INVOKE_DEFAULT, + (em->selectmode & SCE_SELECT_VERTEX) ? UI_ITEM_O_DEPRESS : 0, + &op_ptr); + RNA_enum_set(&op_ptr, "type", SCE_SELECT_VERTEX); + uiItemFullO_ptr(row, + ot, + "", + ICON_EDGESEL, + NULL, + WM_OP_INVOKE_DEFAULT, + (em->selectmode & SCE_SELECT_EDGE) ? UI_ITEM_O_DEPRESS : 0, + &op_ptr); + RNA_enum_set(&op_ptr, "type", SCE_SELECT_EDGE); + uiItemFullO_ptr(row, + ot, + "", + ICON_FACESEL, + NULL, + WM_OP_INVOKE_DEFAULT, + (em->selectmode & SCE_SELECT_FACE) ? UI_ITEM_O_DEPRESS : 0, + &op_ptr); + RNA_enum_set(&op_ptr, "type", SCE_SELECT_FACE); } static void uiTemplatePaintModeSelection(uiLayout *layout, struct bContext *C) diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 6a1a09df316..b443ebeed94 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -32,6 +32,8 @@ struct ARegionType; struct BoundBox; struct Depsgraph; struct Object; +struct Scene; +struct ViewContext; struct ViewLayer; struct bContext; struct wmGizmoGroupType; @@ -40,13 +42,6 @@ struct wmKeyConfig; struct wmOperatorType; struct wmWindowManager; -/* drawing flags: */ -enum { - DRAW_PICKING = (1 << 0), - DRAW_CONSTCOLOR = (1 << 1), - DRAW_SCENESET = (1 << 2), -}; - /* view3d_header.c */ void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot); @@ -54,84 +49,24 @@ void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot); void view3d_operatortypes(void); /* view3d_edit.c */ -void VIEW3D_OT_zoom(struct wmOperatorType *ot); -void VIEW3D_OT_dolly(struct wmOperatorType *ot); void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot); -void VIEW3D_OT_move(struct wmOperatorType *ot); -void VIEW3D_OT_rotate(struct wmOperatorType *ot); -#ifdef WITH_INPUT_NDOF -void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot); -void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot); -void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot); -void VIEW3D_OT_ndof_all(struct wmOperatorType *ot); -#endif /* WITH_INPUT_NDOF */ -void VIEW3D_OT_view_all(struct wmOperatorType *ot); -void VIEW3D_OT_view_axis(struct wmOperatorType *ot); -void VIEW3D_OT_view_camera(struct wmOperatorType *ot); -void VIEW3D_OT_view_selected(struct wmOperatorType *ot); void VIEW3D_OT_view_lock_clear(struct wmOperatorType *ot); void VIEW3D_OT_view_lock_to_active(struct wmOperatorType *ot); -void VIEW3D_OT_view_center_cursor(struct wmOperatorType *ot); -void VIEW3D_OT_view_center_pick(struct wmOperatorType *ot); void VIEW3D_OT_view_center_camera(struct wmOperatorType *ot); void VIEW3D_OT_view_center_lock(struct wmOperatorType *ot); -void VIEW3D_OT_view_pan(struct wmOperatorType *ot); void VIEW3D_OT_view_persportho(struct wmOperatorType *ot); void VIEW3D_OT_navigate(struct wmOperatorType *ot); void VIEW3D_OT_background_image_add(struct wmOperatorType *ot); void VIEW3D_OT_background_image_remove(struct wmOperatorType *ot); void VIEW3D_OT_drop_world(struct wmOperatorType *ot); -void VIEW3D_OT_view_orbit(struct wmOperatorType *ot); -void VIEW3D_OT_view_roll(struct wmOperatorType *ot); void VIEW3D_OT_clip_border(struct wmOperatorType *ot); void VIEW3D_OT_cursor3d(struct wmOperatorType *ot); void VIEW3D_OT_render_border(struct wmOperatorType *ot); void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot); -void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot); void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot); -/** - * For home, center etc. - */ -void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region); -/** - * Sync center/zoom view of region to others, for view transforms. - */ -void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region); - -void view3d_orbit_apply_dyn_ofs(float r_ofs[3], - const float ofs_old[3], - const float viewquat_old[4], - const float viewquat_new[4], - const float dyn_ofs[3]); - -#ifdef WITH_INPUT_NDOF -struct wmNDOFMotionData; - -/** - * Called from both fly mode and walk mode, - */ -void view3d_ndof_fly(const struct wmNDOFMotionData *ndof, - struct View3D *v3d, - struct RegionView3D *rv3d, - bool use_precision, - short protectflag, - bool *r_has_translate, - bool *r_has_rotate); -#endif /* WITH_INPUT_NDOF */ - -/* view3d_navigate_fly.c */ - -void view3d_keymap(struct wmKeyConfig *keyconf); -void VIEW3D_OT_fly(struct wmOperatorType *ot); - -/* view3d_navigate_walk.c */ - -void VIEW3D_OT_walk(struct wmOperatorType *ot); - /* view3d_draw.c */ - void view3d_main_region_draw(const struct bContext *C, struct ARegion *region); /** * Information drawn on top of the solid plates and composed data. @@ -141,16 +76,16 @@ void view3d_draw_region_info(const struct bContext *C, struct ARegion *region); /* view3d_draw_legacy.c */ void ED_view3d_draw_select_loop(struct Depsgraph *depsgraph, - ViewContext *vc, - Scene *scene, + struct ViewContext *vc, + struct Scene *scene, struct ViewLayer *view_layer, - View3D *v3d, + struct View3D *v3d, struct ARegion *region, bool use_obedit_skip, bool use_nearest); void ED_view3d_draw_depth_loop(struct Depsgraph *depsgraph, - Scene *scene, + struct Scene *scene, struct ARegion *region, View3D *v3d); @@ -168,57 +103,27 @@ void VIEW3D_OT_select_lasso(struct wmOperatorType *ot); void VIEW3D_OT_select_menu(struct wmOperatorType *ot); void VIEW3D_OT_bone_select_menu(struct wmOperatorType *ot); -/* view3d_view.c */ -void VIEW3D_OT_smoothview(struct wmOperatorType *ot); -void VIEW3D_OT_camera_to_view(struct wmOperatorType *ot); -void VIEW3D_OT_camera_to_view_selected(struct wmOperatorType *ot); -void VIEW3D_OT_object_as_camera(struct wmOperatorType *ot); -void VIEW3D_OT_localview(struct wmOperatorType *ot); -void VIEW3D_OT_localview_remove_from(struct wmOperatorType *ot); +/* view3d_utils.c */ +/** + * For home, center etc. + */ +void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region); +/** + * Sync center/zoom view of region to others, for view transforms. + */ +void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region); bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]); bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb); -/** - * Parameters for setting the new 3D Viewport state. - * - * Each of the struct members may be NULL to signify they aren't to be adjusted. - */ -typedef struct V3D_SmoothParams { - struct Object *camera_old, *camera; - const float *ofs, *quat, *dist, *lens; - - /** Alternate rotation center, when set `ofs` must be NULL. */ - const float *dyn_ofs; -} V3D_SmoothParams; - -/** - * The arguments are the desired situation. - */ -void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph, - struct wmWindowManager *wm, - struct wmWindow *win, - struct ScrArea *area, - struct View3D *v3d, - struct ARegion *region, - int smooth_viewtx, - const V3D_SmoothParams *sview); - -void ED_view3d_smooth_view(struct bContext *C, - struct View3D *v3d, - struct ARegion *region, - int smooth_viewtx, - const V3D_SmoothParams *sview); - -/** - * Apply the smooth-view immediately, use when we need to start a new view operation. - * (so we don't end up half-applying a view operation when pressing keys quickly). - */ -void ED_view3d_smooth_view_force_finish(struct bContext *C, - struct View3D *v3d, - struct ARegion *region); +/* view3d_view.c */ +void VIEW3D_OT_camera_to_view(struct wmOperatorType *ot); +void VIEW3D_OT_camera_to_view_selected(struct wmOperatorType *ot); +void VIEW3D_OT_object_as_camera(struct wmOperatorType *ot); +void VIEW3D_OT_localview(struct wmOperatorType *ot); +void VIEW3D_OT_localview_remove_from(struct wmOperatorType *ot); /** * \param rect: optional for picking (can be NULL). @@ -247,12 +152,7 @@ void view3d_viewmatrix_set(struct Depsgraph *depsgraph, /* Called in transform_ops.c, on each regeneration of key-maps. */ -void fly_modal_keymap(struct wmKeyConfig *keyconf); -void walk_modal_keymap(struct wmKeyConfig *keyconf); -void viewrotate_modal_keymap(struct wmKeyConfig *keyconf); -void viewmove_modal_keymap(struct wmKeyConfig *keyconf); -void viewzoom_modal_keymap(struct wmKeyConfig *keyconf); -void viewdolly_modal_keymap(struct wmKeyConfig *keyconf); +/* view3d_placement.c */ void viewplace_modal_keymap(struct wmKeyConfig *keyconf); /* view3d_buttons.c */ @@ -267,7 +167,7 @@ void view3d_buttons_register(struct ARegionType *art); * the view for first-person style navigation. */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(struct Depsgraph *depsgraph, - Scene *scene, + struct Scene *scene, View3D *v3d, RegionView3D *rv3d); /** diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c new file mode 100644 index 00000000000..98eef94d5fb --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate.c @@ -0,0 +1,1593 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "DNA_curve_types.h" +#include "DNA_gpencil_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_rect.h" + +#include "BKE_armature.h" +#include "BKE_context.h" +#include "BKE_gpencil_geom.h" +#include "BKE_layer.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_vfont.h" + +#include "DEG_depsgraph_query.h" + +#include "ED_mesh.h" +#include "ED_particle.h" +#include "ED_screen.h" +#include "ED_transform.h" + +#include "WM_api.h" +#include "WM_message.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_resources.h" + +#include "view3d_intern.h" + +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Navigation Polls + * \{ */ + +static bool view3d_navigation_poll_impl(bContext *C, const char viewlock) +{ + if (!ED_operator_region_view3d_active(C)) { + return false; + } + + const RegionView3D *rv3d = CTX_wm_region_view3d(C); + return !(RV3D_LOCK_FLAGS(rv3d) & viewlock); +} + +bool view3d_location_poll(bContext *C) +{ + return view3d_navigation_poll_impl(C, RV3D_LOCK_LOCATION); +} + +bool view3d_rotation_poll(bContext *C) +{ + return view3d_navigation_poll_impl(C, RV3D_LOCK_ROTATION); +} + +bool view3d_zoom_or_dolly_poll(bContext *C) +{ + return view3d_navigation_poll_impl(C, RV3D_LOCK_ZOOM_AND_DOLLY); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Properties + * \{ */ + +void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag) +{ + if (flag & V3D_OP_PROP_MOUSE_CO) { + PropertyRNA *prop; + prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + } + if (flag & V3D_OP_PROP_DELTA) { + RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); + } + if (flag & V3D_OP_PROP_USE_ALL_REGIONS) { + PropertyRNA *prop; + prop = RNA_def_boolean( + ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + } + if (flag & V3D_OP_PROP_USE_MOUSE_INIT) { + WM_operator_properties_use_cursor_init(ot); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Custom-Data + * \{ */ + +void calctrackballvec(const rcti *rect, const int event_xy[2], float r_dir[3]) +{ + const float radius = V3D_OP_TRACKBALLSIZE; + const float t = radius / (float)M_SQRT2; + const float size[2] = {BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)}; + /* Aspect correct so dragging in a non-square view doesn't squash the direction. + * So diagonal motion rotates the same direction the cursor is moving. */ + const float size_min = min_ff(size[0], size[1]); + const float aspect[2] = {size_min / size[0], size_min / size[1]}; + + /* Normalize x and y. */ + r_dir[0] = (event_xy[0] - BLI_rcti_cent_x(rect)) / ((size[0] * aspect[0]) / 2.0); + r_dir[1] = (event_xy[1] - BLI_rcti_cent_y(rect)) / ((size[1] * aspect[1]) / 2.0); + const float d = len_v2(r_dir); + if (d < t) { + /* Inside sphere. */ + r_dir[2] = sqrtf(square_f(radius) - square_f(d)); + } + else { + /* On hyperbola. */ + r_dir[2] = square_f(t) / d; + } +} + +void view3d_orbit_apply_dyn_ofs(float r_ofs[3], + const float ofs_old[3], + const float viewquat_old[4], + const float viewquat_new[4], + const float dyn_ofs[3]) +{ + float q[4]; + invert_qt_qt_normalized(q, viewquat_old); + mul_qt_qtqt(q, q, viewquat_new); + + invert_qt_normalized(q); + + sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs); + mul_qt_v3(q, r_ofs); + add_v3_v3(r_ofs, dyn_ofs); +} + +void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4]) +{ + if (vod->use_dyn_ofs) { + RegionView3D *rv3d = vod->rv3d; + view3d_orbit_apply_dyn_ofs( + rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs); + } +} + +bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) +{ + static float lastofs[3] = {0, 0, 0}; + bool is_set = false; + + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); + View3D *v3d = CTX_wm_view3d(C); + Object *ob_act_eval = OBACT(view_layer_eval); + Object *ob_act = DEG_get_original_object(ob_act_eval); + + if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) && + /* with weight-paint + pose-mode, fall through to using calculateTransformCenter */ + ((ob_act->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob_act)) == 0) { + /* in case of sculpting use last average stroke position as a rotation + * center, in other cases it's not clear what rotation center shall be + * so just rotate around object origin + */ + if (ob_act->mode & + (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { + float stroke[3]; + BKE_paint_stroke_get_average(scene, ob_act_eval, stroke); + copy_v3_v3(lastofs, stroke); + } + else { + copy_v3_v3(lastofs, ob_act_eval->obmat[3]); + } + is_set = true; + } + else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) { + Curve *cu = ob_act_eval->data; + EditFont *ef = cu->editfont; + + zero_v3(lastofs); + for (int i = 0; i < 4; i++) { + add_v2_v2(lastofs, ef->textcurs[i]); + } + mul_v2_fl(lastofs, 1.0f / 4.0f); + + mul_m4_v3(ob_act_eval->obmat, lastofs); + + is_set = true; + } + else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) { + /* object mode use boundbox centers */ + Base *base_eval; + uint tot = 0; + float select_center[3]; + + zero_v3(select_center); + for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) { + if (BASE_SELECTED(v3d, base_eval)) { + /* use the boundbox if we can */ + Object *ob_eval = base_eval->object; + + if (ob_eval->runtime.bb && !(ob_eval->runtime.bb->flag & BOUNDBOX_DIRTY)) { + float cent[3]; + + BKE_boundbox_calc_center_aabb(ob_eval->runtime.bb, cent); + + mul_m4_v3(ob_eval->obmat, cent); + add_v3_v3(select_center, cent); + } + else { + add_v3_v3(select_center, ob_eval->obmat[3]); + } + tot++; + } + } + if (tot) { + mul_v3_fl(select_center, 1.0f / (float)tot); + copy_v3_v3(lastofs, select_center); + is_set = true; + } + } + else { + /* If there's no selection, `lastofs` is unmodified and last value since static. */ + is_set = calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, lastofs, NULL); + } + + copy_v3_v3(r_dyn_ofs, lastofs); + + return is_set; +} + +static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth) +{ + enum eViewOpsFlag flag = 0; + if (use_select) { + flag |= VIEWOPS_FLAG_ORBIT_SELECT; + } + if (use_depth) { + flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE; + } + + return flag; +} + +enum eViewOpsFlag viewops_flag_from_prefs(void) +{ + return viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, + (U.uiflag & USER_DEPTH_NAVIGATE) != 0); +} + +ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOpsFlag viewops_flag) +{ + ViewOpsData *vod = MEM_callocN(sizeof(ViewOpsData), __func__); + + /* Store data. */ + vod->bmain = CTX_data_main(C); + vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + vod->scene = CTX_data_scene(C); + vod->area = CTX_wm_area(C); + vod->region = CTX_wm_region(C); + vod->v3d = vod->area->spacedata.first; + vod->rv3d = vod->region->regiondata; + + Depsgraph *depsgraph = vod->depsgraph; + RegionView3D *rv3d = vod->rv3d; + + /* Could do this more nicely. */ + if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) { + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; + } + + /* we need the depth info before changing any viewport options */ + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { + float fallback_depth_pt[3]; + + view3d_operator_needs_opengl(C); /* Needed for Z-buffer drawing. */ + + negate_v3_v3(fallback_depth_pt, rv3d->ofs); + + vod->use_dyn_ofs = ED_view3d_autodist( + depsgraph, vod->region, vod->v3d, event->mval, vod->dyn_ofs, true, fallback_depth_pt); + } + else { + vod->use_dyn_ofs = false; + } + + if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) { + if (ED_view3d_persp_ensure(depsgraph, vod->v3d, vod->region)) { + /* If we're switching from camera view to the perspective one, + * need to tag viewport update, so camera view and borders are properly updated. */ + ED_region_tag_redraw(vod->region); + } + } + + /* set the view from the camera, if view locking is enabled. + * we may want to make this optional but for now its needed always */ + ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d); + + vod->init.persp = rv3d->persp; + vod->init.dist = rv3d->dist; + vod->init.camzoom = rv3d->camzoom; + copy_qt_qt(vod->init.quat, rv3d->viewquat); + copy_v2_v2_int(vod->init.event_xy, event->xy); + copy_v2_v2_int(vod->prev.event_xy, event->xy); + + if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) { + zero_v2_int(vod->init.event_xy_offset); + } + else { + /* Simulate the event starting in the middle of the region. */ + vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->region->winrct) - event->xy[0]; + vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->region->winrct) - event->xy[1]; + } + + vod->init.event_type = event->type; + copy_v3_v3(vod->init.ofs, rv3d->ofs); + + copy_qt_qt(vod->curr.viewquat, rv3d->viewquat); + + if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) { + float ofs[3]; + if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) { + vod->use_dyn_ofs = true; + negate_v3_v3(vod->dyn_ofs, ofs); + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; + } + } + + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { + if (vod->use_dyn_ofs) { + if (rv3d->is_persp) { + float my_origin[3]; /* Original #RegionView3D.ofs. */ + float my_pivot[3]; /* View pivot. */ + float dvec[3]; + + /* locals for dist correction */ + float mat[3][3]; + float upvec[3]; + + negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */ + + /* Set the dist value to be the distance from this 3d point this means you'll + * always be able to zoom into it and panning won't go bad when dist was zero. */ + + /* remove dist value */ + upvec[0] = upvec[1] = 0; + upvec[2] = rv3d->dist; + copy_m3_m4(mat, rv3d->viewinv); + + mul_m3_v3(mat, upvec); + sub_v3_v3v3(my_pivot, rv3d->ofs, upvec); + negate_v3(my_pivot); /* ofs is flipped */ + + /* find a new ofs value that is along the view axis + * (rather than the mouse location) */ + closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin); + vod->init.dist = rv3d->dist = len_v3v3(my_pivot, dvec); + + negate_v3_v3(rv3d->ofs, dvec); + } + else { + const float mval_region_mid[2] = {(float)vod->region->winx / 2.0f, + (float)vod->region->winy / 2.0f}; + + ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_region_mid, rv3d->ofs); + negate_v3(rv3d->ofs); + } + negate_v3(vod->dyn_ofs); + copy_v3_v3(vod->init.ofs, rv3d->ofs); + } + } + + /* For dolly */ + ED_view3d_win_to_vector(vod->region, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec); + + { + int event_xy_offset[2]; + add_v2_v2v2_int(event_xy_offset, event->xy, vod->init.event_xy_offset); + + /* For rotation with trackball rotation. */ + calctrackballvec(&vod->region->winrct, event_xy_offset, vod->init.trackvec); + } + + { + float tvec[3]; + negate_v3_v3(tvec, rv3d->ofs); + vod->init.zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); + } + + vod->reverse = 1.0f; + if (rv3d->persmat[2][1] < 0.0f) { + vod->reverse = -1.0f; + } + + rv3d->rflag |= RV3D_NAVIGATING; + + return vod; +} + +void viewops_data_free(bContext *C, ViewOpsData *vod) +{ + ARegion *region; + if (vod) { + region = vod->region; + vod->rv3d->rflag &= ~RV3D_NAVIGATING; + + if (vod->timer) { + WM_event_remove_timer(CTX_wm_manager(C), vod->timer->win, vod->timer); + } + + if (vod->init.dial) { + MEM_freeN(vod->init.dial); + } + + MEM_freeN(vod); + } + else { + region = CTX_wm_region(C); + } + + /* Need to redraw because drawing code uses RV3D_NAVIGATING to draw + * faster while navigation operator runs. */ + ED_region_tag_redraw(region); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Utilities + * \{ */ + +/** + * \param align_to_quat: When not NULL, set the axis relative to this rotation. + */ +static void axis_set_view(bContext *C, + View3D *v3d, + ARegion *region, + const float quat_[4], + char view, + char view_axis_roll, + int perspo, + const float *align_to_quat, + const int smooth_viewtx) +{ + RegionView3D *rv3d = region->regiondata; /* no NULL check is needed, poll checks */ + float quat[4]; + const short orig_persp = rv3d->persp; + + normalize_qt_qt(quat, quat_); + + if (align_to_quat) { + mul_qt_qtqt(quat, quat, align_to_quat); + rv3d->view = view = RV3D_VIEW_USER; + rv3d->view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; + } + + if (align_to_quat == NULL) { + rv3d->view = view; + rv3d->view_axis_roll = view_axis_roll; + } + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) { + ED_region_tag_redraw(region); + return; + } + + if (U.uiflag & USER_AUTOPERSP) { + rv3d->persp = RV3D_VIEW_IS_AXIS(view) ? RV3D_ORTHO : perspo; + } + else if (rv3d->persp == RV3D_CAMOB) { + rv3d->persp = perspo; + } + + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + /* to camera */ + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .camera_old = v3d->camera, + .ofs = rv3d->ofs, + .quat = quat, + }); + } + else if (orig_persp == RV3D_CAMOB && v3d->camera) { + /* from camera */ + float ofs[3], dist; + + copy_v3_v3(ofs, rv3d->ofs); + dist = rv3d->dist; + + /* so we animate _from_ the camera location */ + Object *camera_eval = DEG_get_evaluated_object(CTX_data_ensure_evaluated_depsgraph(C), + v3d->camera); + ED_view3d_from_object(camera_eval, rv3d->ofs, NULL, &rv3d->dist, NULL); + + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .camera_old = camera_eval, + .ofs = ofs, + .quat = quat, + .dist = &dist, + }); + } + else { + /* rotate around selection */ + const float *dyn_ofs_pt = NULL; + float dyn_ofs[3]; + + if (U.uiflag & USER_ORBIT_SELECTION) { + if (view3d_orbit_calc_center(C, dyn_ofs)) { + negate_v3(dyn_ofs); + dyn_ofs_pt = dyn_ofs; + } + } + + /* no camera involved */ + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .quat = quat, + .dyn_ofs = dyn_ofs_pt, + }); + } +} + +void viewmove_apply(ViewOpsData *vod, int x, int y) +{ + if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) { + vod->rv3d->ofs_lock[0] -= ((vod->prev.event_xy[0] - x) * 2.0f) / (float)vod->region->winx; + vod->rv3d->ofs_lock[1] -= ((vod->prev.event_xy[1] - y) * 2.0f) / (float)vod->region->winy; + } + else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) { + const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; + vod->rv3d->camdx += (vod->prev.event_xy[0] - x) / (vod->region->winx * zoomfac); + vod->rv3d->camdy += (vod->prev.event_xy[1] - y) / (vod->region->winy * zoomfac); + CLAMP(vod->rv3d->camdx, -1.0f, 1.0f); + CLAMP(vod->rv3d->camdy, -1.0f, 1.0f); + } + else { + float dvec[3]; + float mval_f[2]; + + mval_f[0] = x - vod->prev.event_xy[0]; + mval_f[1] = y - vod->prev.event_xy[1]; + ED_view3d_win_to_delta(vod->region, mval_f, dvec, vod->init.zfac); + + add_v3_v3(vod->rv3d->ofs, dvec); + + if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(vod->area, vod->region); + } + } + + vod->prev.event_xy[0] = x; + vod->prev.event_xy[1] = y; + + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); + + ED_region_tag_redraw(vod->region); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View All Operator + * + * Move & Zoom the view to fit all of its contents. + * \{ */ + +static bool view3d_object_skip_minmax(const View3D *v3d, + const RegionView3D *rv3d, + const Object *ob, + const bool skip_camera, + bool *r_only_center) +{ + BLI_assert(ob->id.orig_id == NULL); + *r_only_center = false; + + if (skip_camera && (ob == v3d->camera)) { + return true; + } + + if ((ob->type == OB_EMPTY) && (ob->empty_drawtype == OB_EMPTY_IMAGE) && + !BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d)) { + *r_only_center = true; + return false; + } + + return false; +} + +static void view3d_object_calc_minmax(Depsgraph *depsgraph, + Scene *scene, + Object *ob_eval, + const bool only_center, + float min[3], + float max[3]) +{ + /* Account for duplis. */ + if (BKE_object_minmax_dupli(depsgraph, scene, ob_eval, min, max, false) == 0) { + /* Use if duplis aren't found. */ + if (only_center) { + minmax_v3v3_v3(min, max, ob_eval->obmat[3]); + } + else { + BKE_object_minmax(ob_eval, min, max, false); + } + } +} + +static void view3d_from_minmax(bContext *C, + View3D *v3d, + ARegion *region, + const float min[3], + const float max[3], + bool ok_dist, + const int smooth_viewtx) +{ + RegionView3D *rv3d = region->regiondata; + float afm[3]; + float size; + + ED_view3d_smooth_view_force_finish(C, v3d, region); + + /* SMOOTHVIEW */ + float new_ofs[3]; + float new_dist; + + sub_v3_v3v3(afm, max, min); + size = max_fff(afm[0], afm[1], afm[2]); + + if (ok_dist) { + char persp; + + if (rv3d->is_persp) { + if (rv3d->persp == RV3D_CAMOB && ED_view3d_camera_lock_check(v3d, rv3d)) { + persp = RV3D_CAMOB; + } + else { + persp = RV3D_PERSP; + } + } + else { /* ortho */ + if (size < 0.0001f) { + /* bounding box was a single point so do not zoom */ + ok_dist = false; + } + else { + /* adjust zoom so it looks nicer */ + persp = RV3D_ORTHO; + } + } + + if (ok_dist) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + new_dist = ED_view3d_radius_to_dist( + v3d, region, depsgraph, persp, true, (size / 2) * VIEW3D_MARGIN); + if (rv3d->is_persp) { + /* don't zoom closer than the near clipping plane */ + new_dist = max_ff(new_dist, v3d->clip_start * 1.5f); + } + } + } + + mid_v3_v3v3(new_ofs, min, max); + negate_v3(new_ofs); + + if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) { + rv3d->persp = RV3D_PERSP; + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .camera_old = v3d->camera, + .ofs = new_ofs, + .dist = ok_dist ? &new_dist : NULL, + }); + } + else { + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .ofs = new_ofs, + .dist = ok_dist ? &new_dist : NULL, + }); + } + + /* Smooth-view does view-lock #RV3D_BOXVIEW copy. */ +} + +/** + * Same as #view3d_from_minmax but for all regions (except cameras). + */ +static void view3d_from_minmax_multi(bContext *C, + View3D *v3d, + const float min[3], + const float max[3], + const bool ok_dist, + const int smooth_viewtx) +{ + ScrArea *area = CTX_wm_area(C); + ARegion *region; + for (region = area->regionbase.first; region; region = region->next) { + if (region->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = region->regiondata; + /* when using all regions, don't jump out of camera view, + * but _do_ allow locked cameras to be moved */ + if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { + view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx); + } + } + } +} + +static int view3d_all_exec(bContext *C, wmOperator *op) +{ + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); + Base *base_eval; + const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions"); + const bool skip_camera = (ED_view3d_camera_lock_check(v3d, region->regiondata) || + /* any one of the regions may be locked */ + (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA)); + const bool center = RNA_boolean_get(op->ptr, "center"); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + float min[3], max[3]; + bool changed = false; + + if (center) { + /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */ + View3DCursor *cursor = &scene->cursor; + zero_v3(min); + zero_v3(max); + zero_v3(cursor->location); + float mat3[3][3]; + unit_m3(mat3); + BKE_scene_cursor_mat3_to_rot(cursor, mat3, false); + } + else { + INIT_MINMAX(min, max); + } + + for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) { + if (BASE_VISIBLE(v3d, base_eval)) { + bool only_center = false; + Object *ob = DEG_get_original_object(base_eval->object); + if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) { + continue; + } + view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max); + changed = true; + } + } + + if (center) { + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + WM_msg_publish_rna_prop(mbus, &scene->id, &scene->cursor, View3DCursor, location); + + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + } + + if (!changed) { + ED_region_tag_redraw(region); + /* TODO: should this be cancel? + * I think no, because we always move the cursor, with or without + * object, but in this case there is no change in the scene, + * only the cursor so I choice a ED_region_tag like + * view3d_smooth_view do for the center_cursor. + * See bug T22640. + */ + return OPERATOR_FINISHED; + } + + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { + /* This is an approximation, see function documentation for details. */ + ED_view3d_clipping_clamp_minmax(rv3d, min, max); + } + + if (use_all_regions) { + view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx); + } + else { + view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx); + } + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_view_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Frame All"; + ot->description = "View all objects in scene"; + ot->idname = "VIEW3D_OT_view_all"; + + /* api callbacks */ + ot->exec = view3d_all_exec; + ot->poll = ED_operator_region_view3d_active; + + /* flags */ + ot->flag = 0; + + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); + RNA_def_boolean(ot->srna, "center", 0, "Center", ""); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Frame Selected Operator + * + * Move & Zoom the view to fit selected contents. + * \{ */ + +static int viewselected_exec(bContext *C, wmOperator *op) +{ + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); + Object *ob_eval = OBACT(view_layer_eval); + Object *obedit = CTX_data_edit_object(C); + const bGPdata *gpd_eval = ob_eval && (ob_eval->type == OB_GPENCIL) ? ob_eval->data : NULL; + const bool is_gp_edit = gpd_eval ? GPENCIL_ANY_MODE(gpd_eval) : false; + const bool is_face_map = ((is_gp_edit == false) && region->gizmo_map && + WM_gizmomap_is_any_selected(region->gizmo_map)); + float min[3], max[3]; + bool ok = false, ok_dist = true; + const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions"); + const bool skip_camera = (ED_view3d_camera_lock_check(v3d, region->regiondata) || + /* any one of the regions may be locked */ + (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA)); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + INIT_MINMAX(min, max); + if (is_face_map) { + ob_eval = NULL; + } + + if (ob_eval && (ob_eval->mode & OB_MODE_WEIGHT_PAINT)) { + /* hard-coded exception, we look for the one selected armature */ + /* this is weak code this way, we should make a generic + * active/selection callback interface once... */ + Base *base_eval; + for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) { + if (BASE_SELECTED_EDITABLE(v3d, base_eval)) { + if (base_eval->object->type == OB_ARMATURE) { + if (base_eval->object->mode & OB_MODE_POSE) { + break; + } + } + } + } + if (base_eval) { + ob_eval = base_eval->object; + } + } + + if (is_gp_edit) { + CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { + /* we're only interested in selected points here... */ + if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) { + ok |= BKE_gpencil_stroke_minmax(gps, true, min, max); + } + if (gps->editcurve != NULL) { + for (int i = 0; i < gps->editcurve->tot_curve_points; i++) { + BezTriple *bezt = &gps->editcurve->curve_points[i].bezt; + if ((bezt->f1 & SELECT)) { + minmax_v3v3_v3(min, max, bezt->vec[0]); + ok = true; + } + if ((bezt->f2 & SELECT)) { + minmax_v3v3_v3(min, max, bezt->vec[1]); + ok = true; + } + if ((bezt->f3 & SELECT)) { + minmax_v3v3_v3(min, max, bezt->vec[2]); + ok = true; + } + } + } + } + CTX_DATA_END; + + if ((ob_eval) && (ok)) { + mul_m4_v3(ob_eval->obmat, min); + mul_m4_v3(ob_eval->obmat, max); + } + } + else if (is_face_map) { + ok = WM_gizmomap_minmax(region->gizmo_map, true, true, min, max); + } + else if (obedit) { + /* only selected */ + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->type, obedit->mode, ob_eval_iter) { + ok |= ED_view3d_minmax_verts(ob_eval_iter, min, max); + } + FOREACH_OBJECT_IN_MODE_END; + } + else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) { + FOREACH_OBJECT_IN_MODE_BEGIN ( + view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter) { + ok |= BKE_pose_minmax(ob_eval_iter, min, max, true, true); + } + FOREACH_OBJECT_IN_MODE_END; + } + else if (BKE_paint_select_face_test(ob_eval)) { + ok = paintface_minmax(ob_eval, min, max); + } + else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) { + ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max); + } + else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | + OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { + BKE_paint_stroke_get_average(scene, ob_eval, min); + copy_v3_v3(max, min); + ok = true; + ok_dist = 0; /* don't zoom */ + } + else { + Base *base_eval; + for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) { + if (BASE_SELECTED(v3d, base_eval)) { + bool only_center = false; + Object *ob = DEG_get_original_object(base_eval->object); + if (view3d_object_skip_minmax(v3d, rv3d, ob, skip_camera, &only_center)) { + continue; + } + view3d_object_calc_minmax(depsgraph, scene, base_eval->object, only_center, min, max); + ok = 1; + } + } + } + + if (ok == 0) { + return OPERATOR_FINISHED; + } + + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { + /* This is an approximation, see function documentation for details. */ + ED_view3d_clipping_clamp_minmax(rv3d, min, max); + } + + if (use_all_regions) { + view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx); + } + else { + view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx); + } + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_view_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Frame Selected"; + ot->description = "Move the view to the selection center"; + ot->idname = "VIEW3D_OT_view_selected"; + + /* api callbacks */ + ot->exec = viewselected_exec; + ot->poll = view3d_zoom_or_dolly_poll; + + /* flags */ + ot->flag = 0; + + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Cursor Operator + * \{ */ + +static int viewcenter_cursor_exec(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Scene *scene = CTX_data_scene(C); + + if (rv3d) { + ARegion *region = CTX_wm_region(C); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + ED_view3d_smooth_view_force_finish(C, v3d, region); + + /* non camera center */ + float new_ofs[3]; + negate_v3_v3(new_ofs, scene->cursor.location); + ED_view3d_smooth_view( + C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs}); + + /* Smooth view does view-lock #RV3D_BOXVIEW copy. */ + } + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Center View to Cursor"; + ot->description = "Center the view so that the cursor is in the middle of the view"; + ot->idname = "VIEW3D_OT_view_center_cursor"; + + /* api callbacks */ + ot->exec = viewcenter_cursor_exec; + ot->poll = view3d_location_poll; + + /* flags */ + ot->flag = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Pick Operator + * \{ */ + +static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + ARegion *region = CTX_wm_region(C); + + if (rv3d) { + struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + float new_ofs[3]; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + ED_view3d_smooth_view_force_finish(C, v3d, region); + + view3d_operator_needs_opengl(C); + + if (ED_view3d_autodist(depsgraph, region, v3d, event->mval, new_ofs, false, NULL)) { + /* pass */ + } + else { + /* fallback to simple pan */ + negate_v3_v3(new_ofs, rv3d->ofs); + ED_view3d_win_to_3d_int(v3d, region, new_ofs, event->mval, new_ofs); + } + negate_v3(new_ofs); + ED_view3d_smooth_view( + C, v3d, region, smooth_viewtx, &(const V3D_SmoothParams){.ofs = new_ofs}); + } + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_view_center_pick(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Center View to Mouse"; + ot->description = "Center the view to the Z-depth position under the mouse cursor"; + ot->idname = "VIEW3D_OT_view_center_pick"; + + /* api callbacks */ + ot->invoke = viewcenter_pick_invoke; + ot->poll = view3d_location_poll; + + /* flags */ + ot->flag = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Axis Operator + * \{ */ + +static const EnumPropertyItem prop_view_items[] = { + {RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View from the left"}, + {RV3D_VIEW_RIGHT, "RIGHT", ICON_TRIA_RIGHT, "Right", "View from the right"}, + {RV3D_VIEW_BOTTOM, "BOTTOM", ICON_TRIA_DOWN, "Bottom", "View from the bottom"}, + {RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View from the top"}, + {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View from the front"}, + {RV3D_VIEW_BACK, "BACK", 0, "Back", "View from the back"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int view_axis_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + ARegion *region; + RegionView3D *rv3d; + static int perspo = RV3D_PERSP; + int viewnum; + int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + /* no NULL check is needed, poll checks */ + ED_view3d_context_user_region(C, &v3d, ®ion); + rv3d = region->regiondata; + + ED_view3d_smooth_view_force_finish(C, v3d, region); + + viewnum = RNA_enum_get(op->ptr, "type"); + + float align_quat_buf[4]; + float *align_quat = NULL; + + if (RNA_boolean_get(op->ptr, "align_active")) { + /* align to active object */ + Object *obact = CTX_data_active_object(C); + if (obact != NULL) { + float twmat[3][3]; + struct ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = CTX_data_edit_object(C); + /* same as transform gizmo when normal is set */ + ED_getTransformOrientationMatrix(view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat); + align_quat = align_quat_buf; + mat3_to_quat(align_quat, twmat); + invert_qt_normalized(align_quat); + } + } + + if (RNA_boolean_get(op->ptr, "relative")) { + float quat_rotate[4]; + float quat_test[4]; + + if (viewnum == RV3D_VIEW_LEFT) { + axis_angle_to_quat(quat_rotate, rv3d->viewinv[1], -M_PI / 2.0f); + } + else if (viewnum == RV3D_VIEW_RIGHT) { + axis_angle_to_quat(quat_rotate, rv3d->viewinv[1], M_PI / 2.0f); + } + else if (viewnum == RV3D_VIEW_TOP) { + axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], -M_PI / 2.0f); + } + else if (viewnum == RV3D_VIEW_BOTTOM) { + axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], M_PI / 2.0f); + } + else if (viewnum == RV3D_VIEW_FRONT) { + unit_qt(quat_rotate); + } + else if (viewnum == RV3D_VIEW_BACK) { + axis_angle_to_quat(quat_rotate, rv3d->viewinv[0], M_PI); + } + else { + BLI_assert(0); + } + + mul_qt_qtqt(quat_test, rv3d->viewquat, quat_rotate); + + float angle_best = FLT_MAX; + int view_best = -1; + int view_axis_roll_best = -1; + for (int i = RV3D_VIEW_FRONT; i <= RV3D_VIEW_BOTTOM; i++) { + for (int j = RV3D_VIEW_AXIS_ROLL_0; j <= RV3D_VIEW_AXIS_ROLL_270; j++) { + float quat_axis[4]; + ED_view3d_quat_from_axis_view(i, j, quat_axis); + if (align_quat) { + mul_qt_qtqt(quat_axis, quat_axis, align_quat); + } + const float angle_test = fabsf(angle_signed_qtqt(quat_axis, quat_test)); + if (angle_best > angle_test) { + angle_best = angle_test; + view_best = i; + view_axis_roll_best = j; + } + } + } + if (view_best == -1) { + view_best = RV3D_VIEW_FRONT; + view_axis_roll_best = RV3D_VIEW_AXIS_ROLL_0; + } + + /* Disallow non-upright views in turn-table modes, + * it's too difficult to navigate out of them. */ + if ((U.flag & USER_TRACKBALL) == 0) { + if (!ELEM(view_best, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { + view_axis_roll_best = RV3D_VIEW_AXIS_ROLL_0; + } + } + + viewnum = view_best; + view_axis_roll = view_axis_roll_best; + } + + /* Use this to test if we started out with a camera */ + const int nextperspo = (rv3d->persp == RV3D_CAMOB) ? rv3d->lpersp : perspo; + float quat[4]; + ED_view3d_quat_from_axis_view(viewnum, view_axis_roll, quat); + axis_set_view( + C, v3d, region, quat, viewnum, view_axis_roll, nextperspo, align_quat, smooth_viewtx); + + perspo = rv3d->persp; + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_view_axis(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "View Axis"; + ot->description = "Use a preset viewpoint"; + ot->idname = "VIEW3D_OT_view_axis"; + + /* api callbacks */ + ot->exec = view_axis_exec; + ot->poll = ED_operator_rv3d_user_region_poll; + + /* flags */ + ot->flag = 0; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "Preset viewpoint to use"); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "align_active", 0, "Align Active", "Align to the active object's axis"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "relative", 0, "Relative", "Rotate relative to the current orientation"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Camera Operator + * \{ */ + +static int view_camera_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + ARegion *region; + RegionView3D *rv3d; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + /* no NULL check is needed, poll checks */ + ED_view3d_context_user_region(C, &v3d, ®ion); + rv3d = region->regiondata; + + ED_view3d_smooth_view_force_finish(C, v3d, region); + + if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0) { + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + + if (rv3d->persp != RV3D_CAMOB) { + Object *ob = OBACT(view_layer); + + if (!rv3d->smooth_timer) { + /* store settings of current view before allowing overwriting with camera view + * only if we're not currently in a view transition */ + + ED_view3d_lastview_store(rv3d); + } + + /* first get the default camera for the view lock type */ + if (v3d->scenelock) { + /* sets the camera view if available */ + v3d->camera = scene->camera; + } + else { + /* use scene camera if one is not set (even though we're unlocked) */ + if (v3d->camera == NULL) { + v3d->camera = scene->camera; + } + } + + /* if the camera isn't found, check a number of options */ + if (v3d->camera == NULL && ob && ob->type == OB_CAMERA) { + v3d->camera = ob; + } + + if (v3d->camera == NULL) { + v3d->camera = BKE_view_layer_camera_find(view_layer); + } + + /* couldn't find any useful camera, bail out */ + if (v3d->camera == NULL) { + return OPERATOR_CANCELLED; + } + + /* important these don't get out of sync for locked scenes */ + if (v3d->scenelock && scene->camera != v3d->camera) { + scene->camera = v3d->camera; + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + } + + /* finally do snazzy view zooming */ + rv3d->persp = RV3D_CAMOB; + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .camera = v3d->camera, + .ofs = rv3d->ofs, + .quat = rv3d->viewquat, + .dist = &rv3d->dist, + .lens = &v3d->lens, + }); + } + else { + /* return to settings of last view */ + /* does view3d_smooth_view too */ + axis_set_view(C, + v3d, + region, + rv3d->lviewquat, + rv3d->lview, + rv3d->lview_axis_roll, + rv3d->lpersp, + NULL, + smooth_viewtx); + } + } + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_view_camera(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "View Camera"; + ot->description = "Toggle the camera view"; + ot->idname = "VIEW3D_OT_view_camera"; + + /* api callbacks */ + ot->exec = view_camera_exec; + ot->poll = ED_operator_rv3d_user_region_poll; + + /* flags */ + ot->flag = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Orbit Operator + * + * Rotate (orbit) in incremental steps. For interactive orbit see #VIEW3D_OT_rotate. + * \{ */ + +enum { + V3D_VIEW_STEPLEFT = 1, + V3D_VIEW_STEPRIGHT, + V3D_VIEW_STEPDOWN, + V3D_VIEW_STEPUP, +}; + +static const EnumPropertyItem prop_view_orbit_items[] = { + {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the left"}, + {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the right"}, + {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view up"}, + {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view down"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int vieworbit_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + ARegion *region; + RegionView3D *rv3d; + int orbitdir; + char view_opposite; + PropertyRNA *prop_angle = RNA_struct_find_property(op->ptr, "angle"); + float angle = RNA_property_is_set(op->ptr, prop_angle) ? + RNA_property_float_get(op->ptr, prop_angle) : + DEG2RADF(U.pad_rot_angle); + + /* no NULL check is needed, poll checks */ + v3d = CTX_wm_view3d(C); + region = CTX_wm_region(C); + rv3d = region->regiondata; + + /* support for switching to the opposite view (even when in locked views) */ + view_opposite = (fabsf(angle) == (float)M_PI) ? ED_view3d_axis_view_opposite(rv3d->view) : + RV3D_VIEW_USER; + orbitdir = RNA_enum_get(op->ptr, "type"); + + if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) && (view_opposite == RV3D_VIEW_USER)) { + /* no NULL check is needed, poll checks */ + ED_view3d_context_user_region(C, &v3d, ®ion); + rv3d = region->regiondata; + } + + ED_view3d_smooth_view_force_finish(C, v3d, region); + + if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0 || (view_opposite != RV3D_VIEW_USER)) { + if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { + int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + float quat_mul[4]; + float quat_new[4]; + + if (view_opposite == RV3D_VIEW_USER) { + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_persp_ensure(depsgraph, v3d, region); + } + + if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) { + if (orbitdir == V3D_VIEW_STEPRIGHT) { + angle = -angle; + } + + /* z-axis */ + axis_angle_to_quat_single(quat_mul, 'Z', angle); + } + else { + + if (orbitdir == V3D_VIEW_STEPDOWN) { + angle = -angle; + } + + /* horizontal axis */ + axis_angle_to_quat(quat_mul, rv3d->viewinv[0], angle); + } + + mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul); + + /* avoid precision loss over time */ + normalize_qt(quat_new); + + if (view_opposite != RV3D_VIEW_USER) { + rv3d->view = view_opposite; + /* avoid float in-precision, just get a new orientation */ + ED_view3d_quat_from_axis_view(view_opposite, rv3d->view_axis_roll, quat_new); + } + else { + rv3d->view = RV3D_VIEW_USER; + } + + float dyn_ofs[3], *dyn_ofs_pt = NULL; + + if (U.uiflag & USER_ORBIT_SELECTION) { + if (view3d_orbit_calc_center(C, dyn_ofs)) { + negate_v3(dyn_ofs); + dyn_ofs_pt = dyn_ofs; + } + } + + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .quat = quat_new, + .dyn_ofs = dyn_ofs_pt, + }); + + return OPERATOR_FINISHED; + } + } + + return OPERATOR_CANCELLED; +} + +void VIEW3D_OT_view_orbit(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "View Orbit"; + ot->description = "Orbit the view"; + ot->idname = "VIEW3D_OT_view_orbit"; + + /* api callbacks */ + ot->exec = vieworbit_exec; + ot->poll = ED_operator_rv3d_user_region_poll; + + /* flags */ + ot->flag = 0; + + /* properties */ + prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + ot->prop = RNA_def_enum( + ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Pan Operator + * + * Move (pan) in incremental steps. For interactive pan see #VIEW3D_OT_move. + * \{ */ + +enum { + V3D_VIEW_PANLEFT = 1, + V3D_VIEW_PANRIGHT, + V3D_VIEW_PANDOWN, + V3D_VIEW_PANUP, +}; + +static const EnumPropertyItem prop_view_pan_items[] = { + {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the left"}, + {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the right"}, + {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view up"}, + {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view down"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int x = 0, y = 0; + int pandir = RNA_enum_get(op->ptr, "type"); + + if (pandir == V3D_VIEW_PANRIGHT) { + x = -32; + } + else if (pandir == V3D_VIEW_PANLEFT) { + x = 32; + } + else if (pandir == V3D_VIEW_PANUP) { + y = -25; + } + else if (pandir == V3D_VIEW_PANDOWN) { + y = 25; + } + + ViewOpsData *vod = viewops_data_create( + C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT)); + + viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y); + + viewops_data_free(C, vod); + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_view_pan(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Pan View Direction"; + ot->description = "Pan the view in a given direction"; + ot->idname = "VIEW3D_OT_view_pan"; + + /* api callbacks */ + ot->invoke = viewpan_invoke; + ot->poll = view3d_location_poll; + + /* flags */ + ot->flag = 0; + + /* Properties */ + ot->prop = RNA_def_enum( + ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan"); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate.h b/source/blender/editors/space_view3d/view3d_navigate.h new file mode 100644 index 00000000000..792d2a83bc2 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate.h @@ -0,0 +1,282 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup spview3d + */ + +#pragma once + +/** + * Size of the sphere being dragged for trackball rotation within the view bounds. + * also affects speed (smaller is faster). + */ +#define V3D_OP_TRACKBALLSIZE (1.1f) + +struct ARegion; +struct bContext; +struct Depsgraph; +struct Dial; +struct Main; +struct rcti; +struct RegionView3D; +struct Scene; +struct ScrArea; +struct View3D; +struct wmEvent; +struct wmOperator; + +enum eV3D_OpPropFlag { + V3D_OP_PROP_MOUSE_CO = (1 << 0), + V3D_OP_PROP_DELTA = (1 << 1), + V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2), + V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3), +}; + +enum { + VIEW_PASS = 0, + VIEW_APPLY, + VIEW_CONFIRM, +}; + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ +enum { + VIEW_MODAL_CONFIRM = 1, /* used for all view operations */ + VIEWROT_MODAL_AXIS_SNAP_ENABLE = 2, + VIEWROT_MODAL_AXIS_SNAP_DISABLE = 3, + VIEWROT_MODAL_SWITCH_ZOOM = 4, + VIEWROT_MODAL_SWITCH_MOVE = 5, + VIEWROT_MODAL_SWITCH_ROTATE = 6, +}; + +enum eViewOpsFlag { + /** When enabled, rotate around the selection. */ + VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0), + /** When enabled, use the depth under the cursor for navigation. */ + VIEWOPS_FLAG_DEPTH_NAVIGATE = (1 << 1), + /** + * When enabled run #ED_view3d_persp_ensure this may switch out of camera view + * when orbiting or switch from orthographic to perspective when auto-perspective is enabled. + * Some operations don't require this (view zoom/pan or NDOF where subtle rotation is common + * so we don't want it to trigger auto-perspective). */ + VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2), + /** When set, ignore any options that depend on initial cursor location. */ + VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3), +}; + +/** Generic View Operator Custom-Data */ +typedef struct ViewOpsData { + /** Context pointers (assigned by #viewops_data_create). */ + struct Main *bmain; + struct Scene *scene; + struct ScrArea *area; + struct ARegion *region; + struct View3D *v3d; + struct RegionView3D *rv3d; + struct Depsgraph *depsgraph; + + /** Needed for continuous zoom. */ + struct wmTimer *timer; + + /** Viewport state on initialization, don't change afterwards. */ + struct { + float dist; + float camzoom; + float quat[4]; + /** #wmEvent.xy. */ + int event_xy[2]; + /** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set. + * so we can simulate pressing in the middle of the screen. */ + int event_xy_offset[2]; + /** #wmEvent.type that triggered the operator. */ + int event_type; + float ofs[3]; + /** Initial distance to 'ofs'. */ + float zfac; + + /** Trackball rotation only. */ + float trackvec[3]; + /** Dolly only. */ + float mousevec[3]; + + /** + * #RegionView3D.persp set after auto-perspective is applied. + * If we want the value before running the operator, add a separate member. + */ + char persp; + + /** Used for roll */ + struct Dial *dial; + } init; + + /** Previous state (previous modal event handled). */ + struct { + int event_xy[2]; + /** For operators that use time-steps (continuous zoom). */ + double time; + } prev; + + /** Current state. */ + struct { + /** Working copy of #RegionView3D.viewquat, needed for rotation calculation + * so we can apply snap to the 3D Viewport while keeping the unsnapped rotation + * here to use when snap is disabled and for continued calculation. */ + float viewquat[4]; + } curr; + + float reverse; + bool axis_snap; /* view rotate only */ + + /** Use for orbit selection and auto-dist. */ + float dyn_ofs[3]; + bool use_dyn_ofs; +} ViewOpsData; + +/* view3d_navigate.c */ +bool view3d_location_poll(struct bContext *C); +bool view3d_rotation_poll(struct bContext *C); +bool view3d_zoom_or_dolly_poll(struct bContext *C); + +enum eViewOpsFlag viewops_flag_from_prefs(void); +void calctrackballvec(const struct rcti *rect, const int event_xy[2], float r_dir[3]); +void viewmove_apply(ViewOpsData *vod, int x, int y); +void view3d_orbit_apply_dyn_ofs(float r_ofs[3], + const float ofs_old[3], + const float viewquat_old[4], + const float viewquat_new[4], + const float dyn_ofs[3]); +void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4]); +bool view3d_orbit_calc_center(struct bContext *C, float r_dyn_ofs[3]); + +void view3d_operator_properties_common(struct wmOperatorType *ot, const enum eV3D_OpPropFlag flag); + +/** + * Allocate and fill in context pointers for #ViewOpsData + */ +void viewops_data_free(struct bContext *C, ViewOpsData *vod); + +/** + * Allocate, fill in context pointers and calculate the values for #ViewOpsData + */ +ViewOpsData *viewops_data_create(struct bContext *C, + const struct wmEvent *event, + enum eViewOpsFlag viewops_flag); + +void VIEW3D_OT_view_all(struct wmOperatorType *ot); +void VIEW3D_OT_view_selected(struct wmOperatorType *ot); +void VIEW3D_OT_view_center_cursor(struct wmOperatorType *ot); +void VIEW3D_OT_view_center_pick(struct wmOperatorType *ot); +void VIEW3D_OT_view_axis(struct wmOperatorType *ot); +void VIEW3D_OT_view_camera(struct wmOperatorType *ot); +void VIEW3D_OT_view_orbit(struct wmOperatorType *ot); +void VIEW3D_OT_view_pan(struct wmOperatorType *ot); + +/* view3d_navigate_dolly.c */ +void viewdolly_modal_keymap(struct wmKeyConfig *keyconf); +void VIEW3D_OT_dolly(struct wmOperatorType *ot); + +/* view3d_navigate_fly.c */ +void fly_modal_keymap(struct wmKeyConfig *keyconf); +void view3d_keymap(struct wmKeyConfig *keyconf); +void VIEW3D_OT_fly(struct wmOperatorType *ot); + +/* view3d_navigate_move.c */ +void viewmove_modal_keymap(struct wmKeyConfig *keyconf); +void VIEW3D_OT_move(struct wmOperatorType *ot); + +/* view3d_navigate_ndof.c */ +#ifdef WITH_INPUT_NDOF +struct wmNDOFMotionData; + +/** + * Called from both fly mode and walk mode, + */ +void view3d_ndof_fly(const struct wmNDOFMotionData *ndof, + struct View3D *v3d, + struct RegionView3D *rv3d, + bool use_precision, + short protectflag, + bool *r_has_translate, + bool *r_has_rotate); +void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot); +void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot); +void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot); +void VIEW3D_OT_ndof_all(struct wmOperatorType *ot); +#endif /* WITH_INPUT_NDOF */ + +/* view3d_navigate_roll.c */ +void VIEW3D_OT_view_roll(struct wmOperatorType *ot); + +/* view3d_navigate_rotate.c */ +void viewrotate_modal_keymap(struct wmKeyConfig *keyconf); +void VIEW3D_OT_rotate(struct wmOperatorType *ot); + +/* view3d_navigate_smoothview.c */ + +/** + * Parameters for setting the new 3D Viewport state. + * + * Each of the struct members may be NULL to signify they aren't to be adjusted. + */ +typedef struct V3D_SmoothParams { + struct Object *camera_old, *camera; + const float *ofs, *quat, *dist, *lens; + + /** Alternate rotation center, when set `ofs` must be NULL. */ + const float *dyn_ofs; +} V3D_SmoothParams; + +/** + * The arguments are the desired situation. + */ +void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph, + struct wmWindowManager *wm, + struct wmWindow *win, + struct ScrArea *area, + struct View3D *v3d, + struct ARegion *region, + int smooth_viewtx, + const V3D_SmoothParams *sview); + +void ED_view3d_smooth_view(struct bContext *C, + struct View3D *v3d, + struct ARegion *region, + int smooth_viewtx, + const V3D_SmoothParams *sview); + +/** + * Apply the smooth-view immediately, use when we need to start a new view operation. + * (so we don't end up half-applying a view operation when pressing keys quickly). + */ +void ED_view3d_smooth_view_force_finish(struct bContext *C, + struct View3D *v3d, + struct ARegion *region); + +void VIEW3D_OT_smoothview(struct wmOperatorType *ot); + +/* view3d_navigate_walk.c */ +void walk_modal_keymap(struct wmKeyConfig *keyconf); +void VIEW3D_OT_walk(struct wmOperatorType *ot); + +/* view3d_navigate_zoom.c */ +void viewzoom_modal_keymap(struct wmKeyConfig *keyconf); +void VIEW3D_OT_zoom(struct wmOperatorType *ot); + +/* view3d_navigate_zoom_border.c */ +void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_navigate_dolly.c b/source/blender/editors/space_view3d/view3d_navigate_dolly.c new file mode 100644 index 00000000000..02783c2a244 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_dolly.c @@ -0,0 +1,337 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_report.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" + +#include "RNA_access.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Dolly Operator + * + * Like zoom but translates the view offset along the view direction + * which avoids #RegionView3D.dist approaching zero. + * \{ */ + +/* This is an exact copy of #viewzoom_modal_keymap. */ +void viewdolly_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, + {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, + + {0, NULL, 0, NULL, NULL}, + }; + + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); +} + +static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (ED_view3d_offset_lock_check(v3d, rv3d)) { + BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked"); + return true; + } + return false; +} + +static void view_dolly_to_vector_3d(ARegion *region, + const float orig_ofs[3], + const float dvec[3], + float dfac) +{ + RegionView3D *rv3d = region->regiondata; + madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac)); +} + +static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const bool zoom_invert) +{ + float zfac = 1.0; + + { + float len1, len2; + + if (U.uiflag & USER_ZOOM_HORIZ) { + len1 = (vod->region->winrct.xmax - xy[0]) + 5; + len2 = (vod->region->winrct.xmax - vod->init.event_xy[0]) + 5; + } + else { + len1 = (vod->region->winrct.ymax - xy[1]) + 5; + len2 = (vod->region->winrct.ymax - vod->init.event_xy[1]) + 5; + } + if (zoom_invert) { + SWAP(float, len1, len2); + } + + zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist); + } + + if (zfac != 1.0f) { + view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, zfac); + } + + if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(vod->area, vod->region); + } + + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); + + ED_region_tag_redraw(vod->region); +} + +static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + bool use_autokey = false; + int ret = OPERATOR_RUNNING_MODAL; + + /* execute the events */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_MOVE: + WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ROTATE: + WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } + } + else if (event_code == VIEW_CONFIRM) { + use_autokey = true; + ret = OPERATOR_FINISHED; + } + + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); + } + + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, vod); + op->customdata = NULL; + } + + return ret; +} + +static int viewdolly_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + RegionView3D *rv3d; + ScrArea *area; + ARegion *region; + float mousevec[3]; + + const int delta = RNA_int_get(op->ptr, "delta"); + + if (op->customdata) { + ViewOpsData *vod = op->customdata; + + area = vod->area; + region = vod->region; + copy_v3_v3(mousevec, vod->init.mousevec); + } + else { + area = CTX_wm_area(C); + region = CTX_wm_region(C); + negate_v3_v3(mousevec, ((RegionView3D *)region->regiondata)->viewinv[2]); + normalize_v3(mousevec); + } + + v3d = area->spacedata.first; + rv3d = region->regiondata; + + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + /* overwrite the mouse vector with the view direction (zoom into the center) */ + if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { + normalize_v3_v3(mousevec, rv3d->viewinv[2]); + negate_v3(mousevec); + } + + view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 1.8f : 0.2f); + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(area, region); + } + + ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d); + + ED_region_tag_redraw(region); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + + return OPERATOR_FINISHED; +} + +/* copied from viewzoom_invoke(), changes here may apply there */ +static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + if (viewdolly_offset_lock_check(C, op)) { + return OPERATOR_CANCELLED; + } + + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + vod = op->customdata = viewops_data_create( + C, + event, + (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) | + (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + /* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */ + /* switch from camera view when: */ + if (vod->rv3d->persp != RV3D_PERSP) { + if (vod->rv3d->persp == RV3D_CAMOB) { + /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_persp_switch_from_camera(depsgraph, vod->v3d, vod->rv3d, RV3D_PERSP); + } + else { + vod->rv3d->persp = RV3D_PERSP; + } + ED_region_tag_redraw(vod->region); + } + + /* if one or the other zoom position aren't set, set from event */ + if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) { + RNA_int_set(op->ptr, "mx", event->xy[0]); + RNA_int_set(op->ptr, "my", event->xy[1]); + } + + if (RNA_struct_property_is_set(op->ptr, "delta")) { + viewdolly_exec(C, op); + } + else { + /* overwrite the mouse vector with the view direction (zoom into the center) */ + if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { + negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + normalize_v3(vod->init.mousevec); + } + + if (event->type == MOUSEZOOM) { + /* Bypass Zoom invert flag for track pads (pass false always) */ + + if (U.uiflag & USER_ZOOM_HORIZ) { + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0]; + } + else { + /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] - + event->prev_xy[0]; + } + viewdolly_apply(vod, event->prev_xy, (U.uiflag & USER_ZOOM_INVERT) == 0); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + return OPERATOR_FINISHED; + } + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; + } + return OPERATOR_FINISHED; +} + +static void viewdolly_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op->customdata); + op->customdata = NULL; +} + +void VIEW3D_OT_dolly(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Dolly View"; + ot->description = "Dolly in/out in the view"; + ot->idname = "VIEW3D_OT_dolly"; + + /* api callbacks */ + ot->invoke = viewdolly_invoke; + ot->exec = viewdolly_exec; + ot->modal = viewdolly_modal; + ot->poll = view3d_rotation_poll; + ot->cancel = viewdolly_cancel; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; + + /* properties */ + view3d_operator_properties_common( + ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c index 2e9cb419e2e..940616eec1f 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_fly.c +++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c @@ -58,6 +58,7 @@ #include "DEG_depsgraph.h" #include "view3d_intern.h" /* own include */ +#include "view3d_navigate.h" /* -------------------------------------------------------------------- */ /** \name Modal Key-map diff --git a/source/blender/editors/space_view3d/view3d_navigate_move.c b/source/blender/editors/space_view3d/view3d_navigate_move.c new file mode 100644 index 00000000000..90acf20d24f --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_move.c @@ -0,0 +1,188 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "BKE_context.h" + +#include "WM_api.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Move (Pan) Operator + * \{ */ + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ + +void viewmove_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, + + {0, NULL, 0, NULL, NULL}, + }; + + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Move Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, "View3D Move Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, EVT_ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); + WM_modalkeymap_add_item( + keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_move"); +} + +static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + bool use_autokey = false; + int ret = OPERATOR_RUNNING_MODAL; + + /* execute the events */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ZOOM: + WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ROTATE: + WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + viewmove_apply(vod, event->xy[0], event->xy[1]); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } + } + else if (event_code == VIEW_CONFIRM) { + use_autokey = true; + ret = OPERATOR_FINISHED; + } + + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); + } + + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op->customdata); + op->customdata = NULL; + } + + return ret; +} + +static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + vod = op->customdata = viewops_data_create( + C, + event, + (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) | + (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); + vod = op->customdata; + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + if (event->type == MOUSEPAN) { + /* invert it, trackpad scroll follows same principle as 2d windows this way */ + viewmove_apply( + vod, 2 * event->xy[0] - event->prev_xy[0], 2 * event->xy[1] - event->prev_xy[1]); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + + return OPERATOR_FINISHED; + } + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static void viewmove_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op->customdata); + op->customdata = NULL; +} + +void VIEW3D_OT_move(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name = "Pan View"; + ot->description = "Move the view"; + ot->idname = "VIEW3D_OT_move"; + + /* api callbacks */ + ot->invoke = viewmove_invoke; + ot->modal = viewmove_modal; + ot->poll = view3d_location_poll; + ot->cancel = viewmove_cancel; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; + + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_ndof.c b/source/blender/editors/space_view3d/view3d_navigate_ndof.c new file mode 100644 index 00000000000..285d5c02db2 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_ndof.c @@ -0,0 +1,661 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Utility Functions + * \{ */ + +#ifdef WITH_INPUT_NDOF + +enum { + HAS_TRANSLATE = (1 << 0), + HAS_ROTATE = (1 << 0), +}; + +static bool ndof_has_translate(const wmNDOFMotionData *ndof, + const View3D *v3d, + const RegionView3D *rv3d) +{ + return !is_zero_v3(ndof->tvec) && (!ED_view3d_offset_lock_check(v3d, rv3d)); +} + +static bool ndof_has_rotate(const wmNDOFMotionData *ndof, const RegionView3D *rv3d) +{ + return !is_zero_v3(ndof->rvec) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0); +} + +/** + * \param depth_pt: A point to calculate the depth (in perspective mode) + */ +static float view3d_ndof_pan_speed_calc_ex(RegionView3D *rv3d, const float depth_pt[3]) +{ + float speed = rv3d->pixsize * NDOF_PIXELS_PER_SECOND; + + if (rv3d->is_persp) { + speed *= ED_view3d_calc_zfac(rv3d, depth_pt, NULL); + } + + return speed; +} + +static float view3d_ndof_pan_speed_calc_from_dist(RegionView3D *rv3d, const float dist) +{ + float viewinv[4]; + float tvec[3]; + + BLI_assert(dist >= 0.0f); + + copy_v3_fl3(tvec, 0.0f, 0.0f, dist); + /* rv3d->viewinv isn't always valid */ +# if 0 + mul_mat3_m4_v3(rv3d->viewinv, tvec); +# else + invert_qt_qt_normalized(viewinv, rv3d->viewquat); + mul_qt_v3(viewinv, tvec); +# endif + + return view3d_ndof_pan_speed_calc_ex(rv3d, tvec); +} + +static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d) +{ + float tvec[3]; + negate_v3_v3(tvec, rv3d->ofs); + + return view3d_ndof_pan_speed_calc_ex(rv3d, tvec); +} + +/** + * Zoom and pan in the same function since sometimes zoom is interpreted as dolly (pan forward). + * + * \param has_zoom: zoom, otherwise dolly, + * often `!rv3d->is_persp` since it doesn't make sense to dolly in ortho. + */ +static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, + ScrArea *area, + ARegion *region, + const bool has_translate, + const bool has_zoom) +{ + RegionView3D *rv3d = region->regiondata; + float view_inv[4]; + float pan_vec[3]; + + if (has_translate == false && has_zoom == false) { + return; + } + + WM_event_ndof_pan_get(ndof, pan_vec, false); + + if (has_zoom) { + /* zoom with Z */ + + /* Zoom! + * velocity should be proportional to the linear velocity attained by rotational motion + * of same strength [got that?] proportional to `arclength = radius * angle`. + */ + + pan_vec[2] = 0.0f; + + /* "zoom in" or "translate"? depends on zoom mode in user settings? */ + if (ndof->tvec[2]) { + float zoom_distance = rv3d->dist * ndof->dt * ndof->tvec[2]; + + if (U.ndof_flag & NDOF_ZOOM_INVERT) { + zoom_distance = -zoom_distance; + } + + rv3d->dist += zoom_distance; + } + } + else { + /* dolly with Z */ + + /* all callers must check */ + if (has_translate) { + BLI_assert(ED_view3d_offset_lock_check((View3D *)area->spacedata.first, rv3d) == false); + } + } + + if (has_translate) { + const float speed = view3d_ndof_pan_speed_calc(rv3d); + + mul_v3_fl(pan_vec, speed * ndof->dt); + + /* transform motion from view to world coordinates */ + invert_qt_qt_normalized(view_inv, rv3d->viewquat); + mul_qt_v3(view_inv, pan_vec); + + /* move center of view opposite of hand motion (this is camera mode, not object mode) */ + sub_v3_v3(rv3d->ofs, pan_vec); + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(area, region); + } + } +} + +static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, + ScrArea *area, + ARegion *region, + ViewOpsData *vod, + const bool apply_dyn_ofs) +{ + View3D *v3d = area->spacedata.first; + RegionView3D *rv3d = region->regiondata; + + float view_inv[4]; + + BLI_assert((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0); + + ED_view3d_persp_ensure(vod->depsgraph, v3d, region); + + rv3d->view = RV3D_VIEW_USER; + + invert_qt_qt_normalized(view_inv, rv3d->viewquat); + + if (U.ndof_flag & NDOF_TURNTABLE) { + float rot[3]; + + /* Turntable view code adapted for 3D mouse use. */ + float angle, quat[4]; + float xvec[3] = {1, 0, 0}; + + /* only use XY, ignore Z */ + WM_event_ndof_rotate_get(ndof, rot); + + /* Determine the direction of the x vector (for rotating up and down) */ + mul_qt_v3(view_inv, xvec); + + /* Perform the up/down rotation */ + angle = ndof->dt * rot[0]; + axis_angle_to_quat(quat, xvec, angle); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); + + /* Perform the orbital rotation */ + angle = ndof->dt * rot[1]; + + /* Update the onscreen axis-angle indicator. */ + rv3d->rot_angle = angle; + rv3d->rot_axis[0] = 0; + rv3d->rot_axis[1] = 0; + rv3d->rot_axis[2] = 1; + + axis_angle_to_quat_single(quat, 'Z', angle); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); + } + else { + float quat[4]; + float axis[3]; + float angle = WM_event_ndof_to_axis_angle(ndof, axis); + + /* transform rotation axis from view to world coordinates */ + mul_qt_v3(view_inv, axis); + + /* Update the onscreen axis-angle indicator. */ + rv3d->rot_angle = angle; + copy_v3_v3(rv3d->rot_axis, axis); + + axis_angle_to_quat(quat, axis, angle); + + /* apply rotation */ + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); + } + + if (apply_dyn_ofs) { + viewrotate_apply_dyn_ofs(vod, rv3d->viewquat); + } +} + +void view3d_ndof_fly(const wmNDOFMotionData *ndof, + View3D *v3d, + RegionView3D *rv3d, + const bool use_precision, + const short protectflag, + bool *r_has_translate, + bool *r_has_rotate) +{ + bool has_translate = ndof_has_translate(ndof, v3d, rv3d); + bool has_rotate = ndof_has_rotate(ndof, rv3d); + + float view_inv[4]; + invert_qt_qt_normalized(view_inv, rv3d->viewquat); + + rv3d->rot_angle = 0.0f; /* Disable onscreen rotation indicator. */ + + if (has_translate) { + /* ignore real 'dist' since fly has its own speed settings, + * also its overwritten at this point. */ + float speed = view3d_ndof_pan_speed_calc_from_dist(rv3d, 1.0f); + float trans[3], trans_orig_y; + + if (use_precision) { + speed *= 0.2f; + } + + WM_event_ndof_pan_get(ndof, trans, false); + mul_v3_fl(trans, speed * ndof->dt); + trans_orig_y = trans[1]; + + if (U.ndof_flag & NDOF_FLY_HELICOPTER) { + trans[1] = 0.0f; + } + + /* transform motion from view to world coordinates */ + mul_qt_v3(view_inv, trans); + + if (U.ndof_flag & NDOF_FLY_HELICOPTER) { + /* replace world z component with device y (yes it makes sense) */ + trans[2] = trans_orig_y; + } + + if (rv3d->persp == RV3D_CAMOB) { + /* respect camera position locks */ + if (protectflag & OB_LOCK_LOCX) { + trans[0] = 0.0f; + } + if (protectflag & OB_LOCK_LOCY) { + trans[1] = 0.0f; + } + if (protectflag & OB_LOCK_LOCZ) { + trans[2] = 0.0f; + } + } + + if (!is_zero_v3(trans)) { + /* move center of view opposite of hand motion + * (this is camera mode, not object mode) */ + sub_v3_v3(rv3d->ofs, trans); + has_translate = true; + } + else { + has_translate = false; + } + } + + if (has_rotate) { + const float turn_sensitivity = 1.0f; + + float rotation[4]; + float axis[3]; + float angle = turn_sensitivity * WM_event_ndof_to_axis_angle(ndof, axis); + + if (fabsf(angle) > 0.0001f) { + has_rotate = true; + + if (use_precision) { + angle *= 0.2f; + } + + /* transform rotation axis from view to world coordinates */ + mul_qt_v3(view_inv, axis); + + /* apply rotation to view */ + axis_angle_to_quat(rotation, axis, angle); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); + + if (U.ndof_flag & NDOF_LOCK_HORIZON) { + /* force an upright viewpoint + * TODO: make this less... sudden */ + float view_horizon[3] = {1.0f, 0.0f, 0.0f}; /* view +x */ + float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */ + + /* find new inverse since viewquat has changed */ + invert_qt_qt_normalized(view_inv, rv3d->viewquat); + /* could apply reverse rotation to existing view_inv to save a few cycles */ + + /* transform view vectors to world coordinates */ + mul_qt_v3(view_inv, view_horizon); + mul_qt_v3(view_inv, view_direction); + + /* find difference between view & world horizons + * true horizon lives in world xy plane, so look only at difference in z */ + angle = -asinf(view_horizon[2]); + + /* rotate view so view horizon = world horizon */ + axis_angle_to_quat(rotation, view_direction, angle); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); + } + + rv3d->view = RV3D_VIEW_USER; + } + else { + has_rotate = false; + } + } + + *r_has_translate = has_translate; + *r_has_rotate = has_rotate; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Orbit/Translate Operator + * \{ */ + +static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (event->type != NDOF_MOTION) { + return OPERATOR_CANCELLED; + } + + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ViewOpsData *vod; + View3D *v3d; + RegionView3D *rv3d; + char xform_flag = 0; + + const wmNDOFMotionData *ndof = event->customdata; + + vod = op->customdata = viewops_data_create( + C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_DEPTH_NAVIGATE)); + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + v3d = vod->v3d; + rv3d = vod->rv3d; + + /* off by default, until changed later this function */ + rv3d->rot_angle = 0.0f; + + ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); + + if (ndof->progress != P_FINISHING) { + const bool has_rotation = ndof_has_rotate(ndof, rv3d); + /* if we can't rotate, fallback to translate (locked axis views) */ + const bool has_translate = ndof_has_translate(ndof, v3d, rv3d) && + (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION); + const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp; + + if (has_translate || has_zoom) { + view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom); + xform_flag |= HAS_TRANSLATE; + } + + if (has_rotation) { + view3d_ndof_orbit(ndof, vod->area, vod->region, vod, true); + xform_flag |= HAS_ROTATE; + } + } + + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + if (xform_flag) { + ED_view3d_camera_lock_autokey( + v3d, rv3d, C, xform_flag & HAS_ROTATE, xform_flag & HAS_TRANSLATE); + } + + ED_region_tag_redraw(vod->region); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "NDOF Orbit View"; + ot->description = "Orbit the view using the 3D mouse"; + ot->idname = "VIEW3D_OT_ndof_orbit"; + + /* api callbacks */ + ot->invoke = ndof_orbit_invoke; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Orbit/Zoom Operator + * \{ */ + +static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (event->type != NDOF_MOTION) { + return OPERATOR_CANCELLED; + } + + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ViewOpsData *vod; + View3D *v3d; + RegionView3D *rv3d; + char xform_flag = 0; + + const wmNDOFMotionData *ndof = event->customdata; + + vod = op->customdata = viewops_data_create( + C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_DEPTH_NAVIGATE)); + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + v3d = vod->v3d; + rv3d = vod->rv3d; + + /* off by default, until changed later this function */ + rv3d->rot_angle = 0.0f; + + ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); + + if (ndof->progress == P_FINISHING) { + /* pass */ + } + else if ((rv3d->persp == RV3D_ORTHO) && RV3D_VIEW_IS_AXIS(rv3d->view)) { + /* if we can't rotate, fallback to translate (locked axis views) */ + const bool has_translate = ndof_has_translate(ndof, v3d, rv3d); + const bool has_zoom = (ndof->tvec[2] != 0.0f) && ED_view3d_offset_lock_check(v3d, rv3d); + + if (has_translate || has_zoom) { + view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, true); + xform_flag |= HAS_TRANSLATE; + } + } + else { + /* NOTE: based on feedback from T67579, users want to have pan and orbit enabled at once. + * It's arguable that orbit shouldn't pan (since we have a pan only operator), + * so if there are users who like to separate orbit/pan operations - it can be a preference. */ + const bool is_orbit_around_pivot = (U.ndof_flag & NDOF_MODE_ORBIT) || + ED_view3d_offset_lock_check(v3d, rv3d); + const bool has_rotation = ndof_has_rotate(ndof, rv3d); + bool has_translate, has_zoom; + + if (is_orbit_around_pivot) { + /* Orbit preference or forced lock (Z zooms). */ + has_translate = !is_zero_v2(ndof->tvec) && ndof_has_translate(ndof, v3d, rv3d); + has_zoom = (ndof->tvec[2] != 0.0f); + } + else { + /* Free preference (Z translates). */ + has_translate = ndof_has_translate(ndof, v3d, rv3d); + has_zoom = false; + } + + /* Rotation first because dynamic offset resets offset otherwise (and disables panning). */ + if (has_rotation) { + const float dist_backup = rv3d->dist; + if (!is_orbit_around_pivot) { + ED_view3d_distance_set(rv3d, 0.0f); + } + view3d_ndof_orbit(ndof, vod->area, vod->region, vod, is_orbit_around_pivot); + xform_flag |= HAS_ROTATE; + if (!is_orbit_around_pivot) { + ED_view3d_distance_set(rv3d, dist_backup); + } + } + + if (has_translate || has_zoom) { + view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom); + xform_flag |= HAS_TRANSLATE; + } + } + + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + if (xform_flag) { + ED_view3d_camera_lock_autokey( + v3d, rv3d, C, xform_flag & HAS_ROTATE, xform_flag & HAS_TRANSLATE); + } + + ED_region_tag_redraw(vod->region); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "NDOF Orbit View with Zoom"; + ot->description = "Orbit and zoom the view using the 3D mouse"; + ot->idname = "VIEW3D_OT_ndof_orbit_zoom"; + + /* api callbacks */ + ot->invoke = ndof_orbit_zoom_invoke; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Pan/Zoom Operator + * \{ */ + +static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + if (event->type != NDOF_MOTION) { + return OPERATOR_CANCELLED; + } + + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + const wmNDOFMotionData *ndof = event->customdata; + char xform_flag = 0; + + const bool has_translate = ndof_has_translate(ndof, v3d, rv3d); + const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp; + + /* we're panning here! so erase any leftover rotation from other operators */ + rv3d->rot_angle = 0.0f; + + if (!(has_translate || has_zoom)) { + return OPERATOR_CANCELLED; + } + + ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); + + if (ndof->progress != P_FINISHING) { + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + + if (has_translate || has_zoom) { + view3d_ndof_pan_zoom(ndof, area, region, has_translate, has_zoom); + xform_flag |= HAS_TRANSLATE; + } + } + + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + if (xform_flag) { + ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, xform_flag & HAS_TRANSLATE); + } + + ED_region_tag_redraw(CTX_wm_region(C)); + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "NDOF Pan View"; + ot->description = "Pan the view with the 3D mouse"; + ot->idname = "VIEW3D_OT_ndof_pan"; + + /* api callbacks */ + ot->invoke = ndof_pan_invoke; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Transform All Operator + * \{ */ + +/** + * wraps #ndof_orbit_zoom but never restrict to orbit. + */ +static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* weak!, but it works */ + const int ndof_flag = U.ndof_flag; + int ret; + + U.ndof_flag &= ~NDOF_MODE_ORBIT; + + ret = ndof_orbit_zoom_invoke(C, op, event); + + U.ndof_flag = ndof_flag; + + return ret; +} + +void VIEW3D_OT_ndof_all(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "NDOF Transform View"; + ot->description = "Pan and rotate the view with the 3D mouse"; + ot->idname = "VIEW3D_OT_ndof_all"; + + /* api callbacks */ + ot->invoke = ndof_all_invoke; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} + +#endif /* WITH_INPUT_NDOF */ + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_roll.c b/source/blender/editors/space_view3d/view3d_navigate_roll.c new file mode 100644 index 00000000000..c9bfdc4412a --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_roll.c @@ -0,0 +1,292 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "BLI_blenlib.h" +#include "BLI_dial_2d.h" +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "WM_api.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Roll Operator + * \{ */ + +static void view_roll_angle( + ARegion *region, float quat[4], const float orig_quat[4], const float dvec[3], float angle) +{ + RegionView3D *rv3d = region->regiondata; + float quat_mul[4]; + + /* camera axis */ + axis_angle_normalized_to_quat(quat_mul, dvec, angle); + + mul_qt_qtqt(quat, orig_quat, quat_mul); + + /* avoid precision loss over time */ + normalize_qt(quat); + + rv3d->view = RV3D_VIEW_USER; +} + +static void viewroll_apply(ViewOpsData *vod, int x, int y) +{ + float angle = BLI_dial_angle(vod->init.dial, (const float[2]){x, y}); + + if (angle != 0.0f) { + view_roll_angle(vod->region, vod->rv3d->viewquat, vod->init.quat, vod->init.mousevec, angle); + } + + if (vod->use_dyn_ofs) { + view3d_orbit_apply_dyn_ofs( + vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs); + } + + if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(vod->area, vod->region); + } + + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); + + ED_region_tag_redraw(vod->region); +} + +static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + bool use_autokey = false; + int ret = OPERATOR_RUNNING_MODAL; + + /* execute the events */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_MOVE: + WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ROTATE: + WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) { + /* Note this does not remove auto-keys on locked cameras. */ + copy_qt_qt(vod->rv3d->viewquat, vod->init.quat); + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); + viewops_data_free(C, op->customdata); + op->customdata = NULL; + return OPERATOR_CANCELLED; + } + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + viewroll_apply(vod, event->xy[0], event->xy[1]); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } + } + else if (event_code == VIEW_CONFIRM) { + use_autokey = true; + ret = OPERATOR_FINISHED; + } + + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false); + } + + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op->customdata); + op->customdata = NULL; + } + + return ret; +} + +enum { + V3D_VIEW_STEPLEFT = 1, + V3D_VIEW_STEPRIGHT, +}; + +static const EnumPropertyItem prop_view_roll_items[] = { + {0, "ANGLE", 0, "Roll Angle", "Roll the view using an angle value"}, + {V3D_VIEW_STEPLEFT, "LEFT", 0, "Roll Left", "Roll the view around to the left"}, + {V3D_VIEW_STEPRIGHT, "RIGHT", 0, "Roll Right", "Roll the view around to the right"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int viewroll_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + RegionView3D *rv3d; + ARegion *region; + + if (op->customdata) { + ViewOpsData *vod = op->customdata; + region = vod->region; + v3d = vod->v3d; + } + else { + ED_view3d_context_user_region(C, &v3d, ®ion); + } + + rv3d = region->regiondata; + if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { + + ED_view3d_smooth_view_force_finish(C, v3d, region); + + int type = RNA_enum_get(op->ptr, "type"); + float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF(U.pad_rot_angle); + float mousevec[3]; + float quat_new[4]; + + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + if (type == V3D_VIEW_STEPLEFT) { + angle = -angle; + } + + normalize_v3_v3(mousevec, rv3d->viewinv[2]); + negate_v3(mousevec); + view_roll_angle(region, quat_new, rv3d->viewquat, mousevec, angle); + + const float *dyn_ofs_pt = NULL; + float dyn_ofs[3]; + if (U.uiflag & USER_ORBIT_SELECTION) { + if (view3d_orbit_calc_center(C, dyn_ofs)) { + negate_v3(dyn_ofs); + dyn_ofs_pt = dyn_ofs; + } + } + + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .quat = quat_new, + .dyn_ofs = dyn_ofs_pt, + }); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + return OPERATOR_FINISHED; + } + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + return OPERATOR_CANCELLED; +} + +static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + bool use_angle = RNA_enum_get(op->ptr, "type") != 0; + + if (use_angle || RNA_struct_property_is_set(op->ptr, "angle")) { + viewroll_exec(C, op); + } + else { + /* makes op->customdata */ + vod = op->customdata = viewops_data_create(C, event, viewops_flag_from_prefs()); + vod->init.dial = BLI_dial_init((const float[2]){BLI_rcti_cent_x(&vod->region->winrct), + BLI_rcti_cent_y(&vod->region->winrct)}, + FLT_EPSILON); + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + /* overwrite the mouse vector with the view direction */ + normalize_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + negate_v3(vod->init.mousevec); + + if (event->type == MOUSEROTATE) { + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0]; + viewroll_apply(vod, event->prev_xy[0], event->prev_xy[1]); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + return OPERATOR_FINISHED; + } + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; + } + return OPERATOR_FINISHED; +} + +static void viewroll_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op->customdata); + op->customdata = NULL; +} + +void VIEW3D_OT_view_roll(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "View Roll"; + ot->description = "Roll the view"; + ot->idname = "VIEW3D_OT_view_roll"; + + /* api callbacks */ + ot->invoke = viewroll_invoke; + ot->exec = viewroll_exec; + ot->modal = viewroll_modal; + ot->poll = ED_operator_rv3d_user_region_poll; + ot->cancel = viewroll_cancel; + + /* flags */ + ot->flag = 0; + + /* properties */ + ot->prop = prop = RNA_def_float( + ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, + "type", + prop_view_roll_items, + 0, + "Roll Angle Source", + "How roll angle is calculated"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_rotate.c b/source/blender/editors/space_view3d/view3d_navigate_rotate.c new file mode 100644 index 00000000000..c3730b3b3b1 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_rotate.c @@ -0,0 +1,452 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "WM_api.h" + +#include "RNA_access.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Rotate Operator + * \{ */ + +void viewrotate_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Axis Snap", ""}, + {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Axis Snap (Off)", ""}, + + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, + {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, + + {0, NULL, 0, NULL, NULL}, + }; + + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Rotate Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, "View3D Rotate Modal", modal_items); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate"); +} + +static void viewrotate_apply_snap(ViewOpsData *vod) +{ + const float axis_limit = DEG2RADF(45 / 3); + + RegionView3D *rv3d = vod->rv3d; + + float viewquat_inv[4]; + float zaxis[3] = {0, 0, 1}; + float zaxis_best[3]; + int x, y, z; + bool found = false; + + invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat); + + mul_qt_v3(viewquat_inv, zaxis); + normalize_v3(zaxis); + + for (x = -1; x < 2; x++) { + for (y = -1; y < 2; y++) { + for (z = -1; z < 2; z++) { + if (x || y || z) { + float zaxis_test[3] = {x, y, z}; + + normalize_v3(zaxis_test); + + if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) { + copy_v3_v3(zaxis_best, zaxis_test); + found = true; + } + } + } + } + } + + if (found) { + + /* find the best roll */ + float quat_roll[4], quat_final[4], quat_best[4], quat_snap[4]; + float viewquat_align[4]; /* viewquat aligned to zaxis_best */ + float viewquat_align_inv[4]; /* viewquat aligned to zaxis_best */ + float best_angle = axis_limit; + int j; + + /* viewquat_align is the original viewquat aligned to the snapped axis + * for testing roll */ + rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis); + normalize_qt(viewquat_align); + mul_qt_qtqt(viewquat_align, vod->curr.viewquat, viewquat_align); + normalize_qt(viewquat_align); + invert_qt_qt_normalized(viewquat_align_inv, viewquat_align); + + vec_to_quat(quat_snap, zaxis_best, OB_NEGZ, OB_POSY); + normalize_qt(quat_snap); + invert_qt_normalized(quat_snap); + + /* check if we can find the roll */ + found = false; + + /* find best roll */ + for (j = 0; j < 8; j++) { + float angle; + float xaxis1[3] = {1, 0, 0}; + float xaxis2[3] = {1, 0, 0}; + float quat_final_inv[4]; + + axis_angle_to_quat(quat_roll, zaxis_best, (float)j * DEG2RADF(45.0f)); + normalize_qt(quat_roll); + + mul_qt_qtqt(quat_final, quat_snap, quat_roll); + normalize_qt(quat_final); + + /* compare 2 vector angles to find the least roll */ + invert_qt_qt_normalized(quat_final_inv, quat_final); + mul_qt_v3(viewquat_align_inv, xaxis1); + mul_qt_v3(quat_final_inv, xaxis2); + angle = angle_v3v3(xaxis1, xaxis2); + + if (angle <= best_angle) { + found = true; + best_angle = angle; + copy_qt_qt(quat_best, quat_final); + } + } + + if (found) { + /* lock 'quat_best' to an axis view if we can */ + ED_view3d_quat_to_axis_view(quat_best, 0.01f, &rv3d->view, &rv3d->view_axis_roll); + if (rv3d->view != RV3D_VIEW_USER) { + ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, quat_best); + } + } + else { + copy_qt_qt(quat_best, viewquat_align); + } + + copy_qt_qt(rv3d->viewquat, quat_best); + + viewrotate_apply_dyn_ofs(vod, rv3d->viewquat); + + if (U.uiflag & USER_AUTOPERSP) { + if (RV3D_VIEW_IS_AXIS(rv3d->view)) { + if (rv3d->persp == RV3D_PERSP) { + rv3d->persp = RV3D_ORTHO; + } + } + } + } + else if (U.uiflag & USER_AUTOPERSP) { + rv3d->persp = vod->init.persp; + } +} + +static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2]) +{ + RegionView3D *rv3d = vod->rv3d; + + rv3d->view = RV3D_VIEW_USER; /* need to reset every time because of view snapping */ + + if (U.flag & USER_TRACKBALL) { + float axis[3], q1[4], dvec[3], newvec[3]; + float angle; + + { + const int event_xy_offset[2] = { + event_xy[0] + vod->init.event_xy_offset[0], + event_xy[1] + vod->init.event_xy_offset[1], + }; + calctrackballvec(&vod->region->winrct, event_xy_offset, newvec); + } + + sub_v3_v3v3(dvec, newvec, vod->init.trackvec); + + angle = (len_v3(dvec) / (2.0f * V3D_OP_TRACKBALLSIZE)) * (float)M_PI; + + /* Before applying the sensitivity this is rotating 1:1, + * where the cursor would match the surface of a sphere in the view. */ + angle *= U.view_rotate_sensitivity_trackball; + + /* Allow for rotation beyond the interval [-pi, pi] */ + angle = angle_wrap_rad(angle); + + /* This relation is used instead of the actual angle between vectors + * so that the angle of rotation is linearly proportional to + * the distance that the mouse is dragged. */ + + cross_v3_v3v3(axis, vod->init.trackvec, newvec); + axis_angle_to_quat(q1, axis, angle); + + mul_qt_qtqt(vod->curr.viewquat, q1, vod->init.quat); + + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); + } + else { + float quat_local_x[4], quat_global_z[4]; + float m[3][3]; + float m_inv[3][3]; + const float zvec_global[3] = {0.0f, 0.0f, 1.0f}; + float xaxis[3]; + + /* Radians per-pixel. */ + const float sensitivity = U.view_rotate_sensitivity_turntable / U.dpi_fac; + + /* Get the 3x3 matrix and its inverse from the quaternion */ + quat_to_mat3(m, vod->curr.viewquat); + invert_m3_m3(m_inv, m); + + /* Avoid Gimbal Lock + * + * Even though turn-table mode is in use, this can occur when the user exits the camera view + * or when aligning the view to a rotated object. + * + * We have gimbal lock when the user's view is rotated +/- 90 degrees along the view axis. + * In this case the vertical rotation is the same as the sideways turntable motion. + * Making it impossible to get out of the gimbal locked state without resetting the view. + * + * The logic below lets the user exit out of this state without any abrupt 'fix' + * which would be disorienting. + * + * This works by blending two horizons: + * - Rotated-horizon: `cross_v3_v3v3(xaxis, zvec_global, m_inv[2])` + * When only this is used, this turntable rotation works - but it's side-ways + * (as if the entire turn-table has been placed on its side) + * While there is no gimbal lock, it's also awkward to use. + * - Un-rotated-horizon: `m_inv[0]` + * When only this is used, the turntable rotation can have gimbal lock. + * + * The solution used here is to blend between these two values, + * so the severity of the gimbal lock is used to blend the rotated horizon. + * Blending isn't essential, it just makes the transition smoother. + * + * This allows sideways turn-table rotation on a Z axis that isn't world-space Z, + * While up-down turntable rotation eventually corrects gimbal lock. */ +#if 1 + if (len_squared_v3v3(zvec_global, m_inv[2]) > 0.001f) { + float fac; + cross_v3_v3v3(xaxis, zvec_global, m_inv[2]); + if (dot_v3v3(xaxis, m_inv[0]) < 0) { + negate_v3(xaxis); + } + fac = angle_normalized_v3v3(zvec_global, m_inv[2]) / (float)M_PI; + fac = fabsf(fac - 0.5f) * 2; + fac = fac * fac; + interp_v3_v3v3(xaxis, xaxis, m_inv[0], fac); + } + else { + copy_v3_v3(xaxis, m_inv[0]); + } +#else + copy_v3_v3(xaxis, m_inv[0]); +#endif + + /* Determine the direction of the x vector (for rotating up and down) */ + /* This can likely be computed directly from the quaternion. */ + + /* Perform the up/down rotation */ + axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(event_xy[1] - vod->prev.event_xy[1])); + mul_qt_qtqt(quat_local_x, vod->curr.viewquat, quat_local_x); + + /* Perform the orbital rotation */ + axis_angle_to_quat_single( + quat_global_z, 'Z', sensitivity * vod->reverse * (event_xy[0] - vod->prev.event_xy[0])); + mul_qt_qtqt(vod->curr.viewquat, quat_local_x, quat_global_z); + + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); + } + + /* avoid precision loss over time */ + normalize_qt(vod->curr.viewquat); + + /* use a working copy so view rotation locking doesn't overwrite the locked + * rotation back into the view we calculate with */ + copy_qt_qt(rv3d->viewquat, vod->curr.viewquat); + + /* Check for view snap, + * NOTE: don't apply snap to `vod->viewquat` so the view won't jam up. */ + if (vod->axis_snap) { + viewrotate_apply_snap(vod); + } + vod->prev.event_xy[0] = event_xy[0]; + vod->prev.event_xy[1] = event_xy[1]; + + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, rv3d); + + ED_region_tag_redraw(vod->region); +} + +static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + bool use_autokey = false; + int ret = OPERATOR_RUNNING_MODAL; + + /* execute the events */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_AXIS_SNAP_ENABLE: + vod->axis_snap = true; + event_code = VIEW_APPLY; + break; + case VIEWROT_MODAL_AXIS_SNAP_DISABLE: + vod->rv3d->persp = vod->init.persp; + vod->axis_snap = false; + event_code = VIEW_APPLY; + break; + case VIEWROT_MODAL_SWITCH_ZOOM: + WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_MOVE: + WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + viewrotate_apply(vod, event->xy); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } + } + else if (event_code == VIEW_CONFIRM) { + use_autokey = true; + ret = OPERATOR_FINISHED; + } + + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true); + } + + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op->customdata); + op->customdata = NULL; + } + + return ret; +} + +static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + /* makes op->customdata */ + vod = op->customdata = viewops_data_create( + C, + event, + viewops_flag_from_prefs() | VIEWOPS_FLAG_PERSP_ENSURE | + (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) { + /* Rotate direction we keep always same */ + int event_xy[2]; + + if (event->type == MOUSEPAN) { + if (event->is_direction_inverted) { + event_xy[0] = 2 * event->xy[0] - event->prev_xy[0]; + event_xy[1] = 2 * event->xy[1] - event->prev_xy[1]; + } + else { + copy_v2_v2_int(event_xy, event->prev_xy); + } + } + else { + /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ + copy_v2_v2_int(event_xy, event->prev_xy); + } + + viewrotate_apply(vod, event_xy); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + + return OPERATOR_FINISHED; + } + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static void viewrotate_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op->customdata); + op->customdata = NULL; +} + +void VIEW3D_OT_rotate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Rotate View"; + ot->description = "Rotate the view"; + ot->idname = "VIEW3D_OT_rotate"; + + /* api callbacks */ + ot->invoke = viewrotate_invoke; + ot->modal = viewrotate_modal; + ot->poll = view3d_rotation_poll; + ot->cancel = viewrotate_cancel; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; + + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c new file mode 100644 index 00000000000..aeffb520b0a --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c @@ -0,0 +1,406 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "DNA_camera_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth View Operator & Utilities + * + * Use for view transitions to have smooth (animated) transitions. + * \{ */ + +/* This operator is one of the 'timer refresh' ones like animation playback */ + +struct SmoothView3DState { + float dist; + float lens; + float quat[4]; + float ofs[3]; +}; + +struct SmoothView3DStore { + /* Source. */ + struct SmoothView3DState src; /* source */ + struct SmoothView3DState dst; /* destination */ + struct SmoothView3DState org; /* original */ + + bool to_camera; + + bool use_dyn_ofs; + float dyn_ofs[3]; + + /* When smooth-view is enabled, store the 'rv3d->view' here, + * assign back when the view motion is completed. */ + char org_view; + + double time_allowed; +}; + +static void view3d_smooth_view_state_backup(struct SmoothView3DState *sms_state, + const View3D *v3d, + const RegionView3D *rv3d) +{ + copy_v3_v3(sms_state->ofs, rv3d->ofs); + copy_qt_qt(sms_state->quat, rv3d->viewquat); + sms_state->dist = rv3d->dist; + sms_state->lens = v3d->lens; +} + +static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms_state, + View3D *v3d, + RegionView3D *rv3d) +{ + copy_v3_v3(rv3d->ofs, sms_state->ofs); + copy_qt_qt(rv3d->viewquat, sms_state->quat); + rv3d->dist = sms_state->dist; + v3d->lens = sms_state->lens; +} + +/* will start timer if appropriate */ +void ED_view3d_smooth_view_ex( + /* avoid passing in the context */ + const Depsgraph *depsgraph, + wmWindowManager *wm, + wmWindow *win, + ScrArea *area, + View3D *v3d, + ARegion *region, + const int smooth_viewtx, + const V3D_SmoothParams *sview) +{ + RegionView3D *rv3d = region->regiondata; + struct SmoothView3DStore sms = {{0}}; + + /* initialize sms */ + view3d_smooth_view_state_backup(&sms.dst, v3d, rv3d); + view3d_smooth_view_state_backup(&sms.src, v3d, rv3d); + /* If smooth-view runs multiple times. */ + if (rv3d->sms == NULL) { + view3d_smooth_view_state_backup(&sms.org, v3d, rv3d); + } + else { + sms.org = rv3d->sms->org; + } + sms.org_view = rv3d->view; + + /* sms.to_camera = false; */ /* initialized to zero anyway */ + + /* note on camera locking, this is a little confusing but works ok. + * we may be changing the view 'as if' there is no active camera, but in fact + * there is an active camera which is locked to the view. + * + * In the case where smooth view is moving _to_ a camera we don't want that + * camera to be moved or changed, so only when the camera is not being set should + * we allow camera option locking to initialize the view settings from the camera. + */ + if (sview->camera == NULL && sview->camera_old == NULL) { + ED_view3d_camera_lock_init(depsgraph, v3d, rv3d); + } + + /* store the options we want to end with */ + if (sview->ofs) { + copy_v3_v3(sms.dst.ofs, sview->ofs); + } + if (sview->quat) { + copy_qt_qt(sms.dst.quat, sview->quat); + } + if (sview->dist) { + sms.dst.dist = *sview->dist; + } + if (sview->lens) { + sms.dst.lens = *sview->lens; + } + + if (sview->dyn_ofs) { + BLI_assert(sview->ofs == NULL); + BLI_assert(sview->quat != NULL); + + copy_v3_v3(sms.dyn_ofs, sview->dyn_ofs); + sms.use_dyn_ofs = true; + + /* calculate the final destination offset */ + view3d_orbit_apply_dyn_ofs(sms.dst.ofs, sms.src.ofs, sms.src.quat, sms.dst.quat, sms.dyn_ofs); + } + + if (sview->camera) { + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); + if (sview->ofs != NULL) { + sms.dst.dist = ED_view3d_offset_distance( + ob_camera_eval->obmat, sview->ofs, VIEW3D_DIST_FALLBACK); + } + ED_view3d_from_object(ob_camera_eval, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens); + sms.to_camera = true; /* restore view3d values in end */ + } + + if ((sview->camera_old == sview->camera) && /* Camera. */ + (sms.dst.dist == rv3d->dist) && /* Distance. */ + (sms.dst.lens == v3d->lens) && /* Lens. */ + equals_v3v3(sms.dst.ofs, rv3d->ofs) && /* Offset. */ + equals_v4v4(sms.dst.quat, rv3d->viewquat) /* Rotation. */ + ) { + /* Early return if nothing changed. */ + return; + } + + /* Skip smooth viewing for external render engine draw. */ + if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) { + + /* original values */ + if (sview->camera_old) { + Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old); + if (sview->ofs != NULL) { + sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f); + } + ED_view3d_from_object( + ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens); + } + /* grid draw as floor */ + if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) { + /* use existing if exists, means multiple calls to smooth view + * won't lose the original 'view' setting */ + rv3d->view = RV3D_VIEW_USER; + } + + sms.time_allowed = (double)smooth_viewtx / 1000.0; + + /* If this is view rotation only we can decrease the time allowed by the angle between quats + * this means small rotations won't lag. */ + if (sview->quat && !sview->ofs && !sview->dist) { + /* scale the time allowed by the rotation */ + /* 180deg == 1.0 */ + sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) / + M_PI; + } + + /* ensure it shows correct */ + if (sms.to_camera) { + /* use ortho if we move from an ortho view to an ortho camera */ + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); + rv3d->persp = (((rv3d->is_persp == false) && (ob_camera_eval->type == OB_CAMERA) && + (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ? + RV3D_ORTHO : + RV3D_PERSP); + } + + rv3d->rflag |= RV3D_NAVIGATING; + + /* not essential but in some cases the caller will tag the area for redraw, and in that + * case we can get a flicker of the 'org' user view but we want to see 'src' */ + view3d_smooth_view_state_restore(&sms.src, v3d, rv3d); + + /* keep track of running timer! */ + if (rv3d->sms == NULL) { + rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d"); + } + *rv3d->sms = sms; + if (rv3d->smooth_timer) { + WM_event_remove_timer(wm, win, rv3d->smooth_timer); + } + /* #TIMER1 is hard-coded in key-map. */ + rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0); + } + else { + /* Animation is disabled, apply immediately. */ + if (sms.to_camera == false) { + copy_v3_v3(rv3d->ofs, sms.dst.ofs); + copy_qt_qt(rv3d->viewquat, sms.dst.quat); + rv3d->dist = sms.dst.dist; + v3d->lens = sms.dst.lens; + + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + } + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_copy(area, region); + } + + ED_region_tag_redraw(region); + + WM_event_add_mousemove(win); + } +} + +void ED_view3d_smooth_view(bContext *C, + View3D *v3d, + ARegion *region, + const int smooth_viewtx, + const struct V3D_SmoothParams *sview) +{ + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + ScrArea *area = CTX_wm_area(C); + + ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, sview); +} + +/* only meant for timer usage */ +static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, bool sync_boxview) +{ + wmWindowManager *wm = CTX_wm_manager(C); + RegionView3D *rv3d = region->regiondata; + struct SmoothView3DStore *sms = rv3d->sms; + float step, step_inv; + + if (sms->time_allowed != 0.0) { + step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed); + } + else { + step = 1.0f; + } + + /* end timer */ + if (step >= 1.0f) { + wmWindow *win = CTX_wm_window(C); + + /* if we went to camera, store the original */ + if (sms->to_camera) { + rv3d->persp = RV3D_CAMOB; + view3d_smooth_view_state_restore(&sms->org, v3d, rv3d); + } + else { + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + + view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d); + + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); + } + + if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) { + rv3d->view = sms->org_view; + } + + MEM_freeN(rv3d->sms); + rv3d->sms = NULL; + + WM_event_remove_timer(wm, win, rv3d->smooth_timer); + rv3d->smooth_timer = NULL; + rv3d->rflag &= ~RV3D_NAVIGATING; + + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(win); + } + else { + /* ease in/out */ + step = (3.0f * step * step - 2.0f * step * step * step); + + step_inv = 1.0f - step; + + interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, step); + + if (sms->use_dyn_ofs) { + view3d_orbit_apply_dyn_ofs( + rv3d->ofs, sms->src.ofs, sms->src.quat, rv3d->viewquat, sms->dyn_ofs); + } + else { + interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, step); + } + + rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv; + v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv; + + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + if (ED_screen_animation_playing(wm)) { + ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); + } + } + + if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) { + view3d_boxview_copy(CTX_wm_area(C), region); + } + + /* NOTE: this doesn't work right because the v3d->lens is now used in ortho mode r51636, + * when switching camera in quad-view the other ortho views would zoom & reset. + * + * For now only redraw all regions when smooth-view finishes. + */ + if (step >= 1.0f) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + } + else { + ED_region_tag_redraw(region); + } +} + +static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + View3D *v3d = CTX_wm_view3d(C); + ARegion *region = CTX_wm_region(C); + RegionView3D *rv3d = region->regiondata; + + /* escape if not our timer */ + if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata) { + return OPERATOR_PASS_THROUGH; + } + + view3d_smoothview_apply(C, v3d, region, true); + + return OPERATOR_FINISHED; +} + +void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region) +{ + RegionView3D *rv3d = region->regiondata; + + if (rv3d && rv3d->sms) { + rv3d->sms->time_allowed = 0.0; /* force finishing */ + view3d_smoothview_apply(C, v3d, region, false); + + /* force update of view matrix so tools that run immediately after + * can use them without redrawing first */ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ED_view3d_update_viewmat(depsgraph, scene, v3d, region, NULL, NULL, NULL, false); + } +} + +void VIEW3D_OT_smoothview(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Smooth View"; + ot->idname = "VIEW3D_OT_smoothview"; + + /* api callbacks */ + ot->invoke = view3d_smoothview_invoke; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; + + ot->poll = ED_operator_view3d_active; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c index ed76b10c95a..d72fa3cb90f 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_walk.c +++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c @@ -58,6 +58,7 @@ #include "DEG_depsgraph.h" #include "view3d_intern.h" /* own include */ +#include "view3d_navigate.h" #ifdef WITH_INPUT_NDOF //# define NDOF_WALK_DEBUG diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom.c b/source/blender/editors/space_view3d/view3d_navigate_zoom.c new file mode 100644 index 00000000000..a6c7d06c079 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_zoom.c @@ -0,0 +1,598 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "BLI_math.h" +#include "BLI_rect.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" + +#include "RNA_access.h" + +#include "ED_screen.h" + +#include "PIL_time.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Operator + * \{ */ + +/* #viewdolly_modal_keymap has an exact copy of this, apply fixes to both. */ +void viewzoom_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, + {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, + + {0, NULL, 0, NULL, NULL}, + }; + + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Zoom Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, "View3D Zoom Modal", modal_items); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); +} + +/** + * \param zoom_xy: Optionally zoom to window location + * (coords compatible w/ #wmEvent.xy). Use when not NULL. + */ +static void view_zoom_to_window_xy_camera(Scene *scene, + Depsgraph *depsgraph, + View3D *v3d, + ARegion *region, + float dfac, + const int zoom_xy[2]) +{ + RegionView3D *rv3d = region->regiondata; + const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); + const float zoomfac_new = clamp_f( + zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR); + const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new); + + if (zoom_xy != NULL) { + float zoomfac_px; + rctf camera_frame_old; + rctf camera_frame_new; + + const float pt_src[2] = {zoom_xy[0], zoom_xy[1]}; + float pt_dst[2]; + float delta_px[2]; + + ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_old, false); + BLI_rctf_translate(&camera_frame_old, region->winrct.xmin, region->winrct.ymin); + + rv3d->camzoom = camzoom_new; + CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); + + ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &camera_frame_new, false); + BLI_rctf_translate(&camera_frame_new, region->winrct.xmin, region->winrct.ymin); + + BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src); + sub_v2_v2v2(delta_px, pt_dst, pt_src); + + /* translate the camera offset using pixel space delta + * mapped back to the camera (same logic as panning in camera view) */ + zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f; + + rv3d->camdx += delta_px[0] / (region->winx * zoomfac_px); + rv3d->camdy += delta_px[1] / (region->winy * zoomfac_px); + CLAMP(rv3d->camdx, -1.0f, 1.0f); + CLAMP(rv3d->camdy, -1.0f, 1.0f); + } + else { + rv3d->camzoom = camzoom_new; + CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); + } +} + +/** + * \param zoom_xy: Optionally zoom to window location + * (coords compatible w/ #wmEvent.xy). Use when not NULL. + */ +static void view_zoom_to_window_xy_3d(ARegion *region, float dfac, const int zoom_xy[2]) +{ + RegionView3D *rv3d = region->regiondata; + const float dist_new = rv3d->dist * dfac; + + if (zoom_xy != NULL) { + float dvec[3]; + float tvec[3]; + float tpos[3]; + float mval_f[2]; + + float zfac; + + negate_v3_v3(tpos, rv3d->ofs); + + mval_f[0] = (float)(((zoom_xy[0] - region->winrct.xmin) * 2) - region->winx) / 2.0f; + mval_f[1] = (float)(((zoom_xy[1] - region->winrct.ymin) * 2) - region->winy) / 2.0f; + + /* Project cursor position into 3D space */ + zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL); + ED_view3d_win_to_delta(region, mval_f, dvec, zfac); + + /* Calculate view target position for dolly */ + add_v3_v3v3(tvec, tpos, dvec); + negate_v3(tvec); + + /* Offset to target position and dolly */ + copy_v3_v3(rv3d->ofs, tvec); + rv3d->dist = dist_new; + + /* Calculate final offset */ + madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac); + } + else { + rv3d->dist = dist_new; + } +} + +static float viewzoom_scale_value(const rcti *winrct, + const eViewZoom_Style viewzoom, + const bool zoom_invert, + const bool zoom_invert_force, + const int xy_curr[2], + const int xy_init[2], + const float val, + const float val_orig, + double *r_timer_lastdraw) +{ + float zfac; + + if (viewzoom == USER_ZOOM_CONTINUE) { + double time = PIL_check_seconds_timer(); + float time_step = (float)(time - *r_timer_lastdraw); + float fac; + + if (U.uiflag & USER_ZOOM_HORIZ) { + fac = (float)(xy_init[0] - xy_curr[0]); + } + else { + fac = (float)(xy_init[1] - xy_curr[1]); + } + + fac /= U.dpi_fac; + + if (zoom_invert != zoom_invert_force) { + fac = -fac; + } + + zfac = 1.0f + ((fac / 20.0f) * time_step); + *r_timer_lastdraw = time; + } + else if (viewzoom == USER_ZOOM_SCALE) { + /* method which zooms based on how far you move the mouse */ + + const int ctr[2] = { + BLI_rcti_cent_x(winrct), + BLI_rcti_cent_y(winrct), + }; + float len_new = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_curr) / U.dpi_fac); + float len_old = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_init) / U.dpi_fac); + + /* intentionally ignore 'zoom_invert' for scale */ + if (zoom_invert_force) { + SWAP(float, len_new, len_old); + } + + zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val; + } + else { /* USER_ZOOM_DOLLY */ + float len_new = 5 * U.dpi_fac; + float len_old = 5 * U.dpi_fac; + + if (U.uiflag & USER_ZOOM_HORIZ) { + len_new += (winrct->xmax - (xy_curr[0])) / U.dpi_fac; + len_old += (winrct->xmax - (xy_init[0])) / U.dpi_fac; + } + else { + len_new += (winrct->ymax - (xy_curr[1])) / U.dpi_fac; + len_old += (winrct->ymax - (xy_init[1])) / U.dpi_fac; + } + + if (zoom_invert != zoom_invert_force) { + SWAP(float, len_new, len_old); + } + + zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val; + } + + return zfac; +} + +static float viewzoom_scale_value_offset(const rcti *winrct, + const eViewZoom_Style viewzoom, + const bool zoom_invert, + const bool zoom_invert_force, + const int xy_curr[2], + const int xy_init[2], + const int xy_offset[2], + const float val, + const float val_orig, + double *r_timer_lastdraw) +{ + const int xy_curr_offset[2] = { + xy_curr[0] + xy_offset[0], + xy_curr[1] + xy_offset[1], + }; + const int xy_init_offset[2] = { + xy_init[0] + xy_offset[0], + xy_init[1] + xy_offset[1], + }; + return viewzoom_scale_value(winrct, + viewzoom, + zoom_invert, + zoom_invert_force, + xy_curr_offset, + xy_init_offset, + val, + val_orig, + r_timer_lastdraw); +} + +static void viewzoom_apply_camera(ViewOpsData *vod, + const int xy[2], + const eViewZoom_Style viewzoom, + const bool zoom_invert, + const bool zoom_to_pos) +{ + float zfac; + float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f; + float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; + + zfac = viewzoom_scale_value_offset(&vod->region->winrct, + viewzoom, + zoom_invert, + true, + xy, + vod->init.event_xy, + vod->init.event_xy_offset, + zoomfac, + zoomfac_prev, + &vod->prev.time); + + if (!ELEM(zfac, 1.0f, 0.0f)) { + /* calculate inverted, then invert again (needed because of camera zoom scaling) */ + zfac = 1.0f / zfac; + view_zoom_to_window_xy_camera(vod->scene, + vod->depsgraph, + vod->v3d, + vod->region, + zfac, + zoom_to_pos ? vod->prev.event_xy : NULL); + } + + ED_region_tag_redraw(vod->region); +} + +static void viewzoom_apply_3d(ViewOpsData *vod, + const int xy[2], + const eViewZoom_Style viewzoom, + const bool zoom_invert, + const bool zoom_to_pos) +{ + float zfac; + float dist_range[2]; + + ED_view3d_dist_range_get(vod->v3d, dist_range); + + zfac = viewzoom_scale_value_offset(&vod->region->winrct, + viewzoom, + zoom_invert, + false, + xy, + vod->init.event_xy, + vod->init.event_xy_offset, + vod->rv3d->dist, + vod->init.dist, + &vod->prev.time); + + if (zfac != 1.0f) { + const float zfac_min = dist_range[0] / vod->rv3d->dist; + const float zfac_max = dist_range[1] / vod->rv3d->dist; + CLAMP(zfac, zfac_min, zfac_max); + + view_zoom_to_window_xy_3d(vod->region, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); + } + + /* these limits were in old code too */ + CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]); + + if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(vod->area, vod->region); + } + + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); + + ED_region_tag_redraw(vod->region); +} + +static void viewzoom_apply(ViewOpsData *vod, + const int xy[2], + const eViewZoom_Style viewzoom, + const bool zoom_invert, + const bool zoom_to_pos) +{ + if ((vod->rv3d->persp == RV3D_CAMOB) && + (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) { + viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos); + } + else { + viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos); + } +} + +static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + bool use_autokey = false; + int ret = OPERATOR_RUNNING_MODAL; + + /* execute the events */ + if (event->type == TIMER && event->customdata == vod->timer) { + /* continuous zoom */ + event_code = VIEW_APPLY; + } + else if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_MOVE: + WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ROTATE: + WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + viewzoom_apply(vod, + event->xy, + (eViewZoom_Style)U.viewzoom, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } + } + else if (event_code == VIEW_CONFIRM) { + use_autokey = true; + ret = OPERATOR_FINISHED; + } + + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); + } + + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op->customdata); + op->customdata = NULL; + } + + return ret; +} + +static int viewzoom_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + View3D *v3d; + RegionView3D *rv3d; + ScrArea *area; + ARegion *region; + bool use_cam_zoom; + float dist_range[2]; + + const int delta = RNA_int_get(op->ptr, "delta"); + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + if (op->customdata) { + ViewOpsData *vod = op->customdata; + + area = vod->area; + region = vod->region; + } + else { + area = CTX_wm_area(C); + region = CTX_wm_region(C); + } + + v3d = area->spacedata.first; + rv3d = region->regiondata; + + use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && + !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d)); + + int zoom_xy_buf[2]; + const int *zoom_xy = NULL; + if (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) { + zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : + region->winx / 2; + zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : + region->winy / 2; + zoom_xy = zoom_xy_buf; + } + + ED_view3d_dist_range_get(v3d, dist_range); + + if (delta < 0) { + const float step = 1.2f; + if (use_cam_zoom) { + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy); + } + else { + if (rv3d->dist < dist_range[1]) { + view_zoom_to_window_xy_3d(region, step, zoom_xy); + } + } + } + else { + const float step = 1.0f / 1.2f; + if (use_cam_zoom) { + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy); + } + else { + if (rv3d->dist > dist_range[0]) { + view_zoom_to_window_xy_3d(region, step, zoom_xy); + } + } + } + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(area, region); + } + + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true); + + ED_region_tag_redraw(region); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + + return OPERATOR_FINISHED; +} + +/* viewdolly_invoke() copied this function, changes here may apply there */ +static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + vod = op->customdata = viewops_data_create( + C, + event, + (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) | + (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + /* if one or the other zoom position aren't set, set from event */ + if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) { + RNA_int_set(op->ptr, "mx", event->xy[0]); + RNA_int_set(op->ptr, "my", event->xy[1]); + } + + if (RNA_struct_property_is_set(op->ptr, "delta")) { + viewzoom_exec(C, op); + } + else { + if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) { + + if (U.uiflag & USER_ZOOM_HORIZ) { + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0]; + } + else { + /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] - + event->prev_xy[0]; + } + viewzoom_apply(vod, + event->prev_xy, + USER_ZOOM_DOLLY, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + return OPERATOR_FINISHED; + } + + if (U.viewzoom == USER_ZOOM_CONTINUE) { + /* needs a timer to continue redrawing */ + vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); + vod->prev.time = PIL_check_seconds_timer(); + } + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + return OPERATOR_FINISHED; +} + +static void viewzoom_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op->customdata); + op->customdata = NULL; +} + +void VIEW3D_OT_zoom(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Zoom View"; + ot->description = "Zoom in/out in the view"; + ot->idname = "VIEW3D_OT_zoom"; + + /* api callbacks */ + ot->invoke = viewzoom_invoke; + ot->exec = viewzoom_exec; + ot->modal = viewzoom_modal; + ot->poll = view3d_zoom_or_dolly_poll; + ot->cancel = viewzoom_cancel; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; + + /* properties */ + view3d_operator_properties_common( + ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c b/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c new file mode 100644 index 00000000000..38c3e37bac6 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_zoom_border.c @@ -0,0 +1,221 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "DNA_camera_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_rect.h" + +#include "BKE_context.h" +#include "BKE_report.h" + +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" + +#include "RNA_access.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Border Zoom Operator + * \{ */ + +static int view3d_zoom_border_exec(bContext *C, wmOperator *op) +{ + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + /* Zooms in on a border drawn by the user */ + rcti rect; + float dvec[3], vb[2], xscale, yscale; + float dist_range[2]; + + /* SMOOTHVIEW */ + float new_dist; + float new_ofs[3]; + + /* ZBuffer depth vars */ + float depth_close = FLT_MAX; + float cent[2], p[3]; + + /* NOTE: otherwise opengl won't work. */ + view3d_operator_needs_opengl(C); + + /* get box select values using rna */ + WM_operator_properties_border_to_rcti(op, &rect); + + /* check if zooming in/out view */ + const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out"); + + ED_view3d_dist_range_get(v3d, dist_range); + + ED_view3d_depth_override( + CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); + { + /* avoid allocating the whole depth buffer */ + ViewDepths depth_temp = {0}; + + /* avoid view3d_update_depths() for speed. */ + view3d_depths_rect_create(region, &rect, &depth_temp); + + /* find the closest Z pixel */ + depth_close = view3d_depth_near(&depth_temp); + + MEM_SAFE_FREE(depth_temp.depths); + } + + /* Resize border to the same ratio as the window. */ + { + const float region_aspect = (float)region->winx / (float)region->winy; + if (((float)BLI_rcti_size_x(&rect) / (float)BLI_rcti_size_y(&rect)) < region_aspect) { + BLI_rcti_resize_x(&rect, (int)(BLI_rcti_size_y(&rect) * region_aspect)); + } + else { + BLI_rcti_resize_y(&rect, (int)(BLI_rcti_size_x(&rect) / region_aspect)); + } + } + + cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2; + cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2; + + if (rv3d->is_persp) { + float p_corner[3]; + + /* no depths to use, we can't do anything! */ + if (depth_close == FLT_MAX) { + BKE_report(op->reports, RPT_ERROR, "Depth too large"); + return OPERATOR_CANCELLED; + } + /* convert border to 3d coordinates */ + if ((!ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p)) || + (!ED_view3d_unproject_v3(region, rect.xmin, rect.ymin, depth_close, p_corner))) { + return OPERATOR_CANCELLED; + } + + sub_v3_v3v3(dvec, p, p_corner); + negate_v3_v3(new_ofs, p); + + new_dist = len_v3(dvec); + + /* Account for the lens, without this a narrow lens zooms in too close. */ + new_dist *= (v3d->lens / DEFAULT_SENSOR_WIDTH); + + /* ignore dist_range min */ + dist_range[0] = v3d->clip_start * 1.5f; + } + else { /* orthographic */ + /* find the current window width and height */ + vb[0] = region->winx; + vb[1] = region->winy; + + new_dist = rv3d->dist; + + /* convert the drawn rectangle into 3d space */ + if (depth_close != FLT_MAX && + ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p)) { + negate_v3_v3(new_ofs, p); + } + else { + float mval_f[2]; + float zfac; + + /* We can't use the depth, fallback to the old way that doesn't set the center depth */ + copy_v3_v3(new_ofs, rv3d->ofs); + + { + float tvec[3]; + negate_v3_v3(tvec, new_ofs); + zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); + } + + mval_f[0] = (rect.xmin + rect.xmax - vb[0]) / 2.0f; + mval_f[1] = (rect.ymin + rect.ymax - vb[1]) / 2.0f; + ED_view3d_win_to_delta(region, mval_f, dvec, zfac); + /* center the view to the center of the rectangle */ + sub_v3_v3(new_ofs, dvec); + } + + /* work out the ratios, so that everything selected fits when we zoom */ + xscale = (BLI_rcti_size_x(&rect) / vb[0]); + yscale = (BLI_rcti_size_y(&rect) / vb[1]); + new_dist *= max_ff(xscale, yscale); + } + + if (!zoom_in) { + sub_v3_v3v3(dvec, new_ofs, rv3d->ofs); + new_dist = rv3d->dist * (rv3d->dist / new_dist); + add_v3_v3v3(new_ofs, rv3d->ofs, dvec); + } + + /* clamp after because we may have been zooming out */ + CLAMP(new_dist, dist_range[0], dist_range[1]); + + /* TODO(campbell): 'is_camera_lock' not currently working well. */ + const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d); + if ((rv3d->persp == RV3D_CAMOB) && (is_camera_lock == false)) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, RV3D_PERSP); + } + + ED_view3d_smooth_view(C, + v3d, + region, + smooth_viewtx, + &(const V3D_SmoothParams){ + .ofs = new_ofs, + .dist = &new_dist, + }); + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(CTX_wm_area(C), region); + } + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_zoom_border(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Zoom to Border"; + ot->description = "Zoom in the view to the nearest object contained in the border"; + ot->idname = "VIEW3D_OT_zoom_border"; + + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = view3d_zoom_border_exec; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; + + ot->poll = view3d_zoom_or_dolly_poll; + + /* flags */ + ot->flag = 0; + + /* properties */ + WM_operator_properties_gesture_box_zoom(ot); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 823aa3b6643..52db8526937 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -50,6 +50,7 @@ #include "ED_transform.h" #include "view3d_intern.h" +#include "view3d_navigate.h" #ifdef WIN32 # include "BLI_math_base.h" /* M_PI */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 45899880b41..34aa24a1eef 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -99,6 +99,7 @@ #include "UI_resources.h" #include "GPU_matrix.h" +#include "GPU_select.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -1566,8 +1567,8 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, - const uint *buffer, - int hits, + const GPUSelectResult *buffer, + const int hits, const int mval[2], bool extend, bool deselect, @@ -1585,7 +1586,7 @@ static Base *object_mouse_select_menu(bContext *C, if (buffer) { for (int a = 0; a < hits; a++) { /* index was converted */ - if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { + if (base->object->runtime.select_id == (buffer[a].id & ~0xFFFF0000)) { ok = true; break; } @@ -1742,7 +1743,7 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static bool bone_mouse_select_menu(bContext *C, - const uint *buffer, + const GPUSelectResult *buffer, const int hits, const bool is_editmode, const bool extend, @@ -1760,7 +1761,7 @@ static bool bone_mouse_select_menu(bContext *C, for (int a = 0; a < hits; a++) { void *bone_ptr = NULL; Base *bone_base = NULL; - uint hitresult = buffer[3 + (a * 4)]; + uint hitresult = buffer[a].id; if (!(hitresult & BONESEL_ANY)) { /* To avoid including objects in selection. */ @@ -1874,10 +1875,10 @@ static bool bone_mouse_select_menu(bContext *C, return true; } -static bool selectbuffer_has_bones(const uint *buffer, const uint hits) +static bool selectbuffer_has_bones(const GPUSelectResult *buffer, const uint hits) { for (uint i = 0; i < hits; i++) { - if (buffer[(4 * i) + 3] & 0xFFFF0000) { + if (buffer[i].id & 0xFFFF0000) { return true; } } @@ -1885,25 +1886,25 @@ static bool selectbuffer_has_bones(const uint *buffer, const uint hits) } /* utility function for mixed_bones_object_selectbuffer */ -static int selectbuffer_ret_hits_15(uint *UNUSED(buffer), const int hits15) +static int selectbuffer_ret_hits_15(GPUSelectResult *UNUSED(buffer), const int hits15) { return hits15; } -static int selectbuffer_ret_hits_9(uint *buffer, const int hits15, const int hits9) +static int selectbuffer_ret_hits_9(GPUSelectResult *buffer, const int hits15, const int hits9) { - const int ofs = 4 * hits15; - memcpy(buffer, buffer + ofs, 4 * hits9 * sizeof(uint)); + const int ofs = hits15; + memcpy(buffer, buffer + ofs, hits9 * sizeof(GPUSelectResult)); return hits9; } -static int selectbuffer_ret_hits_5(uint *buffer, +static int selectbuffer_ret_hits_5(GPUSelectResult *buffer, const int hits15, const int hits9, const int hits5) { - const int ofs = 4 * hits15 + 4 * hits9; - memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint)); + const int ofs = hits15 + hits9; + memcpy(buffer, buffer + ofs, hits5 * sizeof(GPUSelectResult)); return hits5; } @@ -1916,7 +1917,8 @@ static int selectbuffer_ret_hits_5(uint *buffer, * Needed so we can step to the next, non-active object when it's already selected, see: T76445. */ static int mixed_bones_object_selectbuffer(ViewContext *vc, - uint *buffer, + GPUSelectResult *buffer, + const int buffer_len, const int mval[2], eV3DSelectObjectFilter select_filter, bool do_nearest, @@ -1941,7 +1943,7 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc, BLI_rcti_init_pt_radius(&rect, mval, 14); hits15 = view3d_opengl_select_ex( - vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter, do_material_slot_selection); + vc, buffer, buffer_len, &rect, select_mode, select_filter, do_material_slot_selection); if (hits15 == 1) { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; @@ -1950,10 +1952,10 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc, int ofs; has_bones15 = selectbuffer_has_bones(buffer, hits15); - ofs = 4 * hits15; + ofs = hits15; BLI_rcti_init_pt_radius(&rect, mval, 9); hits9 = view3d_opengl_select( - vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter); + vc, buffer + ofs, buffer_len - ofs, &rect, select_mode, select_filter); if (hits9 == 1) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; @@ -1961,10 +1963,10 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc, else if (hits9 > 0) { has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9); - ofs += 4 * hits9; + ofs += hits9; BLI_rcti_init_pt_radius(&rect, mval, 5); hits5 = view3d_opengl_select( - vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter); + vc, buffer + ofs, buffer_len - ofs, &rect, select_mode, select_filter); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; @@ -2007,7 +2009,8 @@ finally: } static int mixed_bones_object_selectbuffer_extended(ViewContext *vc, - uint *buffer, + GPUSelectResult *buffer, + const int buffer_len, const int mval[2], eV3DSelectObjectFilter select_filter, bool use_cycle, @@ -2038,7 +2041,7 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc, do_nearest = do_nearest && !enumerate; int hits = mixed_bones_object_selectbuffer( - vc, buffer, mval, select_filter, do_nearest, true, false); + vc, buffer, buffer_len, mval, select_filter, do_nearest, true, false); return hits; } @@ -2051,7 +2054,7 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc, * \return the active base or NULL. */ static Base *mouse_select_eval_buffer(ViewContext *vc, - const uint *buffer, + const GPUSelectResult *buffer, int hits, Base *startbase, bool has_bones, @@ -2071,10 +2074,10 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, if (has_bones) { /* we skip non-bone hits */ for (a = 0; a < hits; a++) { - if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000)) { - min = buffer[4 * a + 1]; - selcol = buffer[4 * a + 3] & 0xFFFF; - sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16; + if (min > buffer[a].depth && (buffer[a].id & 0xFFFF0000)) { + min = buffer[a].depth; + selcol = buffer[a].id & 0xFFFF; + sub_selection_id = (buffer[a].id & 0xFFFF0000) >> 16; } } } @@ -2085,10 +2088,10 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, } for (a = 0; a < hits; a++) { - if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) { - min = buffer[4 * a + 1]; - selcol = buffer[4 * a + 3] & 0xFFFF; - sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16; + if (min > buffer[a].depth && notcol != (buffer[a].id & 0xFFFF)) { + min = buffer[a].depth; + selcol = buffer[a].id & 0xFFFF; + sub_selection_id = (buffer[a].id & 0xFFFF0000) >> 16; } } } @@ -2127,14 +2130,14 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, for (a = 0; a < hits; a++) { if (has_bones) { /* skip non-bone objects */ - if (buffer[4 * a + 3] & 0xFFFF0000) { - if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { + if (buffer[a].id & 0xFFFF0000) { + if (base->object->runtime.select_id == (buffer[a].id & 0xFFFF)) { basact = base; } } } else { - if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { + if (base->object->runtime.select_id == (buffer[a].id & 0xFFFF)) { basact = base; } } @@ -2169,7 +2172,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C, Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; Base *basact = NULL; - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; /* setup view context for argument to callbacks */ view3d_operator_needs_opengl(C); @@ -2179,8 +2182,14 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C, const bool do_nearest = !XRAY_ACTIVE(vc.v3d); const bool do_material_slot_selection = r_material_slot != NULL; - const int hits = mixed_bones_object_selectbuffer( - &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false, do_material_slot_selection); + const int hits = mixed_bones_object_selectbuffer(&vc, + buffer, + ARRAY_SIZE(buffer), + mval, + VIEW3D_SELECT_FILTER_NOP, + do_nearest, + false, + do_material_slot_selection); if (hits > 0) { const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits); @@ -2342,7 +2351,7 @@ static bool ed_object_select_pick(bContext *C, } } else { - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; bool do_nearest; // TIMEIT_START(select_time); @@ -2353,7 +2362,7 @@ static bool ed_object_select_pick(bContext *C, vc.obact) : VIEW3D_SELECT_FILTER_NOP); hits = mixed_bones_object_selectbuffer_extended( - &vc, buffer, mval, select_filter, true, enumerate, &do_nearest); + &vc, buffer, ARRAY_SIZE(buffer), mval, select_filter, true, enumerate, &do_nearest); // TIMEIT_END(select_time); @@ -2383,7 +2392,7 @@ static bool ed_object_select_pick(bContext *C, bool changed = false; for (int i = 0; i < hits; i++) { - int hitresult = buffer[3 + (i * 4)]; + const int hitresult = buffer[i].id; /* if there's bundles in buffer select bundles first, * so non-camera elements should be ignored in buffer */ @@ -2394,7 +2403,7 @@ static bool ed_object_select_pick(bContext *C, /* index of bundle is 1<<16-based. if there's no "bone" index * in height word, this buffer value belongs to camera. not to bundle */ - if (buffer[4 * i + 3] & 0xFFFF0000) { + if (hitresult & 0xFFFF0000) { MovieTracking *tracking = &clip->tracking; ListBase *tracksbase; MovieTrackingTrack *track; @@ -2674,9 +2683,15 @@ static int view3d_select_exec(bContext *C, wmOperator *op) ViewContext vc; ED_view3d_viewcontext_init(C, &vc, depsgraph); - uint buffer[MAXPICKBUF]; - const int hits = mixed_bones_object_selectbuffer( - &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true, false); + GPUSelectResult buffer[MAXPICKELEMS]; + const int hits = mixed_bones_object_selectbuffer(&vc, + buffer, + ARRAY_SIZE(buffer), + location, + VIEW3D_SELECT_FILTER_NOP, + false, + true, + false); retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle); } if (!retval) { @@ -3256,11 +3271,11 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO int a; bool changed = false; - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; int hits; hits = view3d_opengl_select( - vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); + vc, buffer, MAXPICKELEMS, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { changed |= BKE_mball_deselect_all(mb); @@ -3272,7 +3287,7 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO bool is_inside_stiff = false; for (a = 0; a < hits; a++) { - int hitresult = buffer[(4 * a) + 3]; + const int hitresult = buffer[a].id; if (hitresult == -1) { continue; @@ -3323,11 +3338,11 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel bool changed = false; int a; - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; int hits; hits = view3d_opengl_select( - vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); + vc, buffer, MAXPICKELEMS, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( @@ -3347,7 +3362,7 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel /* first we only check points inside the border */ for (a = 0; a < hits; a++) { - int select_id = buffer[(4 * a) + 3]; + const int select_id = buffer[a].id; if (select_id != -1) { if ((select_id & 0xFFFF0000) == 0) { continue; @@ -3375,14 +3390,13 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel } /** - * Compare result of 'GPU_select': 'uint[4]', + * Compare result of 'GPU_select': 'GPUSelectResult', * needed for when we need to align with object draw-order. */ static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p) { - /* 4th element is select id */ - uint sel_a = ((uint *)sel_a_p)[3]; - uint sel_b = ((uint *)sel_b_p)[3]; + uint sel_a = ((GPUSelectResult *)sel_a_p)->id; + uint sel_b = ((GPUSelectResult *)sel_b_p)->id; #ifdef __BIG_ENDIAN__ BLI_endian_switch_uint32(&sel_a); @@ -3401,14 +3415,15 @@ static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op) { View3D *v3d = vc->v3d; - int totobj = MAXPICKBUF; /* XXX solve later */ + int totobj = MAXPICKELEMS; /* XXX solve later */ - /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ - uint *vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer"); + /* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */ + GPUSelectResult *buffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), + "selection buffer"); const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); const int hits = view3d_opengl_select( - vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); + vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) { base->object->id.tag &= ~LIB_TAG_DOIT; @@ -3435,12 +3450,13 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const } /* The draw order doesn't always match the order we populate the engine, see: T51695. */ - qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp); + qsort(buffer, hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp); - for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) { + for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end; + buf_iter++) { bPoseChannel *pchan_dummy; Base *base = ED_armature_base_and_pchan_from_select_buffer( - bases, BLI_array_len(bases), *col, &pchan_dummy); + bases, BLI_array_len(bases), buf_iter->id, &pchan_dummy); if (base != NULL) { base->object->id.tag |= LIB_TAG_DOIT; } @@ -3463,7 +3479,7 @@ finally: MEM_freeN(bases); } - MEM_freeN(vbuffer); + MEM_freeN(buffer); if (changed) { DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); @@ -3477,14 +3493,15 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e uint bases_len; Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len); - int totobj = MAXPICKBUF; /* XXX solve later */ + int totobj = MAXPICKELEMS; /* XXX solve later */ - /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ - uint *vbuffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer"); + /* Selection buffer has bones potentially too, so add #MAXPICKELEMS. */ + GPUSelectResult *buffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), + "selection buffer"); const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); const int hits = view3d_opengl_select( - vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); + vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); /* * LOGIC NOTES (theeth): * The buffer and ListBase have the same relative order, which makes the selection @@ -3498,18 +3515,20 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e /* no need to loop if there's no hit */ /* The draw order doesn't always match the order we populate the engine, see: T51695. */ - qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp); + qsort(buffer, hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp); - for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) { + for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end; + buf_iter++) { Bone *bone; - Base *base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, *col, &bone); + Base *base = ED_armature_base_and_bone_from_select_buffer( + bases, bases_len, buf_iter->id, &bone); if (base == NULL) { continue; } /* Loop over contiguous bone hits for 'base'. */ - for (; col != col_end; col += 4) { + for (; buf_iter != buf_end; buf_iter++) { /* should never fail */ if (bone != NULL) { base->object->id.tag |= LIB_TAG_DOIT; @@ -3517,12 +3536,13 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e } /* Select the next bone if we're not switching bases. */ - if (col + 4 != col_end) { - if ((base->object->runtime.select_id & 0x0000FFFF) != (col[4] & 0x0000FFFF)) { + if (buf_iter + 1 != buf_end) { + const GPUSelectResult *col_next = buf_iter + 1; + if ((base->object->runtime.select_id & 0x0000FFFF) != (col_next->id & 0x0000FFFF)) { break; } if (base->object->pose != NULL) { - const uint hit_bone = (col[4] & ~BONESEL_ANY) >> 16; + const uint hit_bone = (col_next->id & ~BONESEL_ANY) >> 16; bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone); bone = pchan ? pchan->bone : NULL; } @@ -3543,7 +3563,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e if (bases != NULL) { MEM_freeN(bases); } - MEM_freeN(vbuffer); + MEM_freeN(buffer); return changed_multi; } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 165f931394d..ddd5cc640bb 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -21,21 +21,14 @@ * \ingroup spview3d */ -#include "DNA_camera_types.h" -#include "DNA_gpencil_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - #include "MEM_guardedalloc.h" #include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" -#include "BLI_utildefines.h" #include "BKE_action.h" -#include "BKE_camera.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_gpencil_modifier.h" @@ -47,7 +40,6 @@ #include "BKE_report.h" #include "BKE_scene.h" -#include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" #include "UI_resources.h" @@ -57,7 +49,6 @@ #include "GPU_state.h" #include "WM_api.h" -#include "WM_types.h" #include "ED_object.h" #include "ED_screen.h" @@ -68,376 +59,7 @@ #include "RNA_define.h" #include "view3d_intern.h" /* own include */ - -/* -------------------------------------------------------------------- */ -/** \name Smooth View Operator & Utilities - * - * Use for view transitions to have smooth (animated) transitions. - * \{ */ - -/* This operator is one of the 'timer refresh' ones like animation playback */ - -struct SmoothView3DState { - float dist; - float lens; - float quat[4]; - float ofs[3]; -}; - -struct SmoothView3DStore { - /* Source. */ - struct SmoothView3DState src; /* source */ - struct SmoothView3DState dst; /* destination */ - struct SmoothView3DState org; /* original */ - - bool to_camera; - - bool use_dyn_ofs; - float dyn_ofs[3]; - - /* When smooth-view is enabled, store the 'rv3d->view' here, - * assign back when the view motion is completed. */ - char org_view; - - double time_allowed; -}; - -static void view3d_smooth_view_state_backup(struct SmoothView3DState *sms_state, - const View3D *v3d, - const RegionView3D *rv3d) -{ - copy_v3_v3(sms_state->ofs, rv3d->ofs); - copy_qt_qt(sms_state->quat, rv3d->viewquat); - sms_state->dist = rv3d->dist; - sms_state->lens = v3d->lens; -} - -static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms_state, - View3D *v3d, - RegionView3D *rv3d) -{ - copy_v3_v3(rv3d->ofs, sms_state->ofs); - copy_qt_qt(rv3d->viewquat, sms_state->quat); - rv3d->dist = sms_state->dist; - v3d->lens = sms_state->lens; -} - -/* will start timer if appropriate */ -void ED_view3d_smooth_view_ex( - /* avoid passing in the context */ - const Depsgraph *depsgraph, - wmWindowManager *wm, - wmWindow *win, - ScrArea *area, - View3D *v3d, - ARegion *region, - const int smooth_viewtx, - const V3D_SmoothParams *sview) -{ - RegionView3D *rv3d = region->regiondata; - struct SmoothView3DStore sms = {{0}}; - - /* initialize sms */ - view3d_smooth_view_state_backup(&sms.dst, v3d, rv3d); - view3d_smooth_view_state_backup(&sms.src, v3d, rv3d); - /* If smooth-view runs multiple times. */ - if (rv3d->sms == NULL) { - view3d_smooth_view_state_backup(&sms.org, v3d, rv3d); - } - else { - sms.org = rv3d->sms->org; - } - sms.org_view = rv3d->view; - - /* sms.to_camera = false; */ /* initialized to zero anyway */ - - /* note on camera locking, this is a little confusing but works ok. - * we may be changing the view 'as if' there is no active camera, but in fact - * there is an active camera which is locked to the view. - * - * In the case where smooth view is moving _to_ a camera we don't want that - * camera to be moved or changed, so only when the camera is not being set should - * we allow camera option locking to initialize the view settings from the camera. - */ - if (sview->camera == NULL && sview->camera_old == NULL) { - ED_view3d_camera_lock_init(depsgraph, v3d, rv3d); - } - - /* store the options we want to end with */ - if (sview->ofs) { - copy_v3_v3(sms.dst.ofs, sview->ofs); - } - if (sview->quat) { - copy_qt_qt(sms.dst.quat, sview->quat); - } - if (sview->dist) { - sms.dst.dist = *sview->dist; - } - if (sview->lens) { - sms.dst.lens = *sview->lens; - } - - if (sview->dyn_ofs) { - BLI_assert(sview->ofs == NULL); - BLI_assert(sview->quat != NULL); - - copy_v3_v3(sms.dyn_ofs, sview->dyn_ofs); - sms.use_dyn_ofs = true; - - /* calculate the final destination offset */ - view3d_orbit_apply_dyn_ofs(sms.dst.ofs, sms.src.ofs, sms.src.quat, sms.dst.quat, sms.dyn_ofs); - } - - if (sview->camera) { - Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); - if (sview->ofs != NULL) { - sms.dst.dist = ED_view3d_offset_distance( - ob_camera_eval->obmat, sview->ofs, VIEW3D_DIST_FALLBACK); - } - ED_view3d_from_object(ob_camera_eval, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens); - sms.to_camera = true; /* restore view3d values in end */ - } - - if ((sview->camera_old == sview->camera) && /* Camera. */ - (sms.dst.dist == rv3d->dist) && /* Distance. */ - (sms.dst.lens == v3d->lens) && /* Lens. */ - equals_v3v3(sms.dst.ofs, rv3d->ofs) && /* Offset. */ - equals_v4v4(sms.dst.quat, rv3d->viewquat) /* Rotation. */ - ) { - /* Early return if nothing changed. */ - return; - } - - /* Skip smooth viewing for external render engine draw. */ - if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) { - - /* original values */ - if (sview->camera_old) { - Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old); - if (sview->ofs != NULL) { - sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f); - } - ED_view3d_from_object( - ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens); - } - /* grid draw as floor */ - if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) { - /* use existing if exists, means multiple calls to smooth view - * won't lose the original 'view' setting */ - rv3d->view = RV3D_VIEW_USER; - } - - sms.time_allowed = (double)smooth_viewtx / 1000.0; - - /* If this is view rotation only we can decrease the time allowed by the angle between quats - * this means small rotations won't lag. */ - if (sview->quat && !sview->ofs && !sview->dist) { - /* scale the time allowed by the rotation */ - /* 180deg == 1.0 */ - sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) / - M_PI; - } - - /* ensure it shows correct */ - if (sms.to_camera) { - /* use ortho if we move from an ortho view to an ortho camera */ - Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); - rv3d->persp = (((rv3d->is_persp == false) && (ob_camera_eval->type == OB_CAMERA) && - (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ? - RV3D_ORTHO : - RV3D_PERSP); - } - - rv3d->rflag |= RV3D_NAVIGATING; - - /* not essential but in some cases the caller will tag the area for redraw, and in that - * case we can get a flicker of the 'org' user view but we want to see 'src' */ - view3d_smooth_view_state_restore(&sms.src, v3d, rv3d); - - /* keep track of running timer! */ - if (rv3d->sms == NULL) { - rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d"); - } - *rv3d->sms = sms; - if (rv3d->smooth_timer) { - WM_event_remove_timer(wm, win, rv3d->smooth_timer); - } - /* #TIMER1 is hard-coded in key-map. */ - rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0); - } - else { - /* Animation is disabled, apply immediately. */ - if (sms.to_camera == false) { - copy_v3_v3(rv3d->ofs, sms.dst.ofs); - copy_qt_qt(rv3d->viewquat, sms.dst.quat); - rv3d->dist = sms.dst.dist; - v3d->lens = sms.dst.lens; - - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - } - - if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_copy(area, region); - } - - ED_region_tag_redraw(region); - - WM_event_add_mousemove(win); - } -} - -void ED_view3d_smooth_view(bContext *C, - View3D *v3d, - ARegion *region, - const int smooth_viewtx, - const struct V3D_SmoothParams *sview) -{ - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win = CTX_wm_window(C); - ScrArea *area = CTX_wm_area(C); - - ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, sview); -} - -/* only meant for timer usage */ -static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, bool sync_boxview) -{ - wmWindowManager *wm = CTX_wm_manager(C); - RegionView3D *rv3d = region->regiondata; - struct SmoothView3DStore *sms = rv3d->sms; - float step, step_inv; - - if (sms->time_allowed != 0.0) { - step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed); - } - else { - step = 1.0f; - } - - /* end timer */ - if (step >= 1.0f) { - wmWindow *win = CTX_wm_window(C); - - /* if we went to camera, store the original */ - if (sms->to_camera) { - rv3d->persp = RV3D_CAMOB; - view3d_smooth_view_state_restore(&sms->org, v3d, rv3d); - } - else { - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - - view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d); - - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); - } - - if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) { - rv3d->view = sms->org_view; - } - - MEM_freeN(rv3d->sms); - rv3d->sms = NULL; - - WM_event_remove_timer(wm, win, rv3d->smooth_timer); - rv3d->smooth_timer = NULL; - rv3d->rflag &= ~RV3D_NAVIGATING; - - /* Event handling won't know if a UI item has been moved under the pointer. */ - WM_event_add_mousemove(win); - } - else { - /* ease in/out */ - step = (3.0f * step * step - 2.0f * step * step * step); - - step_inv = 1.0f - step; - - interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, step); - - if (sms->use_dyn_ofs) { - view3d_orbit_apply_dyn_ofs( - rv3d->ofs, sms->src.ofs, sms->src.quat, rv3d->viewquat, sms->dyn_ofs); - } - else { - interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, step); - } - - rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv; - v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv; - - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - if (ED_screen_animation_playing(wm)) { - ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); - } - } - - if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) { - view3d_boxview_copy(CTX_wm_area(C), region); - } - - /* NOTE: this doesn't work right because the v3d->lens is now used in ortho mode r51636, - * when switching camera in quad-view the other ortho views would zoom & reset. - * - * For now only redraw all regions when smooth-view finishes. - */ - if (step >= 1.0f) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); - } - else { - ED_region_tag_redraw(region); - } -} - -static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) -{ - View3D *v3d = CTX_wm_view3d(C); - ARegion *region = CTX_wm_region(C); - RegionView3D *rv3d = region->regiondata; - - /* escape if not our timer */ - if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata) { - return OPERATOR_PASS_THROUGH; - } - - view3d_smoothview_apply(C, v3d, region, true); - - return OPERATOR_FINISHED; -} - -void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region) -{ - RegionView3D *rv3d = region->regiondata; - - if (rv3d && rv3d->sms) { - rv3d->sms->time_allowed = 0.0; /* force finishing */ - view3d_smoothview_apply(C, v3d, region, false); - - /* force update of view matrix so tools that run immediately after - * can use them without redrawing first */ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ED_view3d_update_viewmat(depsgraph, scene, v3d, region, NULL, NULL, NULL, false); - } -} - -void VIEW3D_OT_smoothview(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Smooth View"; - ot->idname = "VIEW3D_OT_smoothview"; - - /* api callbacks */ - ot->invoke = view3d_smoothview_invoke; - - /* flags */ - ot->flag = OPTYPE_INTERNAL; - - ot->poll = ED_operator_view3d_active; -} - -/** \} */ +#include "view3d_navigate.h" /* -------------------------------------------------------------------- */ /** \name Camera to View Operator @@ -863,10 +485,10 @@ void view3d_opengl_select_cache_end(void) struct DrawSelectLoopUserData { uint pass; uint hits; - uint *buffer; + GPUSelectResult *buffer; uint buffer_len; const rcti *rect; - char gpu_select_mode; + eGPUSelectMode gpu_select_mode; }; static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data) @@ -927,8 +549,8 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void } int view3d_opengl_select_ex(ViewContext *vc, - uint *buffer, - uint bufsize, + GPUSelectResult *buffer, + uint buffer_len, const rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter, @@ -950,7 +572,7 @@ int view3d_opengl_select_ex(ViewContext *vc, const bool use_nearest = (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST); bool draw_surface = true; - char gpu_select_mode; + eGPUSelectMode gpu_select_mode; /* case not a box select */ if (input->xmin == input->xmax) { @@ -981,6 +603,15 @@ int view3d_opengl_select_ex(ViewContext *vc, } } + /* Re-use cache (rect must be smaller than the cached) + * other context is assumed to be unchanged */ + if (GPU_select_is_cached()) { + GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0); + GPU_select_cache_load_id(); + hits = GPU_select_end(); + goto finally; + } + /* Important to use 'vc->obact', not 'OBACT(vc->view_layer)' below, * so it will be NULL when hidden. */ struct { @@ -1040,15 +671,6 @@ int view3d_opengl_select_ex(ViewContext *vc, UI_Theme_Store(&theme_state); UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); - /* Re-use cache (rect must be smaller than the cached) - * other context is assumed to be unchanged */ - if (GPU_select_is_cached()) { - GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0); - GPU_select_cache_load_id(); - hits = GPU_select_end(); - goto finally; - } - /* All of the queries need to be perform on the drawing context. */ DRW_opengl_context_enable(); @@ -1071,7 +693,7 @@ int view3d_opengl_select_ex(ViewContext *vc, .pass = 0, .hits = 0, .buffer = buffer, - .buffer_len = bufsize, + .buffer_len = buffer_len, .rect = &rect, .gpu_select_mode = gpu_select_mode, }; @@ -1101,7 +723,7 @@ int view3d_opengl_select_ex(ViewContext *vc, .pass = 0, .hits = 0, .buffer = buffer, - .buffer_len = bufsize, + .buffer_len = buffer_len, .rect = &rect, .gpu_select_mode = gpu_select_mode, }; @@ -1132,36 +754,36 @@ int view3d_opengl_select_ex(ViewContext *vc, DRW_opengl_context_disable(); + UI_Theme_Restore(&theme_state); + finally: if (hits < 0) { printf("Too many objects in select buffer\n"); /* XXX make error message */ } - UI_Theme_Restore(&theme_state); - return hits; } int view3d_opengl_select(ViewContext *vc, - uint *buffer, - uint bufsize, + GPUSelectResult *buffer, + uint buffer_len, const rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter) { - return view3d_opengl_select_ex(vc, buffer, bufsize, input, select_mode, select_filter, false); + return view3d_opengl_select_ex(vc, buffer, buffer_len, input, select_mode, select_filter, false); } int view3d_opengl_select_with_id_filter(ViewContext *vc, - uint *buffer, - uint bufsize, + GPUSelectResult *buffer, + const uint buffer_len, const rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter, uint select_id) { - int hits = view3d_opengl_select(vc, buffer, bufsize, input, select_mode, select_filter); + int hits = view3d_opengl_select(vc, buffer, buffer_len, input, select_mode, select_filter); /* Selection sometimes uses -1 for an invalid selection ID, remove these as they * interfere with detection of actual number of hits in the selection. */ diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 64a720322c1..09c53d7196c 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -125,9 +125,5 @@ set(LIB bf_gpu ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 642de550812..8d91f90ea29 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -580,11 +580,11 @@ typedef struct TransInfo { /** Mouse side of the current frame, 'L', 'R' or 'B' */ char frame_side; - /** copy from G.vd, prevents feedback. */ + /** copy from #RegionView3D, prevents feedback. */ float viewmat[4][4]; /** and to make sure we don't have to. */ float viewinv[4][4]; - /** access G.vd from other space types. */ + /** Access #RegionView3D from other space types. */ float persmat[4][4]; float persinv[4][4]; short persp; diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index c40f3c28a79..90f78d4abf1 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -124,10 +124,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t); * Sets transform flags in the bones. * Returns total number of bones with #BONE_TRANSFORM. */ -int transform_convert_pose_transflags_update(Object *ob, - int mode, - short around, - bool has_translate_rotate[2]); +void transform_convert_pose_transflags_update(Object *ob, int mode, short around); + /** * When objects array is NULL, use 't->data_container' as is. */ diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 5d0a3bd9dd1..04a8d462924 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -739,9 +739,43 @@ void createTransPose(TransInfo *t) const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); - /* set flags and count total */ - tc->data_len = transform_convert_pose_transflags_update( - ob, t->mode, t->around, has_translate_rotate); + /* Set flags. */ + transform_convert_pose_transflags_update(ob, t->mode, t->around); + + /* Now count, and check if we have autoIK or have to switch from translate to rotate. */ + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + Bone *bone = pchan->bone; + if (!(bone->flag & BONE_TRANSFORM)) { + continue; + } + + tc->data_len++; + + if (has_translate_rotate != NULL) { + if (has_translate_rotate[0] && has_translate_rotate[1]) { + continue; + } + + if (has_targetless_ik(pchan) == NULL) { + if (pchan->parent && (bone->flag & BONE_CONNECTED)) { + if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) { + has_translate_rotate[0] = true; + } + } + else { + if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) { + has_translate_rotate[0] = true; + } + } + if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) { + has_translate_rotate[1] = true; + } + } + else { + has_translate_rotate[0] = true; + } + } + } if (tc->data_len == 0) { continue; @@ -1499,15 +1533,11 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) } } -int transform_convert_pose_transflags_update(Object *ob, - const int mode, - const short around, - bool has_translate_rotate[2]) +void transform_convert_pose_transflags_update(Object *ob, const int mode, const short around) { bArmature *arm = ob->data; bPoseChannel *pchan; Bone *bone; - int total = 0; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { bone = pchan->bone; @@ -1537,36 +1567,6 @@ int transform_convert_pose_transflags_update(Object *ob, } } } - /* now count, and check if we have autoIK or have to switch from translate to rotate */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; - if (bone->flag & BONE_TRANSFORM) { - total++; - - if (has_translate_rotate != NULL) { - if (has_targetless_ik(pchan) == NULL) { - if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) { - if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) { - has_translate_rotate[0] = true; - } - } - else { - if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) { - has_translate_rotate[0] = true; - } - } - if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) { - has_translate_rotate[1] = true; - } - } - else { - has_translate_rotate[0] = true; - } - } - } - } - - return total; } static short apply_targetless_ik(Object *ob) @@ -1733,7 +1733,7 @@ void special_aftertrans_update__pose(bContext *C, TransInfo *t) /* Set BONE_TRANSFORM flags for auto-key, gizmo draw might have changed them. */ if (!canceled && (t->mode != TFM_DUMMY)) { - transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL); + transform_convert_pose_transflags_update(ob, t->mode, t->around); } /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */ diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 9bd55d78039..c0572478481 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -953,32 +953,25 @@ int ED_transform_calc_gizmo_stats(const bContext *C, for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob_iter = objects[ob_index]; - const bool use_mat_local = (ob_iter != ob); - bPoseChannel *pchan; - + const bool use_mat_local = params->use_local_axis && (ob_iter != ob); /* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */ const int mode = TFM_ROTATION; - const int totsel_iter = transform_convert_pose_transflags_update( - ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL); + transform_convert_pose_transflags_update(ob_iter, mode, V3D_AROUND_CENTER_BOUNDS); - if (totsel_iter) { - float mat_local[4][4]; - if (params->use_local_axis) { - if (use_mat_local) { - mul_m4_m4m4(mat_local, ob->imat, ob_iter->obmat); - } - } + float mat_local[4][4]; + if (use_mat_local) { + mul_m4_m4m4(mat_local, ob->imat, ob_iter->obmat); + } - /* use channels to get stats */ - for (pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { - Bone *bone = pchan->bone; - if (bone && (bone->flag & BONE_TRANSFORM)) { - calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local); - protectflag_to_drawflags_pchan(rv3d, pchan, orient_index); - } + /* Use channels to get stats. */ + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + if (!(pchan->bone->flag & BONE_TRANSFORM)) { + continue; } - totsel += totsel_iter; + calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local); + protectflag_to_drawflags_pchan(rv3d, pchan, orient_index); + totsel++; } } MEM_freeN(objects); diff --git a/source/blender/editors/undo/CMakeLists.txt b/source/blender/editors/undo/CMakeLists.txt index 0f4152c9128..6f659e383fe 100644 --- a/source/blender/editors/undo/CMakeLists.txt +++ b/source/blender/editors/undo/CMakeLists.txt @@ -46,8 +46,4 @@ set(LIB bf_editor_physics ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_undo "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 90a09c87cc6..66cda0fc3f8 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -115,10 +115,6 @@ set(LIB ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) list(APPEND INC diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 1c8a56e0608..a3b29f29354 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -52,9 +52,5 @@ set(LIB bf_bmesh ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_editor_uvedit "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt index d16787714c9..948e68e52da 100644 --- a/source/blender/freestyle/CMakeLists.txt +++ b/source/blender/freestyle/CMakeLists.txt @@ -583,10 +583,6 @@ if(WITH_PYTHON_SAFETY) add_definitions(-DWITH_PYTHON_SAFETY) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WIN32) list(APPEND INC_SYS ${PTHREADS_INC} diff --git a/source/blender/freestyle/intern/geometry/matrix_util.cpp b/source/blender/freestyle/intern/geometry/matrix_util.cpp index 95a24d85677..c917e9c87fd 100644 --- a/source/blender/freestyle/intern/geometry/matrix_util.cpp +++ b/source/blender/freestyle/intern/geometry/matrix_util.cpp @@ -15,14 +15,7 @@ * * The Original Code is: * GXML/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000 Bruno Levy - * Contact: Bruno Levy - * <levy@loria.fr> - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE + * Copyright 2000 Bruno Levy <levy@loria.fr> */ /** \file diff --git a/source/blender/freestyle/intern/geometry/matrix_util.h b/source/blender/freestyle/intern/geometry/matrix_util.h index 8c2eb799d13..147e25e9608 100644 --- a/source/blender/freestyle/intern/geometry/matrix_util.h +++ b/source/blender/freestyle/intern/geometry/matrix_util.h @@ -15,14 +15,7 @@ * * The Original Code is: * GXML/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000 Bruno Levy - * Contact: Bruno Levy - * <levy@loria.fr> - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE + * Copyright 2000 Bruno Levy <levy@loria.fr> */ #pragma once diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.cpp b/source/blender/freestyle/intern/geometry/normal_cycle.cpp index 77a80e63b77..fbcbeb220df 100644 --- a/source/blender/freestyle/intern/geometry/normal_cycle.cpp +++ b/source/blender/freestyle/intern/geometry/normal_cycle.cpp @@ -15,14 +15,7 @@ * * The Original Code is: * OGF/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000 Bruno Levy - * Contact: Bruno Levy - * <levy@loria.fr> - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE + * Copyright 2000 Bruno Levy <levy@loria.fr> */ /** \file diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h index 949675e9d8d..1fb59bcad19 100644 --- a/source/blender/freestyle/intern/geometry/normal_cycle.h +++ b/source/blender/freestyle/intern/geometry/normal_cycle.h @@ -15,14 +15,7 @@ * * The Original Code is: * OGF/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000 Bruno Levy - * Contact: Bruno Levy - * <levy@loria.fr> - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE + * Copyright 2000 Bruno Levy <levy@loria.fr> */ #pragma once diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp index ec07a124808..571f21ac309 100644 --- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp +++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp @@ -18,13 +18,7 @@ * Copyright (C) 1999 Stephane Popinet * and: * OGF/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000-2003 Bruno Levy - * Contact: Bruno Levy <levy@loria.fr> - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE + * Copyright 2000-2003 Bruno Levy <levy@loria.fr> */ /** \file diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.h b/source/blender/freestyle/intern/winged_edge/Curvature.h index acbe4e8daf6..c87134a0c14 100644 --- a/source/blender/freestyle/intern/winged_edge/Curvature.h +++ b/source/blender/freestyle/intern/winged_edge/Curvature.h @@ -15,16 +15,10 @@ * * The Original Code is: * GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stephane Popinet + * Copyright 1999 Stephane Popinet * and: * OGF/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000-2003 Bruno Levy - * Contact: Bruno Levy <levy@loria.fr> - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE + * Copyright (C) 2000-2003 Bruno Levy <levy@loria.fr> */ #pragma once diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index e869927c33b..e42feac1644 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -87,8 +87,7 @@ class FieldNode { public: FieldNode(FieldNodeType node_type); - - virtual ~FieldNode() = default; + virtual ~FieldNode(); virtual const CPPType &output_cpp_type(int output_index) const = 0; @@ -230,6 +229,7 @@ class FieldOperation : public FieldNode { public: FieldOperation(std::shared_ptr<const MultiFunction> function, Vector<GField> inputs = {}); FieldOperation(const MultiFunction &function, Vector<GField> inputs = {}); + ~FieldOperation(); Span<GField> inputs() const; const MultiFunction &multi_function() const; @@ -259,6 +259,7 @@ class FieldInput : public FieldNode { public: FieldInput(const CPPType &type, std::string debug_name = ""); + ~FieldInput(); /** * Get the value of this specific input based on the given context. The returned virtual array, diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc index 0bbfbc8cb10..7f1eb8bc1a7 100644 --- a/source/blender/functions/intern/cpp_types.cc +++ b/source/blender/functions/intern/cpp_types.cc @@ -31,6 +31,7 @@ MAKE_CPP_TYPE(float3, blender::float3, CPPTypeFlags::BasicType) MAKE_CPP_TYPE(float4x4, blender::float4x4, CPPTypeFlags::BasicType) MAKE_CPP_TYPE(int32, int32_t, CPPTypeFlags::BasicType) +MAKE_CPP_TYPE(int8, int8_t, CPPTypeFlags::BasicType) MAKE_CPP_TYPE(uint32, uint32_t, CPPTypeFlags::BasicType) MAKE_CPP_TYPE(uint8, uint8_t, CPPTypeFlags::BasicType) @@ -44,6 +45,7 @@ MAKE_FIELD_CPP_TYPE(Float2Field, float2); MAKE_FIELD_CPP_TYPE(Float3Field, float3); MAKE_FIELD_CPP_TYPE(ColorGeometry4fField, blender::ColorGeometry4f); MAKE_FIELD_CPP_TYPE(BoolField, bool); +MAKE_FIELD_CPP_TYPE(Int8Field, int8_t); MAKE_FIELD_CPP_TYPE(Int32Field, int32_t); MAKE_FIELD_CPP_TYPE(StringField, std::string); diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index d6b83c42294..fe3041b8602 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -571,6 +571,13 @@ bool IndexFieldInput::is_equal_to(const fn::FieldNode &other) const } /* -------------------------------------------------------------------- + * FieldNode. + */ + +/* Avoid generating the destructor in every translation unit. */ +FieldNode::~FieldNode() = default; + +/* -------------------------------------------------------------------- * FieldOperation. */ @@ -581,6 +588,9 @@ FieldOperation::FieldOperation(std::shared_ptr<const MultiFunction> function, owned_function_ = std::move(function); } +/* Avoid generating the destructor in every translation unit. */ +FieldOperation::~FieldOperation() = default; + /** * Returns the field inputs used by all the provided fields. * This tries to reuse an existing #FieldInputs whenever possible to avoid copying it. @@ -655,6 +665,9 @@ FieldInput::FieldInput(const CPPType &type, std::string debug_name) field_inputs_ = std::move(field_inputs); } +/* Avoid generating the destructor in every translation unit. */ +FieldInput::~FieldInput() = default; + /* -------------------------------------------------------------------- * FieldConstant. */ diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt index f7ddd393b4d..110092e4f5f 100644 --- a/source/blender/geometry/CMakeLists.txt +++ b/source/blender/geometry/CMakeLists.txt @@ -14,7 +14,7 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -# The Original Code is Copyright (C) 2006, Blender Foundation +# The Original Code is Copyright (C) 2006 Blender Foundation # All rights reserved. set(INC diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index 5ee75619259..a3f468a20dc 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -92,10 +92,6 @@ set(SRC set(LIB ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_gpencil_modifiers "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 2b6b28bd649..cffea5e9dcc 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -375,7 +375,7 @@ set(GLSL_SRC shaders/gpu_shader_common_obinfos_lib.glsl - intern/gpu_shader_shared_utils.h + GPU_shader_shared_utils.h ) set(GLSL_C) diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index c02af763311..3076058c075 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -32,7 +32,7 @@ extern "C" { struct rcti; /** Flags for mode of operation. */ -enum { +typedef enum eGPUSelectMode { GPU_SELECT_ALL = 1, /* gpu_select_query */ GPU_SELECT_NEAREST_FIRST_PASS = 2, @@ -40,13 +40,32 @@ enum { /* gpu_select_pick */ GPU_SELECT_PICK_ALL = 4, GPU_SELECT_PICK_NEAREST = 5, -}; +} eGPUSelectMode; + +/** + * The result of calling #GPU_select_begin & #GPU_select_end. + */ +typedef struct GPUSelectResult { + /** The selection identifier matching the value passed in by #GPU_select_load_id. */ + unsigned int id; + /** + * The nearest depth. + * - Only supported by picking modes (#GPU_SELECT_PICK_ALL and #GPU_SELECT_PICK_NEAREST) + * since occlusion quires don't provide a convenient way of accessing the depth-buffer. + * - OpenGL's `GL_SELECT` supported both near and far depths, + * this has not been included as Blender doesn't need this however support could be added. + */ + unsigned int depth; +} GPUSelectResult; /** * Initialize and provide buffer for results. */ -void GPU_select_begin( - unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits); +void GPU_select_begin(GPUSelectResult *buffer, + unsigned int buffer_len, + const struct rcti *input, + eGPUSelectMode mode, + int oldhits); /** * Loads a new selection id and ends previous query, if any. * In second pass of selection it also returns @@ -79,8 +98,8 @@ void GPU_select_cache_end(void); * * Note that comparing depth as uint is fine. */ -const uint *GPU_select_buffer_near(const uint *buffer, int hits); -uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id); +const GPUSelectResult *GPU_select_buffer_near(const GPUSelectResult *buffer, int hits); +uint GPU_select_buffer_remove_by_id(GPUSelectResult *buffer, int hits, uint select_id); /** * Part of the solution copied from `rect_subregion_stride_calc`. */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 972758febd4..05c992274eb 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -71,6 +71,8 @@ GPUShader *GPU_shader_create_ex(const char *vertcode, GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info); GPUShader *GPU_shader_create_from_info_name(const char *info_name); +const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name); + struct GPU_ShaderCreateFromArray_Params { const char **vert, **geom, **frag, **defs; }; diff --git a/source/blender/gpu/GPU_shader_shared.h b/source/blender/gpu/GPU_shader_shared.h index eeca7ee6caa..636a8f53ba6 100644 --- a/source/blender/gpu/GPU_shader_shared.h +++ b/source/blender/gpu/GPU_shader_shared.h @@ -22,7 +22,7 @@ */ #ifndef USE_GPU_SHADER_CREATE_INFO -# include "intern/gpu_shader_shared_utils.h" +# include "GPU_shader_shared_utils.h" #endif struct NodeLinkData { diff --git a/source/blender/gpu/intern/gpu_shader_shared_utils.h b/source/blender/gpu/GPU_shader_shared_utils.h index 0d283fb1e66..0d283fb1e66 100644 --- a/source/blender/gpu/intern/gpu_shader_shared_utils.h +++ b/source/blender/gpu/GPU_shader_shared_utils.h diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 22cd7eab927..bd52b8321bb 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -37,11 +37,14 @@ ENUM_OPERATORS(eGPUWriteMask, GPU_WRITE_COLOR) typedef enum eGPUBarrier { GPU_BARRIER_NONE = 0, - GPU_BARRIER_SHADER_IMAGE_ACCESS = (1 << 0), - GPU_BARRIER_TEXTURE_FETCH = (1 << 1), - GPU_BARRIER_SHADER_STORAGE = (1 << 2), - GPU_BARRIER_VERTEX_ATTRIB_ARRAY = (1 << 3), - GPU_BARRIER_ELEMENT_ARRAY = (1 << 4), + GPU_BARRIER_COMMAND = (1 << 0), + GPU_BARRIER_FRAMEBUFFER = (1 << 1), + GPU_BARRIER_SHADER_IMAGE_ACCESS = (1 << 2), + GPU_BARRIER_SHADER_STORAGE = (1 << 3), + GPU_BARRIER_TEXTURE_FETCH = (1 << 4), + GPU_BARRIER_TEXTURE_UPDATE = (1 << 5), + GPU_BARRIER_VERTEX_ATTRIB_ARRAY = (1 << 6), + GPU_BARRIER_ELEMENT_ARRAY = (1 << 7), } eGPUBarrier; ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY) diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 6fae4a13918..7812c7a7257 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -272,7 +272,8 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl); * Fills the whole texture with the same data for all pixels. * \warning Only work for 2D texture for now. * \warning Only clears the mip 0 of the texture. - * \param data_format: data format of the pixel data. \note The format is float for unorm textures. + * \param data_format: data format of the pixel data. + * \note The format is float for unorm textures. * \param data: 1 pixel worth of data to fill the texture with. */ void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 568462ec2a6..e1c6901470a 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -711,10 +711,10 @@ static char *code_generate_vertex(GPUNodeGraph *graph, LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { const char *type_str = gpu_data_type_to_string(attr->gputype); const char *prefix = attr_prefix_get(attr->type); - /* XXX FIXME : see notes in mesh_render_data_create() */ - /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ + /* XXX FIXME: see notes in mesh_render_data_create() */ + /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ if (attr->type == CD_ORCO) { - /* OPTI : orco is computed from local positions, but only if no modifier is present. */ + /* OPTI: orco is computed from local positions, but only if no modifier is present. */ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n"); } diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index 5b1eac2e82f..28f5b8b02b0 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -437,7 +437,7 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read, fb_read->blit_to(blit_buffers, read_slot, fb_write, write_slot, 0, 0); - /* FIXME(fclem) sRGB is not saved. */ + /* FIXME(@fclem): sRGB is not saved. */ prev_fb->bind(true); } diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh index a936e889e57..e7505258d2a 100644 --- a/source/blender/gpu/intern/gpu_framebuffer_private.hh +++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh @@ -43,8 +43,9 @@ typedef enum GPUAttachmentType : int { GPU_FB_COLOR_ATTACHMENT3, GPU_FB_COLOR_ATTACHMENT4, GPU_FB_COLOR_ATTACHMENT5, - /* Number of maximum output slots. - * We support 6 outputs for now (usually we wouldn't need more to preserve fill rate). */ + GPU_FB_COLOR_ATTACHMENT6, + GPU_FB_COLOR_ATTACHMENT7, + /* Number of maximum output slots. */ /* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to * the maximum number of COLOR attachments specified by glDrawBuffers. */ GPU_FB_MAX_ATTACHMENT, diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 958aab65b57..afef0e70ccc 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -43,22 +43,22 @@ * \{ */ /* Internal algorithm used */ -enum { +typedef enum eGPUSelectAlgo { /** glBegin/EndQuery(GL_SAMPLES_PASSED... ), `gpu_select_query.c` * Only sets 4th component (ID) correctly. */ ALGO_GL_QUERY = 1, /** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c` * Only sets 4th component (ID) correctly. */ ALGO_GL_PICK = 2, -}; +} eGPUSelectAlgo; typedef struct GPUSelectState { /* To ignore selection id calls when not initialized */ bool select_is_active; /* mode of operation */ - char mode; + eGPUSelectMode mode; /* internal algorithm for selection */ - char algorithm; + eGPUSelectAlgo algorithm; /* allow GPU_select_begin/end without drawing */ bool use_cache; /** @@ -80,7 +80,11 @@ static GPUSelectState g_select_state = {0}; /** \name Public API * \{ */ -void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits) +void GPU_select_begin(GPUSelectResult *buffer, + const uint buffer_len, + const rcti *input, + eGPUSelectMode mode, + int oldhits) { if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { /* In the case hits was '-1', @@ -119,12 +123,12 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, switch (g_select_state.algorithm) { case ALGO_GL_QUERY: { - gpu_select_query_begin((uint(*)[4])buffer, bufsize / 4, input, mode, oldhits); + gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits); break; } default: /* ALGO_GL_PICK */ { - gpu_select_pick_begin((uint(*)[4])buffer, bufsize / 4, input, mode); + gpu_select_pick_begin(buffer, buffer_len, input, mode); break; } } @@ -219,35 +223,35 @@ bool GPU_select_is_cached(void) /** \name Utilities * \{ */ -const uint *GPU_select_buffer_near(const uint *buffer, int hits) +const GPUSelectResult *GPU_select_buffer_near(const GPUSelectResult *buffer, int hits) { - const uint *buffer_near = NULL; + const GPUSelectResult *buffer_near = NULL; uint depth_min = (uint)-1; for (int i = 0; i < hits; i++) { - if (buffer[1] < depth_min) { - BLI_assert(buffer[3] != -1); - depth_min = buffer[1]; + if (buffer->depth < depth_min) { + BLI_assert(buffer->id != -1); + depth_min = buffer->depth; buffer_near = buffer; } - buffer += 4; + buffer++; } return buffer_near; } -uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id) +uint GPU_select_buffer_remove_by_id(GPUSelectResult *buffer, int hits, uint select_id) { - uint *buffer_src = buffer; - uint *buffer_dst = buffer; + GPUSelectResult *buffer_src = buffer; + GPUSelectResult *buffer_dst = buffer; int hits_final = 0; for (int i = 0; i < hits; i++) { - if (buffer_src[3] != select_id) { + if (buffer_src->id != select_id) { if (buffer_dst != buffer_src) { - memcpy(buffer_dst, buffer_src, sizeof(int[4])); + memcpy(buffer_dst, buffer_src, sizeof(GPUSelectResult)); } - buffer_dst += 4; + buffer_dst++; hits_final += 1; } - buffer_src += 4; + buffer_src++; } return hits_final; } diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index ddd3dfc6879..a5c0b2b1a14 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -55,15 +55,19 @@ /** \name #SubRectStride * \{ */ -/* For looping over a sub-region of a rect, could be moved into 'rct.c'. */ +/** For looping over a sub-region of a #rcti, could be moved into 'rct.c'. */ typedef struct SubRectStride { - uint start; /* start here */ - uint span; /* read these */ - uint span_len; /* len times (read span 'len' times). */ - uint skip; /* skip those */ + /** Start here. */ + uint start; + /** Read these. */ + uint span; + /** `len` times (read span 'len' times). */ + uint span_len; + /** Skip those. */ + uint skip; } SubRectStride; -/* we may want to change back to float if uint isn't well supported */ +/** We may want to change back to float if `uint` isn't well supported. */ typedef uint depth_t; /** @@ -104,11 +108,11 @@ BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr) /* -------------------------------------------------------------------- */ /** \name #DepthBufCache * - * Result of reading #glReadPixels, + * Result of reading #GPU_framebuffer_read_depth, * use for both cache and non-cached storage. * \{ */ -/** Store result of #glReadPixels. */ +/** Store result of #GPU_framebuffer_read_depth. */ typedef struct DepthBufCache { struct DepthBufCache *next, *prev; uint id; @@ -174,7 +178,7 @@ static bool depth_buf_subrect_depth_any_filled(const DepthBufCache *rect_src, const DepthBufCache *rect_dst, const SubRectStride *sub_rect) { - /* same as above but different rect sizes */ + /* Same as above but different rectangle sizes. */ const depth_t *prev = rect_src->buf + sub_rect->start; const depth_t *curr = rect_dst->buf + sub_rect->start; for (uint i = 0; i < sub_rect->span_len; i++) { @@ -235,66 +239,68 @@ static int depth_cmp(const void *v1, const void *v2) /** \name Main Selection Begin/End/Load API * \{ */ -/* depth sorting */ +/** Depth sorting. */ typedef struct GPUPickState { - /* cache on initialization */ - uint (*buffer)[4]; + /** Cache on initialization. */ + GPUSelectResult *buffer; + uint buffer_len; + /** Mode of this operation. */ + eGPUSelectMode mode; - /* Buffer size (stores number of integers, for actual size multiply by sizeof integer). */ - uint bufsize; - /* mode of operation */ - char mode; - - /* OpenGL drawing, never use when (is_cached == true). */ + /** GPU drawing, never use when `is_cached == true`. */ struct { - /* The current depth, accumulated as we draw */ + /** The current depth, accumulated while drawing. */ DepthBufCache *rect_depth; - /* Scratch buffer, avoid allocs every time (when not caching) */ + /** Scratch buffer, avoid allocations every time (when not caching). */ DepthBufCache *rect_depth_test; - /* Pass to glReadPixels (x, y, w, h) */ + /** Pass to `GPU_framebuffer_read_depth(x, y, w, h)`. */ int clip_readpixels[4]; - /* Set after first draw */ + /** Set after first draw. */ bool is_init; uint prev_id; - } gl; + } gpu; - /* src: data stored in 'cache' and 'gl', - * dst: use when cached region is smaller (where src -> dst isn't 1:1) */ + /** + * `src`: data stored in 'cache' and 'gpu', + * `dst`: use when cached region is smaller (where `src` -> `dst` isn't 1:1). + */ struct { rcti clip_rect; uint rect_len; } src, dst; - /* Store cache between `GPU_select_cache_begin/end` */ + /** Store cache between `GPU_select_cache_begin/end` */ bool use_cache; bool is_cached; struct { - /* Cleanup used for iterating over both source and destination buffers: - * src.clip_rect -> dst.clip_rect */ + /** + * Cleanup used for iterating over both source and destination buffers: + * `src.clip_rect` -> `dst.clip_rect`. + */ SubRectStride sub_rect; - /* List of DepthBufCache, sized of 'src.clip_rect' */ + /** List of #DepthBufCache, sized of 'src.clip_rect'. */ ListBase bufs; } cache; - /* Picking methods. */ + /** Picking methods. */ union { - /* GPU_SELECT_PICK_ALL */ + /** #GPU_SELECT_PICK_ALL */ struct { DepthID *hits; uint hits_len; uint hits_len_alloc; } all; - /* GPU_SELECT_PICK_NEAREST */ + /** #GPU_SELECT_PICK_NEAREST */ struct { uint *rect_id; } nearest; }; - /* Previous state to restore after drawing. */ + /** Previous state to restore after drawing. */ int viewport[4]; int scissor[4]; eGPUWriteMask write_mask; @@ -303,37 +309,44 @@ typedef struct GPUPickState { static GPUPickState g_pick_state = {0}; -void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode) +void gpu_select_pick_begin(GPUSelectResult *buffer, + const uint buffer_len, + const rcti *input, + eGPUSelectMode mode) { GPUPickState *ps = &g_pick_state; #ifdef DEBUG_PRINT - printf("%s: mode=%d, use_cache=%d, is_cache=%d\n", __func__, mode, ps->use_cache, ps->is_cached); + printf("%s: mode=%d, use_cache=%d, is_cache=%d\n", + __func__, + (int)mode, + ps->use_cache, + ps->is_cached); #endif GPU_debug_group_begin("Selection Pick"); - ps->bufsize = bufsize; ps->buffer = buffer; + ps->buffer_len = buffer_len; ps->mode = mode; const uint rect_len = (uint)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input)); ps->dst.clip_rect = *input; ps->dst.rect_len = rect_len; - /* Restrict OpenGL operations for when we don't have cache */ + /* Avoids unnecessary GPU operations when cache is available and they are unnecessary. */ if (ps->is_cached == false) { ps->write_mask = GPU_write_mask_get(); ps->depth_test = GPU_depth_test_get(); GPU_scissor_get(ps->scissor); - /* disable writing to the framebuffer */ + /* Disable writing to the frame-buffer. */ GPU_color_mask(false, false, false, false); GPU_depth_mask(true); - /* Always use #GL_LEQUAL even though GPU_SELECT_PICK_ALL always clears the buffer. This is - * because individual objects themselves might have sections that overlap and we need these - * to have the correct distance information. */ + /* Always use #GPU_DEPTH_LESS_EQUAL even though #GPU_SELECT_PICK_ALL always clears the buffer. + * This is because individual objects themselves might have sections that overlap and we need + * these to have the correct distance information. */ GPU_depth_test(GPU_DEPTH_LESS_EQUAL); float viewport[4]; @@ -342,35 +355,35 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c ps->src.clip_rect = *input; ps->src.rect_len = rect_len; - ps->gl.clip_readpixels[0] = (int)viewport[0]; - ps->gl.clip_readpixels[1] = (int)viewport[1]; - ps->gl.clip_readpixels[2] = BLI_rcti_size_x(&ps->src.clip_rect); - ps->gl.clip_readpixels[3] = BLI_rcti_size_y(&ps->src.clip_rect); + ps->gpu.clip_readpixels[0] = (int)viewport[0]; + ps->gpu.clip_readpixels[1] = (int)viewport[1]; + ps->gpu.clip_readpixels[2] = BLI_rcti_size_x(&ps->src.clip_rect); + ps->gpu.clip_readpixels[3] = BLI_rcti_size_y(&ps->src.clip_rect); - GPU_viewport(UNPACK4(ps->gl.clip_readpixels)); + GPU_viewport(UNPACK4(ps->gpu.clip_readpixels)); /* It's possible we don't want to clear depth buffer, * so existing elements are masked by current z-buffer. */ GPU_clear_depth(1.0f); /* scratch buffer (read new values here) */ - ps->gl.rect_depth_test = depth_buf_malloc(rect_len); - ps->gl.rect_depth = depth_buf_malloc(rect_len); + ps->gpu.rect_depth_test = depth_buf_malloc(rect_len); + ps->gpu.rect_depth = depth_buf_malloc(rect_len); - /* set initial 'far' value */ + /* Set initial 'far' value. */ for (uint i = 0; i < rect_len; i++) { - ps->gl.rect_depth->buf[i] = DEPTH_MAX; + ps->gpu.rect_depth->buf[i] = DEPTH_MAX; } - ps->gl.is_init = false; - ps->gl.prev_id = 0; + ps->gpu.is_init = false; + ps->gpu.prev_id = 0; } else { - /* Using cache (ps->is_cached == true) */ - /* src.clip_rect -> dst.clip_rect */ + /* Using cache `ps->is_cached == true`. */ + /* `src.clip_rect` -> `dst.clip_rect`. */ rect_subregion_stride_calc(&ps->src.clip_rect, &ps->dst.clip_rect, &ps->cache.sub_rect); - BLI_assert(ps->gl.rect_depth == NULL); - BLI_assert(ps->gl.rect_depth_test == NULL); + BLI_assert(ps->gpu.rect_depth == NULL); + BLI_assert(ps->gpu.rect_depth_test == NULL); } if (mode == GPU_SELECT_PICK_ALL) { @@ -379,7 +392,7 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c ps->all.hits_len_alloc = ALLOC_DEPTHS; } else { - /* Set to 0xff for SELECT_ID_NONE */ + /* Set to 0xff for #SELECT_ID_NONE. */ ps->nearest.rect_id = MEM_mallocN(sizeof(uint) * ps->dst.rect_len, __func__); memset(ps->nearest.rect_id, 0xff, sizeof(uint) * ps->dst.rect_len); } @@ -411,7 +424,7 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr) } } else { - /* same as above but different rect sizes */ + /* Same as above but different rectangle sizes. */ const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start; for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) { const depth_t *curr_end = curr + ps->cache.sub_rect.span; @@ -424,7 +437,7 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr) #undef EVAL_TEST - /* ensure enough space */ + /* Ensure enough space. */ if (UNLIKELY(ps->all.hits_len == ps->all.hits_len_alloc)) { ps->all.hits_len_alloc += ALLOC_DEPTHS; ps->all.hits = MEM_reallocN(ps->all.hits, ps->all.hits_len_alloc * sizeof(*ps->all.hits)); @@ -439,7 +452,7 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, { GPUPickState *ps = &g_pick_state; const uint id = rect_curr->id; - /* keep track each pixels ID in 'nearest.rect_id' */ + /* Keep track each pixels ID in `nearest.rect_id`. */ if (id != SELECT_ID_NONE) { uint *id_ptr = ps->nearest.rect_id; @@ -483,8 +496,8 @@ bool gpu_select_pick_load_id(uint id, bool end) { GPUPickState *ps = &g_pick_state; - if (ps->gl.is_init) { - if (id == ps->gl.prev_id && !end) { + if (ps->gpu.is_init) { + if (id == ps->gpu.prev_id && !end) { /* No need to read if we are still drawing for the same id since * all these depths will be merged / de-duplicated in the end. */ return true; @@ -493,21 +506,21 @@ bool gpu_select_pick_load_id(uint id, bool end) const uint rect_len = ps->src.rect_len; GPUFrameBuffer *fb = GPU_framebuffer_active_get(); GPU_framebuffer_read_depth( - fb, UNPACK4(ps->gl.clip_readpixels), GPU_DATA_UINT, ps->gl.rect_depth_test->buf); + fb, UNPACK4(ps->gpu.clip_readpixels), GPU_DATA_UINT, ps->gpu.rect_depth_test->buf); /* Perform initial check since most cases the array remains unchanged. */ bool do_pass = false; if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { - if (depth_buf_rect_depth_any(ps->gl.rect_depth_test, rect_len)) { - ps->gl.rect_depth_test->id = ps->gl.prev_id; - gpu_select_load_id_pass_all(ps->gl.rect_depth_test); + if (depth_buf_rect_depth_any(ps->gpu.rect_depth_test, rect_len)) { + ps->gpu.rect_depth_test->id = ps->gpu.prev_id; + gpu_select_load_id_pass_all(ps->gpu.rect_depth_test); do_pass = true; } } else { - if (depth_buf_rect_depth_any_filled(ps->gl.rect_depth, ps->gl.rect_depth_test, rect_len)) { - ps->gl.rect_depth_test->id = ps->gl.prev_id; - gpu_select_load_id_pass_nearest(ps->gl.rect_depth, ps->gl.rect_depth_test); + if (depth_buf_rect_depth_any_filled(ps->gpu.rect_depth, ps->gpu.rect_depth_test, rect_len)) { + ps->gpu.rect_depth_test->id = ps->gpu.prev_id; + gpu_select_load_id_pass_nearest(ps->gpu.rect_depth, ps->gpu.rect_depth_test); do_pass = true; } } @@ -515,11 +528,11 @@ bool gpu_select_pick_load_id(uint id, bool end) if (do_pass) { /* Store depth in cache */ if (ps->use_cache) { - BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth); - ps->gl.rect_depth = depth_buf_malloc(ps->src.rect_len); + BLI_addtail(&ps->cache.bufs, ps->gpu.rect_depth); + ps->gpu.rect_depth = depth_buf_malloc(ps->src.rect_len); } - SWAP(DepthBufCache *, ps->gl.rect_depth, ps->gl.rect_depth_test); + SWAP(DepthBufCache *, ps->gpu.rect_depth, ps->gpu.rect_depth_test); if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { /* (fclem) This is to be on the safe side. I don't know if this is required. */ @@ -533,8 +546,8 @@ bool gpu_select_pick_load_id(uint id, bool end) } } - ps->gl.is_init = true; - ps->gl.prev_id = id; + ps->gpu.is_init = true; + ps->gpu.prev_id = id; return true; } @@ -548,9 +561,9 @@ uint gpu_select_pick_end(void) #endif if (ps->is_cached == false) { - if (ps->gl.is_init) { + if (ps->gpu.is_init) { /* force finishing last pass */ - gpu_select_pick_load_id(ps->gl.prev_id, true); + gpu_select_pick_load_id(ps->gpu.prev_id, true); } GPU_write_mask(ps->write_mask); GPU_depth_test(ps->depth_test); @@ -559,39 +572,39 @@ uint gpu_select_pick_end(void) GPU_debug_group_end(); - /* assign but never free directly since it may be in cache */ + /* Assign but never free directly since it may be in cache. */ DepthBufCache *rect_depth_final; /* Store depth in cache */ if (ps->use_cache && !ps->is_cached) { - BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth); - ps->gl.rect_depth = NULL; + BLI_addtail(&ps->cache.bufs, ps->gpu.rect_depth); + ps->gpu.rect_depth = NULL; rect_depth_final = ps->cache.bufs.last; } else if (ps->is_cached) { rect_depth_final = ps->cache.bufs.last; } else { - /* common case, no cache */ - rect_depth_final = ps->gl.rect_depth; + /* Common case, no cache. */ + rect_depth_final = ps->gpu.rect_depth; } - uint maxhits = g_pick_state.bufsize; + uint maxhits = g_pick_state.buffer_len; DepthID *depth_data; uint depth_data_len = 0; if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { depth_data = ps->all.hits; depth_data_len = ps->all.hits_len; - /* move ownership */ + /* Move ownership. */ ps->all.hits = NULL; ps->all.hits_len = 0; ps->all.hits_len_alloc = 0; } else { - /* GPU_SELECT_PICK_NEAREST */ + /* #GPU_SELECT_PICK_NEAREST */ - /* Over alloc (unlikely we have as many depths as pixels) */ + /* Over allocate (unlikely we have as many depths as pixels). */ uint depth_data_len_first_pass = 0; depth_data = MEM_mallocN(ps->dst.rect_len * sizeof(*depth_data), __func__); @@ -624,7 +637,7 @@ uint gpu_select_pick_end(void) } } else { - /* same as above but different rect sizes */ + /* Same as above but different rectangle sizes. */ uint i_src = ps->cache.sub_rect.start, i_dst = 0; for (uint j = 0; j < ps->cache.sub_rect.span_len; j++) { const uint i_src_end = i_src + ps->cache.sub_rect.span; @@ -640,7 +653,7 @@ uint gpu_select_pick_end(void) qsort(depth_data, depth_data_len_first_pass, sizeof(DepthID), depth_id_cmp); - /* Sort by ID's then keep the best depth for each ID */ + /* Sort by ID's then keep the best depth for each ID. */ depth_data_len = 0; { DepthID *depth_last = NULL; @@ -657,25 +670,22 @@ uint gpu_select_pick_end(void) } /* Finally sort each unique (id, depth) pair by depth - * so the final hit-list is sorted by depth (nearest first) */ + * so the final hit-list is sorted by depth (nearest first). */ uint hits = 0; if (depth_data_len > maxhits) { hits = (uint)-1; } else { - /* leave sorting up to the caller */ + /* Leave sorting up to the caller. */ qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp); for (uint i = 0; i < depth_data_len; i++) { #ifdef DEBUG_PRINT printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth); #endif - /* first 3 are dummy values */ - g_pick_state.buffer[hits][0] = 1; - g_pick_state.buffer[hits][1] = depth_data[i].depth; - g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */ - g_pick_state.buffer[hits][3] = depth_data[i].id; + g_pick_state.buffer[hits].depth = depth_data[i].depth; + g_pick_state.buffer[hits].id = depth_data[i].id; hits++; } BLI_assert(hits < maxhits); @@ -683,8 +693,8 @@ uint gpu_select_pick_end(void) MEM_freeN(depth_data); - MEM_SAFE_FREE(ps->gl.rect_depth); - MEM_SAFE_FREE(ps->gl.rect_depth_test); + MEM_SAFE_FREE(ps->gpu.rect_depth); + MEM_SAFE_FREE(ps->gpu.rect_depth_test); if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { /* 'hits' already freed as 'depth_data' */ @@ -744,8 +754,8 @@ void gpu_select_pick_cache_load_id(void) #endif LISTBASE_FOREACH (DepthBufCache *, rect_depth, &ps->cache.bufs) { if (rect_depth->next != NULL) { - /* we know the buffers differ, but this sub-region may not. - * double check before adding an id-pass */ + /* We know the buffers differ, but this sub-region may not. + * Double check before adding an id-pass. */ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { if (depth_buf_subrect_depth_any(rect_depth->next, &ps->cache.sub_rect)) { gpu_select_load_id_pass_all(rect_depth->next); diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h index e5a84a037a6..0ec9f083c07 100644 --- a/source/blender/gpu/intern/gpu_select_private.h +++ b/source/blender/gpu/intern/gpu_select_private.h @@ -31,7 +31,10 @@ extern "C" { /* gpu_select_pick */ -void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode); +void gpu_select_pick_begin(GPUSelectResult *buffer, + uint buffer_len, + const rcti *input, + eGPUSelectMode mode); bool gpu_select_pick_load_id(uint id, bool end); uint gpu_select_pick_end(void); @@ -46,7 +49,7 @@ void gpu_select_pick_cache_load_id(void); /* gpu_select_sample_query */ void gpu_select_query_begin( - uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits); + GPUSelectResult *buffer, uint buffer_len, const rcti *input, eGPUSelectMode mode, int oldhits); bool gpu_select_query_load_id(uint id); uint gpu_select_query_end(void); diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc index a430d4a9d62..7559358aaca 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.cc +++ b/source/blender/gpu/intern/gpu_select_sample_query.cc @@ -48,22 +48,22 @@ using namespace blender; using namespace blender::gpu; struct GPUSelectQueryState { - /* Tracks whether a query has been issued so that gpu_load_id can end the previous one. */ + /** Tracks whether a query has been issued so that gpu_load_id can end the previous one. */ bool query_issued; - /* GPU queries abstraction. Contains an array of queries. */ + /** GPU queries abstraction. Contains an array of queries. */ QueryPool *queries; - /* Array holding the id corresponding id to each query. */ + /** Array holding the id corresponding id to each query. */ Vector<uint> *ids; - /* Cache on initialization. */ - uint (*buffer)[4]; - /* Buffer size (stores number of integers, for actual size multiply by `sizeof(int)`). */ - uint bufsize; - /* Mode of operation. */ - char mode; + /** Cache on initialization. */ + GPUSelectResult *buffer; + /** The capacity of the `buffer` array. */ + uint buffer_len; + /** Mode of operation. */ + eGPUSelectMode mode; uint index; int oldhits; - /* Previous state to restore after drawing. */ + /** Previous state to restore after drawing. */ int viewport[4]; int scissor[4]; eGPUWriteMask write_mask; @@ -72,14 +72,17 @@ struct GPUSelectQueryState { static GPUSelectQueryState g_query_state = {false}; -void gpu_select_query_begin( - uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits) +void gpu_select_query_begin(GPUSelectResult *buffer, + uint buffer_len, + const rcti *input, + const eGPUSelectMode mode, + int oldhits) { GPU_debug_group_begin("Selection Queries"); g_query_state.query_issued = false; - g_query_state.bufsize = bufsize; g_query_state.buffer = buffer; + g_query_state.buffer_len = buffer_len; g_query_state.mode = mode; g_query_state.index = 0; g_query_state.oldhits = oldhits; @@ -111,7 +114,7 @@ void gpu_select_query_begin( /* occlusion queries operates on fragments that pass tests and since we are interested on all * objects in the view frustum independently of their order, we need to disable the depth test */ if (mode == GPU_SELECT_ALL) { - /* glQueries on Windows+Intel drivers only works with depth testing turned on. + /* #glQueries on Windows+Intel drivers only works with depth testing turned on. * See T62947 for details */ GPU_depth_test(GPU_DEPTH_ALWAYS); GPU_depth_mask(true); @@ -138,10 +141,11 @@ bool gpu_select_query_load_id(uint id) g_query_state.query_issued = true; if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { - /* Second pass should never run if first pass fails, can read past 'bufsize' in this case. */ + /* Second pass should never run if first pass fails, + * can read past `buffer_len` in this case. */ BLI_assert(g_query_state.oldhits != -1); if (g_query_state.index < g_query_state.oldhits) { - if (g_query_state.buffer[g_query_state.index][3] == id) { + if (g_query_state.buffer[g_query_state.index].id == id) { g_query_state.index++; return true; } @@ -154,7 +158,7 @@ bool gpu_select_query_load_id(uint id) uint gpu_select_query_end() { uint hits = 0; - const uint maxhits = g_query_state.bufsize; + const uint maxhits = g_query_state.buffer_len; if (g_query_state.query_issued) { g_query_state.queries->end_query(); @@ -168,10 +172,8 @@ uint gpu_select_query_end() if (result[i] != 0) { if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { if (hits < maxhits) { - g_query_state.buffer[hits][0] = 1; - g_query_state.buffer[hits][1] = 0xFFFF; - g_query_state.buffer[hits][2] = 0xFFFF; - g_query_state.buffer[hits][3] = ids[i]; + g_query_state.buffer[hits].depth = 0xFFFF; + g_query_state.buffer[hits].id = ids[i]; hits++; } else { @@ -183,9 +185,8 @@ uint gpu_select_query_end() int j; /* search in buffer and make selected object first */ for (j = 0; j < g_query_state.oldhits; j++) { - if (g_query_state.buffer[j][3] == ids[i]) { - g_query_state.buffer[j][1] = 0; - g_query_state.buffer[j][2] = 0; + if (g_query_state.buffer[j].id == ids[i]) { + g_query_state.buffer[j].depth = 0; } } break; diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 2d6b1d171b0..7db34917ad7 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -250,6 +250,11 @@ GPUShader *GPU_shader_create_compute(const char *computecode, shname); } +const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name) +{ + return gpu_shader_create_info_get(info_name); +} + GPUShader *GPU_shader_create_from_info_name(const char *info_name) { using namespace blender::gpu::shader; @@ -299,22 +304,23 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) std::string defines = shader->defines_declare(info); std::string resources = shader->resources_declare(info); - char *shader_shared_utils = nullptr; defines += "#define USE_GPU_SHADER_CREATE_INFO\n"; - Vector<char *> typedefs; - for (auto filename : info.typedef_sources_) { - typedefs.append(gpu_shader_dependency_get_source(filename.c_str())); + Vector<const char *> typedefs; + if (!info.typedef_sources_.is_empty() || !info.typedef_source_generated.empty()) { + typedefs.append(gpu_shader_dependency_get_source("GPU_shader_shared_utils.h").c_str()); + } + if (!info.typedef_source_generated.empty()) { + typedefs.append(info.typedef_source_generated.c_str()); } - if (!typedefs.is_empty()) { - shader_shared_utils = gpu_shader_dependency_get_source("gpu_shader_shared_utils.h"); + for (auto filename : info.typedef_sources_) { + typedefs.append(gpu_shader_dependency_get_source(filename).c_str()); } if (!info.vertex_source_.is_empty()) { - uint32_t builtins = 0; + auto code = gpu_shader_dependency_get_resolved_source(info.vertex_source_); std::string interface = shader->vertex_interface_declare(info); - char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str(), &builtins); Vector<const char *> sources; standard_defines(sources); @@ -323,26 +329,19 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) sources.append("#define USE_GEOMETRY_SHADER\n"); } sources.append(defines.c_str()); - if (!typedefs.is_empty()) { - sources.append(shader_shared_utils); - } - for (auto *types : typedefs) { - sources.append(types); - } + sources.extend(typedefs); sources.append(resources.c_str()); sources.append(interface.c_str()); - sources.append(code); + sources.extend(code); + sources.extend(info.dependencies_generated); + sources.append(info.vertex_source_generated.c_str()); shader->vertex_shader_from_glsl(sources); - - free(code); } if (!info.fragment_source_.is_empty()) { - uint32_t builtins = 0; + auto code = gpu_shader_dependency_get_resolved_source(info.fragment_source_); std::string interface = shader->fragment_interface_declare(info); - char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str(), - &builtins); Vector<const char *> sources; standard_defines(sources); @@ -351,79 +350,48 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) sources.append("#define USE_GEOMETRY_SHADER\n"); } sources.append(defines.c_str()); - if (!typedefs.is_empty()) { - sources.append(shader_shared_utils); - } - for (auto *types : typedefs) { - sources.append(types); - } + sources.extend(typedefs); sources.append(resources.c_str()); sources.append(interface.c_str()); - sources.append(code); + sources.extend(code); + sources.extend(info.dependencies_generated); + sources.append(info.fragment_source_generated.c_str()); shader->fragment_shader_from_glsl(sources); - - free(code); } if (!info.geometry_source_.is_empty()) { - uint32_t builtins = 0; - std::string interface = shader->geometry_interface_declare(info); + auto code = gpu_shader_dependency_get_resolved_source(info.geometry_source_); std::string layout = shader->geometry_layout_declare(info); - char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str(), - &builtins); + std::string interface = shader->geometry_interface_declare(info); Vector<const char *> sources; standard_defines(sources); sources.append("#define GPU_GEOMETRY_SHADER\n"); sources.append(defines.c_str()); - if (!typedefs.is_empty()) { - sources.append(shader_shared_utils); - } - for (auto *types : typedefs) { - sources.append(types); - } + sources.extend(typedefs); sources.append(resources.c_str()); sources.append(layout.c_str()); sources.append(interface.c_str()); - sources.append(code); + sources.extend(code); shader->geometry_shader_from_glsl(sources); - - free(code); } if (!info.compute_source_.is_empty()) { - uint32_t builtins = 0; - char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str(), - &builtins); + auto code = gpu_shader_dependency_get_resolved_source(info.compute_source_); std::string layout = shader->compute_layout_declare(info); Vector<const char *> sources; standard_defines(sources); sources.append("#define GPU_COMPUTE_SHADER\n"); sources.append(defines.c_str()); - if (!typedefs.is_empty()) { - sources.append(shader_shared_utils); - } - for (auto *types : typedefs) { - sources.append(types); - } + sources.extend(typedefs); sources.append(resources.c_str()); sources.append(layout.c_str()); - sources.append(code); + sources.extend(code); shader->compute_shader_from_glsl(sources); - - free(code); - } - - for (auto *types : typedefs) { - free(types); - } - - if (shader_shared_utils) { - free(shader_shared_utils); } if (!shader->finalize(&info)) { diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc index 492b247e192..fe0304828c2 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.cc +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -34,6 +34,7 @@ #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 @@ -54,6 +55,8 @@ void ShaderCreateInfo::finalize() } finalized_ = true; + Set<StringRefNull> deps_merged; + for (auto &info_name : additional_infos_) { const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>( gpu_shader_create_info_get(info_name.c_str())); @@ -61,11 +64,6 @@ void ShaderCreateInfo::finalize() /* Recursive. */ const_cast<ShaderCreateInfo &>(info).finalize(); -#if 0 /* Enabled for debugging merging. TODO(fclem) exception handling and error reporting in \ - console. */ - std::cout << "Merging : " << info_name << " > " << name_ << std::endl; -#endif - interface_names_size_ += info.interface_names_size_; vertex_inputs_.extend(info.vertex_inputs_); @@ -82,37 +80,76 @@ void ShaderCreateInfo::finalize() validate(info); + auto assert_no_overlap = [&](const bool test, const StringRefNull error) { + if (!test) { + std::cout << name_ << ": Validation failed while merging " << info.name_ << " : "; + std::cout << error << std::endl; + BLI_assert(0); + } + }; + + if (!deps_merged.add(info.name_)) { + assert_no_overlap(false, "additional info already merged via another info"); + } + if (info.compute_layout_.local_size_x != -1) { - compute_layout_.local_size_x = info.compute_layout_.local_size_x; - compute_layout_.local_size_y = info.compute_layout_.local_size_y; - compute_layout_.local_size_z = info.compute_layout_.local_size_z; + assert_no_overlap(compute_layout_.local_size_x == -1, "Compute layout already defined"); + compute_layout_ = info.compute_layout_; } if (!info.vertex_source_.is_empty()) { - BLI_assert(vertex_source_.is_empty()); + assert_no_overlap(vertex_source_.is_empty(), "Vertex source already existing"); vertex_source_ = info.vertex_source_; } if (!info.geometry_source_.is_empty()) { - BLI_assert(geometry_source_.is_empty()); + assert_no_overlap(geometry_source_.is_empty(), "Geometry source already existing"); geometry_source_ = info.geometry_source_; geometry_layout_ = info.geometry_layout_; } if (!info.fragment_source_.is_empty()) { - BLI_assert(fragment_source_.is_empty()); + assert_no_overlap(fragment_source_.is_empty(), "Fragment source already existing"); fragment_source_ = info.fragment_source_; } if (!info.compute_source_.is_empty()) { - BLI_assert(compute_source_.is_empty()); + assert_no_overlap(compute_source_.is_empty(), "Compute source already existing"); compute_source_ = info.compute_source_; } do_static_compilation_ = do_static_compilation_ || info.do_static_compilation_; } + + if (auto_resource_location_) { + int images = 0, samplers = 0, ubos = 0, ssbos = 0; + + auto set_resource_slot = [&](Resource &res) { + switch (res.bind_type) { + case Resource::BindType::UNIFORM_BUFFER: + res.slot = ubos++; + break; + case Resource::BindType::STORAGE_BUFFER: + res.slot = ssbos++; + break; + case Resource::BindType::SAMPLER: + res.slot = samplers++; + break; + case Resource::BindType::IMAGE: + res.slot = images++; + break; + } + }; + + for (auto &res : batch_resources_) { + set_resource_slot(res); + } + for (auto &res : pass_resources_) { + set_resource_slot(res); + } + } } void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info) { - { + if (!auto_resource_location_) { /* Check same bind-points usage in OGL. */ Set<int> images, samplers, ubos, ssbos; @@ -132,26 +169,26 @@ void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info) }; auto print_error_msg = [&](const Resource &res) { - std::cerr << name_ << ": Validation failed : Overlapping "; + std::cout << name_ << ": Validation failed : Overlapping "; switch (res.bind_type) { case Resource::BindType::UNIFORM_BUFFER: - std::cerr << "Uniform Buffer " << res.uniformbuf.name; + std::cout << "Uniform Buffer " << res.uniformbuf.name; break; case Resource::BindType::STORAGE_BUFFER: - std::cerr << "Storage Buffer " << res.storagebuf.name; + std::cout << "Storage Buffer " << res.storagebuf.name; break; case Resource::BindType::SAMPLER: - std::cerr << "Sampler " << res.sampler.name; + std::cout << "Sampler " << res.sampler.name; break; case Resource::BindType::IMAGE: - std::cerr << "Image " << res.image.name; + std::cout << "Image " << res.image.name; break; default: - std::cerr << "Unknown Type"; + std::cout << "Unknown Type"; break; } - std::cerr << " (" << res.slot << ") while merging " << other_info.name_ << std::endl; + std::cout << " (" << res.slot << ") while merging " << other_info.name_ << std::endl; }; for (auto &res : batch_resources_) { @@ -167,7 +204,7 @@ void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info) } } { - /* TODO(fclem) Push constant validation. */ + /* TODO(@fclem): Push constant validation. */ } } @@ -209,6 +246,15 @@ void gpu_shader_create_info_init() draw_modelmat = draw_modelmat_legacy; } + for (ShaderCreateInfo *info : g_create_infos->values()) { + if (info->do_static_compilation_) { + info->builtins_ |= gpu_shader_dependency_get_builtins(info->vertex_source_); + info->builtins_ |= gpu_shader_dependency_get_builtins(info->fragment_source_); + info->builtins_ |= gpu_shader_dependency_get_builtins(info->geometry_source_); + info->builtins_ |= gpu_shader_dependency_get_builtins(info->compute_source_); + } + } + /* TEST */ // gpu_shader_create_info_compile_all(); } @@ -302,6 +348,7 @@ const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name) { if (g_create_infos->contains(info_name) == false) { printf("Error: Cannot find shader create info named \"%s\"\n", info_name); + return nullptr; } ShaderCreateInfo *info = g_create_infos->lookup(info_name); return reinterpret_cast<const GPUShaderCreateInfo *>(info); diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index 63c6e94f4c8..dafa741977c 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -30,8 +30,11 @@ #include "BLI_string_ref.hh" #include "BLI_vector.hh" +#include "GPU_material.h" #include "GPU_texture.h" +#include <iostream> + namespace blender::gpu::shader { #ifndef GPU_SHADER_CREATE_INFO @@ -62,7 +65,61 @@ enum class Type { BOOL, }; +/* All of these functions is a bit out of place */ +static inline Type to_type(const eGPUType type) +{ + switch (type) { + case GPU_FLOAT: + return Type::FLOAT; + case GPU_VEC2: + return Type::VEC2; + case GPU_VEC3: + return Type::VEC3; + case GPU_VEC4: + return Type::VEC4; + case GPU_MAT3: + return Type::MAT3; + case GPU_MAT4: + return Type::MAT4; + default: + BLI_assert_msg(0, "Error: Cannot convert eGPUType to shader::Type."); + return Type::FLOAT; + } +} + +static inline std::ostream &operator<<(std::ostream &stream, const Type type) +{ + switch (type) { + case Type::FLOAT: + return stream << "float"; + case Type::VEC2: + return stream << "vec2"; + case Type::VEC3: + return stream << "vec3"; + case Type::VEC4: + return stream << "vec4"; + case Type::MAT3: + return stream << "mat3"; + case Type::MAT4: + return stream << "mat4"; + default: + BLI_assert(0); + return stream; + } +} + +static inline std::ostream &operator<<(std::ostream &stream, const eGPUType type) +{ + switch (type) { + case GPU_CLOSURE: + return stream << "Closure"; + default: + return stream << to_type(type); + } +} + enum class BuiltinBits { + NONE = 0, /** * Allow getting barycentric coordinates inside the fragment shader. * \note Emulated on OpenGL. @@ -72,6 +129,10 @@ enum class BuiltinBits { FRONT_FACING = (1 << 4), GLOBAL_INVOCATION_ID = (1 << 5), INSTANCE_ID = (1 << 6), + /** + * Allow setting the target layer when the output is a layered frame-buffer. + * \note Emulated through geometry shader on older hardware. + */ LAYER = (1 << 7), LOCAL_INVOCATION_ID = (1 << 8), LOCAL_INVOCATION_INDEX = (1 << 9), @@ -125,10 +186,13 @@ enum class ImageType { /* Storage qualifiers. */ enum class Qualifier { - RESTRICT = (1 << 0), - READ_ONLY = (1 << 1), - WRITE_ONLY = (1 << 2), - QUALIFIER_MAX = (WRITE_ONLY << 1) - 1, + /** Restrict flag is set by default. Unless specified otherwise. */ + NO_RESTRICT = (1 << 0), + READ = (1 << 1), + WRITE = (1 << 2), + /** Shorthand version of combined flags. */ + READ_WRITE = READ | WRITE, + QUALIFIER_MAX = (WRITE << 1) - 1, }; ENUM_OPERATORS(Qualifier, Qualifier::QUALIFIER_MAX); @@ -221,16 +285,45 @@ struct ShaderCreateInfo { bool do_static_compilation_ = false; /** If true, all additionally linked create info will be merged into this one. */ bool finalized_ = false; + /** If true, all resources will have an automatic location assigned. */ + bool auto_resource_location_ = false; /** * Maximum length of all the resource names including each null terminator. * Only for names used by gpu::ShaderInterface. */ size_t interface_names_size_ = 0; + /** Manually set builtins. */ + BuiltinBits builtins_ = BuiltinBits::NONE; + /** Manually set generated code. */ + std::string vertex_source_generated = ""; + std::string fragment_source_generated = ""; + std::string typedef_source_generated = ""; + /** Manually set generated dependencies. */ + Vector<const char *, 0> dependencies_generated; + +#define TEST_EQUAL(a, b, _member) \ + if (!((a)._member == (b)._member)) { \ + return false; \ + } + +#define TEST_VECTOR_EQUAL(a, b, _vector) \ + TEST_EQUAL(a, b, _vector.size()); \ + for (auto i : _vector.index_range()) { \ + TEST_EQUAL(a, b, _vector[i]); \ + } struct VertIn { int index; Type type; StringRefNull name; + + bool operator==(const VertIn &b) + { + TEST_EQUAL(*this, b, index); + TEST_EQUAL(*this, b, type); + TEST_EQUAL(*this, b, name); + return true; + } }; Vector<VertIn> vertex_inputs_; @@ -240,6 +333,15 @@ struct ShaderCreateInfo { PrimitiveOut primitive_out; /** Set to -1 by default to check if used. */ int max_vertices = -1; + + bool operator==(const GeometryStageLayout &b) + { + TEST_EQUAL(*this, b, primitive_in); + TEST_EQUAL(*this, b, invocations); + TEST_EQUAL(*this, b, primitive_out); + TEST_EQUAL(*this, b, max_vertices); + return true; + } }; GeometryStageLayout geometry_layout_; @@ -247,8 +349,15 @@ struct ShaderCreateInfo { int local_size_x = -1; int local_size_y = -1; int local_size_z = -1; - }; + bool operator==(const ComputeStageLayout &b) + { + TEST_EQUAL(*this, b, local_size_x); + TEST_EQUAL(*this, b, local_size_y); + TEST_EQUAL(*this, b, local_size_z); + return true; + } + }; ComputeStageLayout compute_layout_; struct FragOut { @@ -256,6 +365,15 @@ struct ShaderCreateInfo { Type type; DualBlend blend; StringRefNull name; + + bool operator==(const FragOut &b) + { + TEST_EQUAL(*this, b, index); + TEST_EQUAL(*this, b, type); + TEST_EQUAL(*this, b, blend); + TEST_EQUAL(*this, b, name); + return true; + } }; Vector<FragOut> fragment_outputs_; @@ -301,6 +419,35 @@ struct ShaderCreateInfo { }; Resource(BindType type, int _slot) : bind_type(type), slot(_slot){}; + + bool operator==(const Resource &b) + { + TEST_EQUAL(*this, b, bind_type); + TEST_EQUAL(*this, b, slot); + switch (bind_type) { + case UNIFORM_BUFFER: + TEST_EQUAL(*this, b, uniformbuf.type_name); + TEST_EQUAL(*this, b, uniformbuf.name); + break; + case STORAGE_BUFFER: + TEST_EQUAL(*this, b, storagebuf.qualifiers); + TEST_EQUAL(*this, b, storagebuf.type_name); + TEST_EQUAL(*this, b, storagebuf.name); + break; + case SAMPLER: + TEST_EQUAL(*this, b, sampler.type); + TEST_EQUAL(*this, b, sampler.sampler); + TEST_EQUAL(*this, b, sampler.name); + break; + case IMAGE: + TEST_EQUAL(*this, b, image.format); + TEST_EQUAL(*this, b, image.type); + TEST_EQUAL(*this, b, image.qualifiers); + TEST_EQUAL(*this, b, image.name); + break; + } + return true; + } }; /** * Resources are grouped by frequency of change. @@ -317,6 +464,14 @@ struct ShaderCreateInfo { Type type; StringRefNull name; int array_size; + + bool operator==(const PushConst &b) + { + TEST_EQUAL(*this, b, type); + TEST_EQUAL(*this, b, name); + TEST_EQUAL(*this, b, array_size); + return true; + } }; Vector<PushConst> push_constants_; @@ -538,6 +693,18 @@ struct ShaderCreateInfo { return *(Self *)this; } + Self &builtins(BuiltinBits builtin) + { + builtins_ |= builtin; + return *(Self *)this; + } + + Self &auto_resource_location(bool value) + { + auto_resource_location_ = value; + return *(Self *)this; + } + /** \} */ /* -------------------------------------------------------------------- */ @@ -608,6 +775,77 @@ struct ShaderCreateInfo { void validate(const ShaderCreateInfo &other_info); /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Operators. + * + * \{ */ + + /* Comparison operator for GPUPass cache. We only compare if it will create the same shader code. + * So we do not compare name and some other internal stuff. */ + bool operator==(const ShaderCreateInfo &b) + { + TEST_EQUAL(*this, b, builtins_); + TEST_EQUAL(*this, b, vertex_source_generated); + TEST_EQUAL(*this, b, fragment_source_generated); + TEST_EQUAL(*this, b, typedef_source_generated); + TEST_VECTOR_EQUAL(*this, b, vertex_inputs_); + TEST_EQUAL(*this, b, geometry_layout_); + TEST_EQUAL(*this, b, compute_layout_); + TEST_VECTOR_EQUAL(*this, b, fragment_outputs_); + TEST_VECTOR_EQUAL(*this, b, pass_resources_); + TEST_VECTOR_EQUAL(*this, b, batch_resources_); + TEST_VECTOR_EQUAL(*this, b, vertex_out_interfaces_); + TEST_VECTOR_EQUAL(*this, b, geometry_out_interfaces_); + TEST_VECTOR_EQUAL(*this, b, push_constants_); + TEST_VECTOR_EQUAL(*this, b, typedef_sources_); + TEST_EQUAL(*this, b, vertex_source_); + TEST_EQUAL(*this, b, geometry_source_); + TEST_EQUAL(*this, b, fragment_source_); + TEST_EQUAL(*this, b, compute_source_); + TEST_VECTOR_EQUAL(*this, b, additional_infos_); + TEST_VECTOR_EQUAL(*this, b, defines_); + return true; + } + + /** Debug print */ + friend std::ostream &operator<<(std::ostream &stream, const ShaderCreateInfo &info) + { + /* TODO(@fclem): Complete print. */ + + auto print_resource = [&](const Resource &res) { + switch (res.bind_type) { + case Resource::BindType::UNIFORM_BUFFER: + stream << "UNIFORM_BUFFER(" << res.slot << ", " << res.uniformbuf.name << ")" + << std::endl; + break; + case Resource::BindType::STORAGE_BUFFER: + stream << "STORAGE_BUFFER(" << res.slot << ", " << res.storagebuf.name << ")" + << std::endl; + break; + case Resource::BindType::SAMPLER: + stream << "SAMPLER(" << res.slot << ", " << res.sampler.name << ")" << std::endl; + break; + case Resource::BindType::IMAGE: + stream << "IMAGE(" << res.slot << ", " << res.image.name << ")" << std::endl; + break; + } + }; + + /* TODO(@fclem): Order the resources. */ + for (auto &res : info.batch_resources_) { + print_resource(res); + } + for (auto &res : info.pass_resources_) { + print_resource(res); + } + return stream; + } + + /** \} */ + +#undef TEST_EQUAL +#undef TEST_VECTOR_EQUAL }; } // namespace blender::gpu::shader diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc index 5e03f7d0767..06ad0817bfb 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency.cc +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -59,7 +59,6 @@ struct GPUSource { /* Scan for builtins. */ /* FIXME: This can trigger false positive caused by disabled #if blocks. */ /* TODO(fclem): Could be made faster by scanning once. */ - /* TODO(fclem): BARYCENTRIC_COORD. */ if (source.find("gl_FragCoord", 0)) { builtins |= shader::BuiltinBits::FRAG_COORD; } @@ -72,9 +71,6 @@ struct GPUSource { if (source.find("gl_InstanceID", 0)) { builtins |= shader::BuiltinBits::INSTANCE_ID; } - if (source.find("gl_Layer", 0)) { - builtins |= shader::BuiltinBits::LAYER; - } if (source.find("gl_LocalInvocationID", 0)) { builtins |= shader::BuiltinBits::LOCAL_INVOCATION_ID; } @@ -336,13 +332,21 @@ struct GPUSource { } /* Returns the final string with all includes done. */ - void build(std::string &str, shader::BuiltinBits &out_builtins) + void build(Vector<const char *> &result) const + { + for (auto *dep : dependencies) { + result.append(dep->source.c_str()); + } + result.append(source.c_str()); + } + + shader::BuiltinBits builtins_get() const { + shader::BuiltinBits out_builtins = shader::BuiltinBits::NONE; for (auto *dep : dependencies) { - out_builtins |= builtins; - str += dep->source; + out_builtins |= dep->builtins; } - str += source; + return out_builtins; } }; @@ -377,18 +381,47 @@ void gpu_shader_dependency_exit() delete g_sources; } -char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name, uint32_t *builtins) +namespace blender::gpu::shader { + +BuiltinBits gpu_shader_dependency_get_builtins(const StringRefNull shader_source_name) { + if (shader_source_name.is_empty()) { + return shader::BuiltinBits::NONE; + } + if (g_sources->contains(shader_source_name) == false) { + std::cout << "Error: Could not find \"" << shader_source_name + << "\" in the list of registered source.\n"; + BLI_assert(0); + return shader::BuiltinBits::NONE; + } GPUSource *source = g_sources->lookup(shader_source_name); - std::string str; - shader::BuiltinBits out_builtins; - source->build(str, out_builtins); - *builtins |= (uint32_t)out_builtins; - return strdup(str.c_str()); + return source->builtins_get(); } -char *gpu_shader_dependency_get_source(const char *shader_source_name) +Vector<const char *> gpu_shader_dependency_get_resolved_source( + const StringRefNull shader_source_name) +{ + Vector<const char *> result; + GPUSource *source = g_sources->lookup(shader_source_name); + source->build(result); + return result; +} + +StringRefNull gpu_shader_dependency_get_source(const StringRefNull shader_source_name) { GPUSource *src = g_sources->lookup(shader_source_name); - return strdup(src->source.c_str()); + return src->source; } + +StringRefNull gpu_shader_dependency_get_filename_from_source_string( + const StringRefNull source_string) +{ + for (auto &source : g_sources->values()) { + if (source->source.c_str() == source_string.c_str()) { + return source->filename; + } + } + return ""; +} + +} // namespace blender::gpu::shader diff --git a/source/blender/gpu/intern/gpu_shader_dependency_private.h b/source/blender/gpu/intern/gpu_shader_dependency_private.h index b129ca74a48..13261dd2021 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency_private.h +++ b/source/blender/gpu/intern/gpu_shader_dependency_private.h @@ -34,11 +34,32 @@ void gpu_shader_dependency_init(void); void gpu_shader_dependency_exit(void); -/* User must free the resulting string using free. */ -char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name, - uint32_t *builtins); -char *gpu_shader_dependency_get_source(const char *shader_source_name); - #ifdef __cplusplus } #endif + +#ifdef __cplusplus + +# include "BLI_string_ref.hh" +# include "BLI_vector.hh" + +# include "gpu_shader_create_info.hh" + +namespace blender::gpu::shader { + +BuiltinBits gpu_shader_dependency_get_builtins(const StringRefNull source_name); + +Vector<const char *> gpu_shader_dependency_get_resolved_source(const StringRefNull source_name); +StringRefNull gpu_shader_dependency_get_source(const StringRefNull source_name); + +/** + * \brief Find the name of the file from which the given string was generated. + * \return Return filename or empty string. + * \note source_string needs to be identical to the one given by gpu_shader_dependency_get_source() + */ +StringRefNull gpu_shader_dependency_get_filename_from_source_string( + const StringRefNull source_string); + +} // namespace blender::gpu::shader + +#endif diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh index 7f99619c98c..514cfc01f09 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.hh +++ b/source/blender/gpu/intern/gpu_shader_interface.hh @@ -68,6 +68,7 @@ class ShaderInterface { uint16_t enabled_ubo_mask_ = 0; uint8_t enabled_ima_mask_ = 0; uint64_t enabled_tex_mask_ = 0; + uint16_t enabled_ssbo_mask_ = 0; /** Location of builtin uniforms. Fast access, no lookup needed. */ int32_t builtins_[GPU_NUM_UNIFORMS]; int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS]; diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc index 12459b4b721..c879e912c5d 100644 --- a/source/blender/gpu/intern/gpu_shader_log.cc +++ b/source/blender/gpu/intern/gpu_shader_log.cc @@ -26,7 +26,9 @@ #include "BLI_dynstr.h" #include "BLI_string.h" #include "BLI_string_utils.h" +#include "BLI_vector.hh" +#include "gpu_shader_dependency_private.h" #include "gpu_shader_private.hh" #include "GPU_platform.h" @@ -41,6 +43,14 @@ namespace blender::gpu { /** \name Debug functions * \{ */ +/* Number of lines before and after the error line to print for compilation errors. */ +#define DEBUG_CONTEXT_LINES 0 +/** + * Print dependencies sources list before the shader report. + * Useful to debug include order or missing dependencies. + */ +#define DEBUG_DEPENDENCIES 0 + void Shader::print_log(Span<const char *> sources, char *log, const char *stage, @@ -61,6 +71,30 @@ void Shader::print_log(Span<const char *> sources, BLI_dynstr_appendf(dynstr, "\n"); +#if DEBUG_DEPENDENCIES + BLI_dynstr_appendf( + dynstr, "%s%sIncluded files (in order):%s\n", info_col, line_prefix, reset_col); +#endif + + Vector<int64_t> sources_end_line; + for (StringRefNull src : sources) { + int64_t cursor = 0, line_count = 0; + while ((cursor = src.find('\n', cursor) + 1)) { + line_count++; + } + if (sources_end_line.is_empty() == false) { + line_count += sources_end_line.last(); + } + sources_end_line.append(line_count); +#if DEBUG_DEPENDENCIES + StringRefNull filename = shader::gpu_shader_dependency_get_filename_from_source_string(src); + if (!filename.is_empty()) { + BLI_dynstr_appendf( + dynstr, "%s%s %s%s\n", info_col, line_prefix, filename.c_str(), reset_col); + } +#endif + } + char *log_line = log, *line_end; LogCursor previous_location; @@ -73,12 +107,32 @@ void Shader::print_log(Span<const char *> sources, continue; } + /* Silence not useful lines. */ + StringRef logref = StringRefNull(log_line).substr(0, (size_t)line_end - (size_t)log_line); + if (logref.endswith(" shader failed to compile with the following errors:") || + logref.endswith(" No code generated")) { + log_line += (size_t)line_end - (size_t)log_line; + continue; + } + GPULogItem log_item; log_line = parser->parse_line(log_line, log_item); + /* Sanitize output. Really bad values can happen when the error line is buggy. */ + if (log_item.cursor.source >= sources.size()) { + log_item.cursor.source = -1; + } + if (log_item.cursor.row >= sources_end_line.last()) { + log_item.cursor.source = -1; + log_item.cursor.row = -1; + } + if (log_item.cursor.row == -1) { found_line_id = false; } + else if (log_item.source_base_row && log_item.cursor.source > 0) { + log_item.cursor.row += sources_end_line[log_item.cursor.source - 1]; + } const char *src_line = sources_combined; @@ -98,15 +152,14 @@ void Shader::print_log(Span<const char *> sources, /* error_line is 1 based in this case. */ int src_line_index = 1; while ((src_line_end = strchr(src_line, '\n'))) { - if (src_line_index == log_item.cursor.row) { + if (src_line_index >= log_item.cursor.row) { found_line_id = true; break; } -/* TODO(fclem) Make this an option to display N lines before error. */ -#if 0 /* Uncomment to print shader file up to the error line to have more context. */ - BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index); - BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line); -#endif + if (src_line_index >= log_item.cursor.row - DEBUG_CONTEXT_LINES) { + BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index); + BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line); + } /* Continue to next line. */ src_line = src_line_end + 1; src_line_index++; @@ -129,10 +182,53 @@ void Shader::print_log(Span<const char *> sources, BLI_dynstr_appendf(dynstr, "^"); } BLI_dynstr_appendf(dynstr, "\n"); + + /* Skip the error line. */ + src_line = src_line_end + 1; + src_line_index++; + while ((src_line_end = strchr(src_line, '\n'))) { + if (src_line_index > log_item.cursor.row + DEBUG_CONTEXT_LINES) { + break; + } + BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index); + BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line); + /* Continue to next line. */ + src_line = src_line_end + 1; + src_line_index++; + } } } BLI_dynstr_appendf(dynstr, line_prefix); + /* Search the correct source index. */ + int row_in_file = log_item.cursor.row; + int source_index = log_item.cursor.source; + if (source_index <= 0) { + for (auto i : sources_end_line.index_range()) { + if (log_item.cursor.row <= sources_end_line[i]) { + source_index = i; + break; + } + } + } + if (source_index > 0) { + row_in_file -= sources_end_line[source_index - 1]; + } + /* Print the filename the error line is coming from. */ + if (source_index > 0) { + StringRefNull filename = shader::gpu_shader_dependency_get_filename_from_source_string( + sources[source_index]); + if (!filename.is_empty()) { + BLI_dynstr_appendf(dynstr, + "%s%s:%d:%d: %s", + info_col, + filename.c_str(), + row_in_file, + log_item.cursor.column + 1, + reset_col); + } + } + if (log_item.severity == Severity::Error) { BLI_dynstr_appendf(dynstr, "%s%s%s: ", err_col, "Error", info_col); } diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh index 3bfecdefba7..93c33811ee0 100644 --- a/source/blender/gpu/intern/gpu_shader_private.hh +++ b/source/blender/gpu/intern/gpu_shader_private.hh @@ -120,6 +120,7 @@ struct LogCursor { struct GPULogItem { LogCursor cursor; + bool source_base_row = false; Severity severity = Severity::Unknown; }; diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 92d180f1140..2ee7c0503f4 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -248,6 +248,8 @@ static void detect_workarounds() GLContext::direct_state_access_support = false; GLContext::fixed_restart_index_support = false; GLContext::geometry_shader_invocations = false; + GLContext::layered_rendering_support = false; + GLContext::native_barycentric_support = false; GLContext::multi_bind_support = false; GLContext::multi_draw_indirect_support = false; GLContext::shader_draw_parameters_support = false; @@ -445,6 +447,8 @@ bool GLContext::direct_state_access_support = false; bool GLContext::explicit_location_support = false; bool GLContext::geometry_shader_invocations = false; bool GLContext::fixed_restart_index_support = false; +bool GLContext::layered_rendering_support = false; +bool GLContext::native_barycentric_support = false; bool GLContext::multi_bind_support = false; bool GLContext::multi_draw_indirect_support = false; bool GLContext::shader_draw_parameters_support = false; @@ -505,6 +509,8 @@ void GLBackend::capabilities_init() GLContext::explicit_location_support = GLEW_VERSION_4_3; GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5; GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility; + GLContext::layered_rendering_support = GLEW_AMD_vertex_shader_layer; + GLContext::native_barycentric_support = GLEW_AMD_shader_explicit_vertex_parameter; GLContext::multi_bind_support = GLEW_ARB_multi_bind; GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect; GLContext::shader_draw_parameters_support = GLEW_ARB_shader_draw_parameters; diff --git a/source/blender/gpu/opengl/gl_compute.cc b/source/blender/gpu/opengl/gl_compute.cc index fa8317dde4a..14164ee181b 100644 --- a/source/blender/gpu/opengl/gl_compute.cc +++ b/source/blender/gpu/opengl/gl_compute.cc @@ -28,8 +28,8 @@ namespace blender::gpu { void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len) { + GL_CHECK_RESOURCES("Compute"); glDispatchCompute(group_x_len, group_y_len, group_z_len); - debug::check_gl_error("Dispatch Compute"); } } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index dd22418972b..b7a74863ac4 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -72,6 +72,8 @@ class GLContext : public Context { static bool explicit_location_support; static bool geometry_shader_invocations; static bool fixed_restart_index_support; + static bool layered_rendering_support; + static bool native_barycentric_support; static bool multi_bind_support; static bool multi_draw_indirect_support; static bool shader_draw_parameters_support; diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc index e624cb9ee46..b82bf10ebe9 100644 --- a/source/blender/gpu/opengl/gl_debug_layer.cc +++ b/source/blender/gpu/opengl/gl_debug_layer.cc @@ -82,6 +82,8 @@ DEBUG_FUNC_DECLARE(PFNGLDRAWBUFFERSPROC, void, glDrawBuffers, GLsizei, n, const DEBUG_FUNC_DECLARE(PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC, void, glDrawElementsInstancedBaseVertexBaseInstance, GLenum, mode, GLsizei, count, GLenum, type, const void *, indices, GLsizei, primcount, GLint, basevertex, GLuint, baseinstance); DEBUG_FUNC_DECLARE(PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC, void, glDrawElementsInstancedBaseVertex, GLenum, mode, GLsizei, count, GLenum, type, const void *, indices, GLsizei, instancecount, GLint, basevertex); DEBUG_FUNC_DECLARE(PFNGLENDQUERYPROC, void, glEndQuery, GLenum, target); +DEBUG_FUNC_DECLARE(PFNGLDISPATCHCOMPUTEPROC, void, glDispatchCompute, GLuint, num_groups_x, GLuint, num_groups_y, GLuint, num_groups_z); +DEBUG_FUNC_DECLARE(PFNGLDISPATCHCOMPUTEINDIRECTPROC, void, glDispatchComputeIndirect, GLintptr, indirect); DEBUG_FUNC_DECLARE(PFNGLENDTRANSFORMFEEDBACKPROC, void, glEndTransformFeedback, void); DEBUG_FUNC_DECLARE(PFNGLFRAMEBUFFERTEXTURE2DPROC, void, glFramebufferTexture2D, GLenum, target, GLenum, attachment, GLenum, textarget, GLuint, texture, GLint, level); DEBUG_FUNC_DECLARE(PFNGLFRAMEBUFFERTEXTURELAYERPROC, void, glFramebufferTextureLayer, GLenum, target, GLenum, attachment, GLuint, texture, GLint, level, GLint, layer); @@ -130,6 +132,8 @@ void init_debug_layer() DEBUG_WRAP(glDeleteSamplers); DEBUG_WRAP(glDeleteShader); DEBUG_WRAP(glDeleteVertexArrays); + DEBUG_WRAP(glDispatchCompute); + DEBUG_WRAP(glDispatchComputeIndirect); DEBUG_WRAP(glDrawArraysInstanced); DEBUG_WRAP(glDrawArraysInstancedBaseInstance); DEBUG_WRAP(glDrawBuffers); diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh index 9ebe549efe7..00a7676dd3f 100644 --- a/source/blender/gpu/opengl/gl_framebuffer.hh +++ b/source/blender/gpu/opengl/gl_framebuffer.hh @@ -141,6 +141,8 @@ static inline GLenum to_gl(const GPUAttachmentType type) ATTACHMENT(COLOR_ATTACHMENT3); ATTACHMENT(COLOR_ATTACHMENT4); ATTACHMENT(COLOR_ATTACHMENT5); + ATTACHMENT(COLOR_ATTACHMENT6); + ATTACHMENT(COLOR_ATTACHMENT7); default: BLI_assert(0); return GL_COLOR_ATTACHMENT0; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 27205cfbc0b..9da35a2bc97 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -127,6 +127,74 @@ static const char *to_string(const Type &type) } } +static const char *to_string(const eGPUTextureFormat &type) +{ + switch (type) { + case GPU_RGBA8UI: + return "rgba8ui"; + case GPU_RGBA8I: + return "rgba8i"; + case GPU_RGBA8: + return "rgba8"; + case GPU_RGBA32UI: + return "rgba32ui"; + case GPU_RGBA32I: + return "rgba32i"; + case GPU_RGBA32F: + return "rgba32f"; + case GPU_RGBA16UI: + return "rgba16ui"; + case GPU_RGBA16I: + return "rgba16i"; + case GPU_RGBA16F: + return "rgba16f"; + case GPU_RGBA16: + return "rgba16"; + case GPU_RG8UI: + return "rg8ui"; + case GPU_RG8I: + return "rg8i"; + case GPU_RG8: + return "rg8"; + case GPU_RG32UI: + return "rg32ui"; + case GPU_RG32I: + return "rg32i"; + case GPU_RG32F: + return "rg32f"; + case GPU_RG16UI: + return "rg16ui"; + case GPU_RG16I: + return "rg16i"; + case GPU_RG16F: + return "rg16f"; + case GPU_RG16: + return "rg16"; + case GPU_R8UI: + return "r8ui"; + case GPU_R8I: + return "r8i"; + case GPU_R8: + return "r8"; + case GPU_R32UI: + return "r32ui"; + case GPU_R32I: + return "r32i"; + case GPU_R32F: + return "r32f"; + case GPU_R16UI: + return "r16ui"; + case GPU_R16I: + return "r16i"; + case GPU_R16F: + return "r16f"; + case GPU_R16: + return "r16"; + default: + return "unkown"; + } +} + static const char *to_string(const PrimitiveIn &layout) { switch (layout) { @@ -277,15 +345,15 @@ static void print_image_type(std::ostream &os, static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers) { - if ((qualifiers & Qualifier::RESTRICT) == Qualifier::RESTRICT) { + if (bool(qualifiers & Qualifier::NO_RESTRICT) == false) { os << "restrict "; } - if ((qualifiers & Qualifier::READ_ONLY) == Qualifier::READ_ONLY) { - os << "readonly "; - } - if ((qualifiers & Qualifier::WRITE_ONLY) == Qualifier::WRITE_ONLY) { + if (bool(qualifiers & Qualifier::READ) == false) { os << "writeonly "; } + if (bool(qualifiers & Qualifier::WRITE) == false) { + os << "readonly "; + } return os; } @@ -294,7 +362,7 @@ static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &r if (GLContext::explicit_location_support) { os << "layout(binding = " << res.slot; if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { - os << ", " << res.image.format; + os << ", " << to_string(res.image.format); } else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { os << ", std140"; @@ -370,7 +438,7 @@ static void print_interface(std::ostream &os, const StageInterfaceInfo &iface, const StringRefNull &suffix = "") { - /* TODO(fclem) Move that to interface check. */ + /* TODO(@fclem): Move that to interface check. */ // if (iface.instance_name.is_empty()) { // BLI_assert_msg(0, "Interfaces require an instance name for geometry shader."); // std::cout << iface.name << ": Interfaces require an instance name for geometry shader.\n"; @@ -426,14 +494,33 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const return ss.str(); } +static std::string main_function_wrapper(std::string &pre_main, std::string &post_main) +{ + std::stringstream ss; + /* Prototype for the original main. */ + ss << "\n"; + ss << "void main_function_();\n"; + /* Wrapper to the main function in order to inject code processing on globals. */ + ss << "void main() {\n"; + ss << pre_main; + ss << " main_function_();\n"; + ss << post_main; + ss << "}\n"; + /* Rename the original main. */ + ss << "#define main main_function_\n"; + ss << "\n"; + return ss.str(); +} + std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const { std::stringstream ss; + std::string post_main = ""; ss << "\n/* Inputs. */\n"; for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) { if (GLContext::explicit_location_support && - /* Fix issue with amdgpu-pro + workbench_prepass_mesh_vert.glsl being quantized. */ + /* Fix issue with AMDGPU-PRO + workbench_prepass_mesh_vert.glsl being quantized. */ GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) == false) { ss << "layout(location = " << attr.index << ") "; } @@ -443,13 +530,35 @@ std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) con for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { print_interface(ss, "out", *iface); } + if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) { + ss << "out int gpu_Layer;\n"; + } + if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { + if (!GLContext::native_barycentric_support) { + /* Disabled or unsupported. */ + } + else if (GLEW_AMD_shader_explicit_vertex_parameter) { + /* Need this for stable barycentric. */ + ss << "flat out vec4 gpu_pos_flat;\n"; + ss << "out vec4 gpu_pos;\n"; + + post_main += " gpu_pos = gpu_pos_flat = gl_Position;\n"; + } + } ss << "\n"; + + if (post_main.empty() == false) { + std::string pre_main = ""; + ss << main_function_wrapper(pre_main, post_main); + } return ss.str(); } std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const { std::stringstream ss; + std::string pre_main = ""; + ss << "\n/* Interfaces. */\n"; const Vector<StageInterfaceInfo *> &in_interfaces = (info.geometry_source_.is_empty()) ? info.vertex_out_interfaces_ : @@ -457,6 +566,32 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c for (const StageInterfaceInfo *iface : in_interfaces) { print_interface(ss, "in", *iface); } + if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { + if (!GLContext::native_barycentric_support) { + ss << "smooth in vec3 gpu_BaryCoord;\n"; + ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n"; + } + else if (GLEW_AMD_shader_explicit_vertex_parameter) { + /* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry + * shader workaround if this extension/feature is detected. */ + ss << "\n/* Stable Barycentric Coordinates. */\n"; + ss << "flat in vec4 gpu_pos_flat;\n"; + ss << "__explicitInterpAMD in vec4 gpu_pos;\n"; + /* Globals. */ + ss << "vec3 gpu_BaryCoord;\n"; + ss << "vec3 gpu_BaryCoordNoPersp;\n"; + ss << "\n"; + ss << "vec2 stable_bary_(vec2 in_bary) {\n"; + ss << " vec3 bary = vec3(in_bary, 1.0 - in_bary.x - in_bary.y);\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { return bary.zxy; }\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n"; + ss << " return bary.xyz;\n"; + ss << "}\n"; + + pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n"; + pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n"; + } + } ss << "\n/* Outputs. */\n"; for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) { ss << "layout(location = " << output.index; @@ -474,6 +609,11 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c ss << "out " << to_string(output.type) << " " << output.name << ";\n"; } ss << "\n"; + + if (pre_main.empty() == false) { + std::string post_main = ""; + ss << main_function_wrapper(pre_main, post_main); + } return ss.str(); } @@ -505,7 +645,7 @@ static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInf const StringRefNull &name) { for (auto *iface : ifaces) { - if (iface->name == name) { + if (iface->instance_name == name) { return iface; } } @@ -514,8 +654,8 @@ static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInf std::string GLShader::geometry_interface_declare(const ShaderCreateInfo &info) const { - std::stringstream ss; + ss << "\n/* Interfaces. */\n"; for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_, @@ -549,6 +689,76 @@ std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const ss << "\n"; return ss.str(); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Passthrough geometry shader emulation + * + * \{ */ + +std::string GLShader::workaround_geometry_shader_source_create( + const shader::ShaderCreateInfo &info) +{ + std::stringstream ss; + + const bool do_layer_workaround = !GLContext::layered_rendering_support && + bool(info.builtins_ & BuiltinBits::LAYER); + const bool do_barycentric_workaround = !GLContext::native_barycentric_support && + bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD); + + shader::ShaderCreateInfo info_modified = info; + info_modified.geometry_out_interfaces_ = info_modified.vertex_out_interfaces_; + /** + * NOTE(@fclem): Assuming we will render TRIANGLES. This will not work with other primitive + * types. In this case, it might not trigger an error on some implementations. + */ + info_modified.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3); + + ss << geometry_layout_declare(info_modified); + ss << geometry_interface_declare(info_modified); + if (do_layer_workaround) { + ss << "in int gpu_Layer[];\n"; + } + if (do_barycentric_workaround) { + ss << "smooth out vec3 gpu_BaryCoord;\n"; + ss << "noperspective out vec3 gpu_BaryCoordNoPersp;\n"; + } + ss << "\n"; + + ss << "void main()\n"; + ss << "{\n"; + if (do_layer_workaround) { + ss << " gl_Layer = gpu_Layer[0];\n"; + } + for (auto i : IndexRange(3)) { + for (auto iface : info_modified.vertex_out_interfaces_) { + for (auto &inout : iface->inouts) { + ss << " " << iface->instance_name << "_out." << inout.name; + ss << " = " << iface->instance_name << "_in[" << i << "]." << inout.name << ";\n"; + } + } + if (do_barycentric_workaround) { + ss << " gpu_BaryCoordNoPersp = gpu_BaryCoord ="; + ss << " vec3(" << int(i == 0) << ", " << int(i == 1) << ", " << int(i == 2) << ");\n"; + } + ss << " gl_Position = gl_in[" << i << "].gl_Position;\n"; + ss << " EmitVertex();\n"; + } + ss << "}\n"; + return ss.str(); +} + +bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info) +{ + BuiltinBits builtins = info->builtins_; + if (!GLContext::native_barycentric_support && bool(builtins & BuiltinBits::BARYCENTRIC_COORD)) { + return true; + } + if (!GLContext::layered_rendering_support && bool(builtins & BuiltinBits::LAYER)) { + return true; + } + return false; +} /** \} */ @@ -559,7 +769,7 @@ std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const static char *glsl_patch_default_get() { /** Used for shader patching. Init once. */ - static char patch[700] = "\0"; + static char patch[1024] = "\0"; if (patch[0] != '\0') { return patch; } @@ -596,13 +806,20 @@ static char *glsl_patch_default_get() STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n"); STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n"); } - if (GLEW_ARB_conservative_depth) { + if (!GLEW_VERSION_4_2 && GLEW_ARB_conservative_depth) { STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n"); } if (GPU_shader_image_load_store_support()) { STR_CONCAT(patch, slen, "#extension GL_ARB_shader_image_load_store: enable\n"); STR_CONCAT(patch, slen, "#extension GL_ARB_shading_language_420pack: enable\n"); } + if (GLContext::layered_rendering_support) { + STR_CONCAT(patch, slen, "#extension GL_AMD_vertex_shader_layer: enable\n"); + STR_CONCAT(patch, slen, "#define gpu_Layer gl_Layer\n"); + } + if (GLContext::native_barycentric_support) { + STR_CONCAT(patch, slen, "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n"); + } /* Fallbacks. */ if (!GLContext::shader_draw_parameters_support) { @@ -612,6 +829,9 @@ static char *glsl_patch_default_get() /* Vulkan GLSL compat. */ STR_CONCAT(patch, slen, "#define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance)\n"); + /* Array compat. */ + STR_CONCAT(patch, slen, "#define array(_type) _type[]\n"); + /* Derivative sign can change depending on implementation. */ STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]); STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]); @@ -719,6 +939,14 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info) return false; } + if (info && do_geometry_shader_injection(info)) { + std::string source = workaround_geometry_shader_source_create(*info); + Vector<const char *> sources; + sources.append("version"); + sources.append(source.c_str()); + geometry_shader_from_glsl(sources); + } + glLinkProgram(shader_program_); GLint status; diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index a82ab026c16..cc1c93142f8 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -94,6 +94,14 @@ class GLShader : public Shader { /** Create, compile and attach the shader stage to the shader program. */ GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources); + /** + * \brief features available on newer implementation such as native barycentric coordinates + * and layered rendering, necessitate a geometry shader to work on older hardware. + */ + std::string workaround_geometry_shader_source_create(const shader::ShaderCreateInfo &info); + + bool do_geometry_shader_injection(const shader::ShaderCreateInfo *info); + MEM_CXX_CLASS_ALLOC_FUNCS("GLShader"); }; diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index 71b908665d3..0a31f8dee7f 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -117,7 +117,28 @@ static inline int image_binding(int32_t program, switch (type) { case GL_IMAGE_1D: case GL_IMAGE_2D: - case GL_IMAGE_3D: { + case GL_IMAGE_3D: + case GL_IMAGE_CUBE: + case GL_IMAGE_BUFFER: + case GL_IMAGE_1D_ARRAY: + case GL_IMAGE_2D_ARRAY: + case GL_IMAGE_CUBE_MAP_ARRAY: + case GL_INT_IMAGE_1D: + case GL_INT_IMAGE_2D: + case GL_INT_IMAGE_3D: + case GL_INT_IMAGE_CUBE: + case GL_INT_IMAGE_BUFFER: + case GL_INT_IMAGE_1D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_CUBE_MAP_ARRAY: + case GL_UNSIGNED_INT_IMAGE_1D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_BUFFER: + case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: { /* For now just assign a consecutive index. In the future, we should set it in * the shader using layout(binding = i) and query its value. */ int binding = *image_len; @@ -298,6 +319,7 @@ GLShaderInterface::GLShaderInterface(GLuint program) input->binding = input->location = binding; name_buffer_offset += this->set_input_name(input, name, name_len); + enabled_ssbo_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu; } /* Builtin Uniforms */ @@ -455,7 +477,7 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); input->location = input->binding = res.slot; - enabled_ubo_mask_ |= (1 << input->binding); + enabled_ssbo_mask_ |= (1 << input->binding); input++; } } @@ -497,7 +519,7 @@ GLShaderInterface::~GLShaderInterface() void GLShaderInterface::ref_add(GLVaoCache *ref) { for (int i = 0; i < refs_.size(); i++) { - if (refs_[i] == NULL) { + if (refs_[i] == nullptr) { refs_[i] = ref; return; } @@ -509,7 +531,7 @@ void GLShaderInterface::ref_remove(GLVaoCache *ref) { for (int i = 0; i < refs_.size(); i++) { if (refs_[i] == ref) { - refs_[i] = NULL; + refs_[i] = nullptr; break; /* cannot have duplicates */ } } diff --git a/source/blender/gpu/opengl/gl_shader_log.cc b/source/blender/gpu/opengl/gl_shader_log.cc index 174cc63ad81..ec13bc44136 100644 --- a/source/blender/gpu/opengl/gl_shader_log.cc +++ b/source/blender/gpu/opengl/gl_shader_log.cc @@ -60,6 +60,15 @@ char *GLLogParser::parse_line(char *log_line, GPULogItem &log_item) log_item.cursor.row = log_item.cursor.column; log_item.cursor.column = -1; } + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL) && + /* WORKAROUND(@fclem): Both Mesa and AMDGPU-PRO are reported as official. */ + StringRefNull(GPU_platform_version()).find(" Mesa ") == -1) { + /* source:row */ + log_item.cursor.source = log_item.cursor.row; + log_item.cursor.row = log_item.cursor.column; + log_item.cursor.column = -1; + log_item.source_base_row = true; + } else { /* line:char */ } diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh index 83ff3ffc9e9..5985f1583f2 100644 --- a/source/blender/gpu/opengl/gl_state.hh +++ b/source/blender/gpu/opengl/gl_state.hh @@ -124,11 +124,20 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits) if (barrier_bits & GPU_BARRIER_SHADER_IMAGE_ACCESS) { barrier |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; } + if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) { + barrier |= GL_SHADER_STORAGE_BARRIER_BIT; + } if (barrier_bits & GPU_BARRIER_TEXTURE_FETCH) { barrier |= GL_TEXTURE_FETCH_BARRIER_BIT; } - if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) { - barrier |= GL_SHADER_STORAGE_BARRIER_BIT; + if (barrier_bits & GPU_BARRIER_TEXTURE_UPDATE) { + barrier |= GL_TEXTURE_UPDATE_BARRIER_BIT; + } + if (barrier_bits & GPU_BARRIER_COMMAND) { + barrier |= GL_COMMAND_BARRIER_BIT; + } + if (barrier_bits & GPU_BARRIER_FRAMEBUFFER) { + barrier |= GL_FRAMEBUFFER_BARRIER_BIT; } if (barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY) { barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl index 01a16e194ca..ab6024b073d 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl @@ -18,7 +18,7 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result) result.radiance = out_Diffuse_0.radiance; - /* TODO(fclem) Try to not use this. */ + /* TODO(@fclem): Try to not use this. */ closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl index c6203bc36ab..2a98d9fadd0 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl @@ -109,6 +109,11 @@ void vector_normalize(vec3 normal, out vec3 outnormal) outnormal = normalize(normal); } +void vector_copy(vec3 normal, out vec3 outnormal) +{ + outnormal = normal; +} + /* Matirx Math */ mat3 euler_to_mat3(vec3 euler) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index bba84c2be52..c97fc090fe2 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -166,7 +166,7 @@ void node_bsdf_principled(vec4 base_color, float btdf = (do_multiscatter != 0.0) ? 1.0 : btdf_lut(NV, in_Refraction_3.roughness, in_Refraction_3.ior).x; - /* TODO(fclem) This could be going to a transmission render pass instead. */ + /* TODO(@fclem): This could be going to a transmission render pass instead. */ out_Refraction_3.radiance *= btdf; out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance); out_Refraction_3.radiance *= base_color.rgb; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl index 7cbc7218f5c..8a42a131f43 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl @@ -21,7 +21,7 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl result.radiance = out_Refraction_0.radiance; - /* TODO(fclem) Try to not use this. */ + /* TODO(@fclem): Try to not use this. */ result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N, viewCameraVec(viewPosition)); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl index d0c159cdf37..20b634aa801 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl @@ -22,7 +22,7 @@ void node_subsurface_scattering(vec4 color, closure_load_sss_data(scale, out_Diffuse_0.radiance, color.rgb, int(sss_id), result); - /* TODO(fclem) Try to not use this. */ + /* TODO(@fclem): Try to not use this. */ closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result); } diff --git a/source/blender/ikplugin/BIK_api.h b/source/blender/ikplugin/BIK_api.h index 674b384adf2..7ce0feb3989 100644 --- a/source/blender/ikplugin/BIK_api.h +++ b/source/blender/ikplugin/BIK_api.h @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Original author: Benoit Bolsee */ /** \file diff --git a/source/blender/ikplugin/intern/ikplugin_api.c b/source/blender/ikplugin/intern/ikplugin_api.c index 233150a77aa..8bbab832b66 100644 --- a/source/blender/ikplugin/intern/ikplugin_api.c +++ b/source/blender/ikplugin/intern/ikplugin_api.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Original author: Benoit Bolsee */ /** \file diff --git a/source/blender/ikplugin/intern/ikplugin_api.h b/source/blender/ikplugin/intern/ikplugin_api.h index f61ba7e3a63..9d54cbec80c 100644 --- a/source/blender/ikplugin/intern/ikplugin_api.h +++ b/source/blender/ikplugin/intern/ikplugin_api.h @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Original author: Benoit Bolsee */ /** \file diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 0ee8b3057d2..5daad507efe 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Original author: Benoit Bolsee */ /** \file diff --git a/source/blender/ikplugin/intern/iksolver_plugin.h b/source/blender/ikplugin/intern/iksolver_plugin.h index 28356b4fc9c..3cb6ac171d9 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.h +++ b/source/blender/ikplugin/intern/iksolver_plugin.h @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Original author: Benoit Bolsee */ /** \file diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 4a4e22ed884..102ad46a5f2 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Original author: Benoit Bolsee */ /** \file diff --git a/source/blender/ikplugin/intern/itasc_plugin.h b/source/blender/ikplugin/intern/itasc_plugin.h index 89342295b35..cd4e210966e 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.h +++ b/source/blender/ikplugin/intern/itasc_plugin.h @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Original author: Benoit Bolsee */ /** \file diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index 758b21f8cda..aa10d8949fe 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org> + * Copyright 1999-2001 David Hodson <hodsond@acm.org> */ /** \file diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h index d1225027b4c..d71b6da9bc6 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.h +++ b/source/blender/imbuf/intern/cineon/cineonlib.h @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org> + * Copyright 1999-2001 David Hodson <hodsond@acm.org> */ /** \file diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index 4580bfd2cbf..79374f87cc1 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright 1999 - 2002 David Hodson <hodsond@acm.org> + * Copyright 1999-2002 David Hodson <hodsond@acm.org> */ /** \file diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h index 1228ac4ee66..59fc6344737 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.h +++ b/source/blender/imbuf/intern/cineon/dpxlib.h @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright 1999 - 2002 David Hodson <hodsond@acm.org> + * Copyright 1999-2002 David Hodson <hodsond@acm.org> */ /** \file diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c index 73bcb8d7ebc..2852e8c6f73 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.c +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org> + * Copyright 1999-2001 David Hodson <hodsond@acm.org> */ /** \file diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h index c2704a086b6..3e98780016e 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.h +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org> + * Copyright 1999-2001 David Hodson <hodsond@acm.org> */ /** \file diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp index 6686d56e9d1..a3cd8056290 100644 --- a/source/blender/imbuf/intern/dds/FlipDXT.cpp +++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp @@ -31,8 +31,11 @@ * All rights reserved. */ -/* This file comes from the chromium project, adapted to Blender to add DDS - * flipping to OpenGL convention for Blender */ +/** \file + * \ingroup imbdds + * This file comes from the chromium project, adapted to Blender to add DDS + * flipping to OpenGL convention for Blender. + */ #include "IMB_imbuf_types.h" diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index f23748e59a2..37ed993f3f6 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * allocimbuf.c */ /** \file diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c index 324bc9806c1..c6f33664f8b 100644 --- a/source/blender/imbuf/intern/filter.c +++ b/source/blender/imbuf/intern/filter.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * filter.c */ /** \file diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 00e96e7840b..2aa61a3b5ee 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Peter Schlaile <peter [at] schlaile [dot] de> 2011 + * Copyright 2011 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index 925ef0a8502..616f4d1421c 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -12,21 +12,14 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright - * All rights reserved. */ /** \file * \ingroup imbuf - */ - -/* ---------------------------------------------------------------------- * Radiance High Dynamic Range image file IO * For description and code for reading/writing of radiance hdr files * by Greg Ward, refer to: * http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html - * ---------------------------------------------------------------------- */ #include "MEM_guardedalloc.h" diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index c75bdfa375c..ef0d547055d 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * allocimbuf.c */ /** \file diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 1d81ee768e9..d368504dab0 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * allocimbuf.c */ /** \file diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c index f02f3e37d6a..84161167ebc 100644 --- a/source/blender/imbuf/intern/rotate.c +++ b/source/blender/imbuf/intern/rotate.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * rotate.c */ /** \file diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index a18ba6748de..a745555eec7 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * allocimbuf.c */ /** \file diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 18ed4710e78..10de80c1330 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * util.c */ /** \file diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index cc6fef634d5..4775d5154a3 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * util.c */ /** \file diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c index f21d274f8fd..c2c87375363 100644 --- a/source/blender/imbuf/intern/writeimage.c +++ b/source/blender/imbuf/intern/writeimage.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * writeimage.c */ /** \file diff --git a/source/blender/io/collada/CMakeLists.txt b/source/blender/io/collada/CMakeLists.txt index e1645083116..9ce3389257d 100644 --- a/source/blender/io/collada/CMakeLists.txt +++ b/source/blender/io/collada/CMakeLists.txt @@ -135,10 +135,6 @@ if(WITH_BUILDINFO) add_definitions(-DWITH_BUILDINFO) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(CMAKE_COMPILER_IS_GNUCXX) # COLLADAFWArray.h gives error with gcc 4.5 string(APPEND CMAKE_CXX_FLAGS " -fpermissive") diff --git a/source/blender/io/usd/intern/usd_reader_camera.cc b/source/blender/io/usd/intern/usd_reader_camera.cc index 2732ed5770d..1d001e19140 100644 --- a/source/blender/io/usd/intern/usd_reader_camera.cc +++ b/source/blender/io/usd/intern/usd_reader_camera.cc @@ -72,7 +72,7 @@ void USDCameraReader::read_object_data(Main *bmain, const double motionSampleTim cam_prim.GetHorizontalApertureAttr().Get(&horAp, motionSampleTime); bcam->lens = val.Get<float>(); - /* TODO(makowalski) */ + /* TODO(@makowalski): support sensor size. */ #if 0 bcam->sensor_x = 0.0f; bcam->sensor_y = 0.0f; diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 95b73c85da6..10de47da0e3 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -14,10 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Adapted from the Blender Alembic importer implementation. - * - * Modifications Copyright (C) 2021 Tangent Animation and - * NVIDIA Corporation. All rights reserved. - */ + * Modifications Copyright 2021 Tangent Animation and + * NVIDIA Corporation. All rights reserved. */ #include "usd_reader_mesh.h" #include "usd_reader_material.h" diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h index c5869fcbd32..0a1ab9a5fbe 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.h +++ b/source/blender/io/usd/intern/usd_reader_mesh.h @@ -16,7 +16,7 @@ * Adapted from the Blender Alembic importer implementation. * * Modifications Copyright (C) 2021 Tangent Animation and - * NVIDIA Corporation. All rights reserved. + * NVIDIA Corporation. All rights reserved. */ #pragma once diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc index 52ad349fb98..5ce04339503 100644 --- a/source/blender/io/usd/intern/usd_writer_material.cc +++ b/source/blender/io/usd/intern/usd_writer_material.cc @@ -286,7 +286,7 @@ static void create_uvmap_shader(const USDExporterContext &usd_export_context, } bNode *uv_node = traverse_channel(tex_node_sock, SH_NODE_UVMAP); - if (uv_node == NULL) { + if (uv_node == nullptr) { continue; } @@ -391,7 +391,7 @@ static void export_in_memory_texture(Image *ima, BKE_image_path_ensure_ext_from_imformat(file_name, &imageFormat); char export_path[FILE_MAX]; - BLI_path_join(export_path, FILE_MAX, export_dir.c_str(), file_name, NULL); + BLI_path_join(export_path, FILE_MAX, export_dir.c_str(), file_name, nullptr); if (!allow_overwrite && BLI_exists(export_path)) { return; @@ -590,7 +590,7 @@ static std::string get_tex_image_asset_path(bNode *node, BLI_split_file_part(path.c_str(), file_path, FILE_MAX); if (export_params.relative_texture_paths) { - BLI_path_join(exp_path, FILE_MAX, ".", "textures", file_path, NULL); + BLI_path_join(exp_path, FILE_MAX, ".", "textures", file_path, nullptr); } else { /* Create absolute path in the textures directory. */ @@ -602,7 +602,7 @@ static std::string get_tex_image_asset_path(bNode *node, char dir_path[FILE_MAX]; BLI_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX); - BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, NULL); + BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, nullptr); } return exp_path; } @@ -697,7 +697,7 @@ static void copy_single_file(Image *ima, const std::string &dest_dir, const bool BLI_split_file_part(source_path, file_name, FILE_MAX); char dest_path[FILE_MAX]; - BLI_path_join(dest_path, FILE_MAX, dest_dir.c_str(), file_name, NULL); + BLI_path_join(dest_path, FILE_MAX, dest_dir.c_str(), file_name, nullptr); if (!allow_overwrite && BLI_exists(dest_path)) { return; @@ -743,7 +743,7 @@ static void export_texture(bNode *node, BLI_split_dir_part(stage_path.c_str(), usd_dir_path, FILE_MAX); char tex_dir_path[FILE_MAX]; - BLI_path_join(tex_dir_path, FILE_MAX, usd_dir_path, "textures", SEP_STR, NULL); + BLI_path_join(tex_dir_path, FILE_MAX, usd_dir_path, "textures", SEP_STR, nullptr); BLI_dir_create_recursive(tex_dir_path); diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt index 296dd70b5a2..0b1be7946cf 100644 --- a/source/blender/io/wavefront_obj/CMakeLists.txt +++ b/source/blender/io/wavefront_obj/CMakeLists.txt @@ -56,6 +56,12 @@ set(LIB bf_blenkernel ) +if(WITH_TBB) + add_definitions(-DWITH_TBB) + list(APPEND INC_SYS ${TBB_INCLUDE_DIRS}) + list(APPEND LIB ${TBB_LIBRARIES}) +endif() + blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) 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 38163af64b6..87f87e37a7e 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 @@ -24,6 +24,7 @@ #include "BKE_blender_version.h" #include "BLI_path_util.h" +#include "BLI_task.hh" #include "obj_export_mesh.hh" #include "obj_export_mtl.hh" @@ -52,68 +53,75 @@ const char *DEFORM_GROUP_DISABLED = "off"; * So an empty material name is written. */ const char *MATERIAL_GROUP_DISABLED = ""; -void OBJWriter::write_vert_uv_normal_indices(Span<int> vert_indices, +void OBJWriter::write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> uv_indices, Span<int> normal_indices) const { BLI_assert(vert_indices.size() == uv_indices.size() && vert_indices.size() == normal_indices.size()); - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (int j = 0; j < vert_indices.size(); j++) { - file_handler_->write<eOBJSyntaxElement::vertex_uv_normal_indices>( - vert_indices[j] + index_offsets_.vertex_offset + 1, - uv_indices[j] + index_offsets_.uv_vertex_offset + 1, - normal_indices[j] + index_offsets_.normal_offset + 1); + fh.write<eOBJSyntaxElement::vertex_uv_normal_indices>( + vert_indices[j] + offsets.vertex_offset + 1, + uv_indices[j] + offsets.uv_vertex_offset + 1, + normal_indices[j] + offsets.normal_offset + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } -void OBJWriter::write_vert_normal_indices(Span<int> vert_indices, +void OBJWriter::write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> /*uv_indices*/, Span<int> normal_indices) const { BLI_assert(vert_indices.size() == normal_indices.size()); - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (int j = 0; j < vert_indices.size(); j++) { - file_handler_->write<eOBJSyntaxElement::vertex_normal_indices>( - vert_indices[j] + index_offsets_.vertex_offset + 1, - normal_indices[j] + index_offsets_.normal_offset + 1); + fh.write<eOBJSyntaxElement::vertex_normal_indices>(vert_indices[j] + offsets.vertex_offset + 1, + normal_indices[j] + offsets.normal_offset + + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } -void OBJWriter::write_vert_uv_indices(Span<int> vert_indices, +void OBJWriter::write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> uv_indices, Span<int> /*normal_indices*/) const { BLI_assert(vert_indices.size() == uv_indices.size()); - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (int j = 0; j < vert_indices.size(); j++) { - file_handler_->write<eOBJSyntaxElement::vertex_uv_indices>( - vert_indices[j] + index_offsets_.vertex_offset + 1, - uv_indices[j] + index_offsets_.uv_vertex_offset + 1); + fh.write<eOBJSyntaxElement::vertex_uv_indices>(vert_indices[j] + offsets.vertex_offset + 1, + uv_indices[j] + offsets.uv_vertex_offset + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } -void OBJWriter::write_vert_indices(Span<int> vert_indices, +void OBJWriter::write_vert_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> /*uv_indices*/, Span<int> /*normal_indices*/) const { - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (const int vert_index : vert_indices) { - file_handler_->write<eOBJSyntaxElement::vertex_indices>(vert_index + - index_offsets_.vertex_offset + 1); + fh.write<eOBJSyntaxElement::vertex_indices>(vert_index + offsets.vertex_offset + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } void OBJWriter::write_header() const { using namespace std::string_literals; - file_handler_->write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + - "\n"); - file_handler_->write<eOBJSyntaxElement::string>("# www.blender.org\n"); + FormatHandler<eFileType::OBJ> fh; + fh.write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + "\n"); + fh.write<eOBJSyntaxElement::string>("# www.blender.org\n"); + fh.write_to_file(outfile_); } void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const @@ -122,10 +130,13 @@ void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const char mtl_file_name[FILE_MAXFILE]; char mtl_dir_name[FILE_MAXDIR]; BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE); - file_handler_->write<eOBJSyntaxElement::mtllib>(mtl_file_name); + FormatHandler<eFileType::OBJ> fh; + fh.write<eOBJSyntaxElement::mtllib>(mtl_file_name); + fh.write_to_file(outfile_); } -void OBJWriter::write_object_group(const OBJMesh &obj_mesh_data) const +void OBJWriter::write_object_group(FormatHandler<eFileType::OBJ> &fh, + const OBJMesh &obj_mesh_data) const { /* "o object_name" is not mandatory. A valid .OBJ file may contain neither * "o name" nor "g group_name". */ @@ -138,125 +149,104 @@ void OBJWriter::write_object_group(const OBJMesh &obj_mesh_data) const const char *object_material_name = obj_mesh_data.get_object_material_name(0); if (export_params_.export_materials && export_params_.export_material_groups && object_material_name) { - file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name + - "_" + object_material_name); - return; + fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name + "_" + + object_material_name); + } + else { + fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name); } - file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name); } -void OBJWriter::write_object_name(const OBJMesh &obj_mesh_data) const +void OBJWriter::write_object_name(FormatHandler<eFileType::OBJ> &fh, + const OBJMesh &obj_mesh_data) const { const char *object_name = obj_mesh_data.get_object_name(); if (export_params_.export_object_groups) { - write_object_group(obj_mesh_data); + write_object_group(fh, obj_mesh_data); return; } - file_handler_->write<eOBJSyntaxElement::object_name>(object_name); + fh.write<eOBJSyntaxElement::object_name>(object_name); } -void OBJWriter::write_vertex_coords(const OBJMesh &obj_mesh_data) const +/* Split up large meshes into multi-threaded jobs; each job processes + * this amount of items. */ +static const int chunk_size = 32768; +static int calc_chunk_count(int count) { - const int tot_vertices = obj_mesh_data.tot_vertices(); - for (int i = 0; i < tot_vertices; i++) { - float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); - file_handler_->write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]); - } + return (count + chunk_size - 1) / chunk_size; } -void OBJWriter::write_uv_coords(OBJMesh &r_obj_mesh_data) const +/* Write /tot_count/ items to OBJ file output. Each item is written + * by a /function/ that should be independent from other items. + * If the amount of items is large enough (> chunk_size), then writing + * will be done in parallel, into temporary FormatHandler buffers that + * will be written into the final /fh/ buffer at the end. + */ +template<typename Function> +void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh, + int tot_count, + const Function &function) { - Vector<std::array<float, 2>> uv_coords; - /* UV indices are calculated and stored in an OBJMesh member here. */ - r_obj_mesh_data.store_uv_coords_and_indices(uv_coords); - - for (const std::array<float, 2> &uv_vertex : uv_coords) { - file_handler_->write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]); + if (tot_count <= 0) { + return; } -} - -void OBJWriter::write_poly_normals(OBJMesh &obj_mesh_data) -{ - obj_mesh_data.ensure_mesh_normals(); - Vector<float3> normals; - obj_mesh_data.store_normal_coords_and_indices(normals); - for (const float3 &normal : normals) { - file_handler_->write<eOBJSyntaxElement::normal>(normal[0], normal[1], normal[2]); + /* If we have just one chunk, process it directly into the output + * buffer - avoids all the job scheduling and temporary vector allocation + * overhead. */ + const int chunk_count = calc_chunk_count(tot_count); + if (chunk_count == 1) { + for (int i = 0; i < tot_count; i++) { + function(fh, i); + } + return; + } + /* Give each chunk its own temporary output buffer, and process them in parallel. */ + std::vector<FormatHandler<eFileType::OBJ>> buffers(chunk_count); + blender::threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) { + for (const int r : range) { + int i_start = r * chunk_size; + int i_end = std::min(i_start + chunk_size, tot_count); + auto &buf = buffers[r]; + for (int i = i_start; i < i_end; i++) { + function(buf, i); + } + } + }); + /* Emit all temporary output buffers into the destination buffer. */ + for (auto &buf : buffers) { + fh.append_from(buf); } } -int OBJWriter::write_smooth_group(const OBJMesh &obj_mesh_data, - const int poly_index, - const int last_poly_smooth_group) const +void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, + const OBJMesh &obj_mesh_data) const { - int current_group = SMOOTH_GROUP_DISABLED; - if (!export_params_.export_smooth_groups && obj_mesh_data.is_ith_poly_smooth(poly_index)) { - /* Smooth group calculation is disabled, but polygon is smooth-shaded. */ - current_group = SMOOTH_GROUP_DEFAULT; - } - else if (obj_mesh_data.is_ith_poly_smooth(poly_index)) { - /* Smooth group calc is enabled and polygon is smooth–shaded, so find the group. */ - current_group = obj_mesh_data.ith_smooth_group(poly_index); - } - - if (current_group == last_poly_smooth_group) { - /* Group has already been written, even if it is "s 0". */ - return current_group; - } - file_handler_->write<eOBJSyntaxElement::smooth_group>(current_group); - return current_group; + 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]); + }); } -int16_t OBJWriter::write_poly_material(const OBJMesh &obj_mesh_data, - const int poly_index, - const int16_t last_poly_mat_nr, - std::function<const char *(int)> matname_fn) const +void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const { - if (!export_params_.export_materials || obj_mesh_data.tot_materials() <= 0) { - return last_poly_mat_nr; - } - const int16_t current_mat_nr = obj_mesh_data.ith_poly_matnr(poly_index); - /* Whenever a polygon with a new material is encountered, write its material - * and/or group, otherwise pass. */ - if (last_poly_mat_nr == current_mat_nr) { - return current_mat_nr; - } - if (current_mat_nr == NOT_FOUND) { - file_handler_->write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED); - return current_mat_nr; - } - if (export_params_.export_object_groups) { - write_object_group(obj_mesh_data); - } - const char *mat_name = matname_fn(current_mat_nr); - if (!mat_name) { - mat_name = MATERIAL_GROUP_DISABLED; - } - file_handler_->write<eOBJSyntaxElement::poly_usemtl>(mat_name); - - return current_mat_nr; + const Vector<float2> &uv_coords = r_obj_mesh_data.get_uv_coords(); + const int tot_count = uv_coords.size(); + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + const float2 &uv_vertex = uv_coords[i]; + buf.write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]); + }); } -int16_t OBJWriter::write_vertex_group(const OBJMesh &obj_mesh_data, - const int poly_index, - const int16_t last_poly_vertex_group) const +void OBJWriter::write_poly_normals(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data) { - if (!export_params_.export_vertex_groups) { - return last_poly_vertex_group; - } - const int16_t current_group = obj_mesh_data.get_poly_deform_group_index(poly_index); - - if (current_group == last_poly_vertex_group) { - /* No vertex group found in this polygon, just like in the last iteration. */ - return current_group; - } - if (current_group == NOT_FOUND) { - file_handler_->write<eOBJSyntaxElement::object_group>(DEFORM_GROUP_DISABLED); - return current_group; - } - file_handler_->write<eOBJSyntaxElement::object_group>( - obj_mesh_data.get_poly_deform_group_name(current_group)); - return current_group; + /* Poly normals should be calculated earlier via store_normal_coords_and_indices. */ + const Vector<float3> &normal_coords = obj_mesh_data.get_normal_coords(); + const int tot_count = normal_coords.size(); + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + const float3 &normal = normal_coords[i]; + buf.write<eOBJSyntaxElement::normal>(normal[0], normal[1], normal[2]); + }); } OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer( @@ -278,32 +268,85 @@ OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer( return &OBJWriter::write_vert_indices; } -void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data, - std::function<const char *(int)> matname_fn) +static int get_smooth_group(const OBJMesh &mesh, const OBJExportParams ¶ms, int poly_idx) { - int last_poly_smooth_group = NEGATIVE_INIT; - int16_t last_poly_vertex_group = NEGATIVE_INIT; - int16_t last_poly_mat_nr = NEGATIVE_INIT; + if (poly_idx < 0) { + return NEGATIVE_INIT; + } + int group = SMOOTH_GROUP_DISABLED; + if (mesh.is_ith_poly_smooth(poly_idx)) { + group = !params.export_smooth_groups ? SMOOTH_GROUP_DEFAULT : mesh.ith_smooth_group(poly_idx); + } + return group; +} +void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + const OBJMesh &obj_mesh_data, + std::function<const char *(int)> matname_fn) +{ const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer( obj_mesh_data.tot_uv_vertices()); const int tot_polygons = obj_mesh_data.tot_polygons(); - for (int i = 0; i < tot_polygons; i++) { + obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler<eFileType::OBJ> &buf, int i) { Vector<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i); Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i); Vector<int> poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i); - last_poly_smooth_group = write_smooth_group(obj_mesh_data, i, last_poly_smooth_group); - last_poly_vertex_group = write_vertex_group(obj_mesh_data, i, last_poly_vertex_group); - last_poly_mat_nr = write_poly_material(obj_mesh_data, i, last_poly_mat_nr, matname_fn); - (this->*poly_element_writer)(poly_vertex_indices, poly_uv_indices, poly_normal_indices); - } + /* Write smoothing group if different from previous. */ + { + const int prev_group = get_smooth_group(obj_mesh_data, export_params_, i - 1); + const int group = get_smooth_group(obj_mesh_data, export_params_, i); + if (group != prev_group) { + buf.write<eOBJSyntaxElement::smooth_group>(group); + } + } + + /* Write vertex group if different from previous. */ + if (export_params_.export_vertex_groups) { + const int16_t prev_group = i == 0 ? NEGATIVE_INIT : + obj_mesh_data.get_poly_deform_group_index(i - 1); + const int16_t group = obj_mesh_data.get_poly_deform_group_index(i); + if (group != prev_group) { + buf.write<eOBJSyntaxElement::object_group>( + group == NOT_FOUND ? DEFORM_GROUP_DISABLED : + obj_mesh_data.get_poly_deform_group_name(group)); + } + } + + /* Write material name and material group if different from previous. */ + if (export_params_.export_materials && obj_mesh_data.tot_materials() > 0) { + const int16_t prev_mat = i == 0 ? NEGATIVE_INIT : obj_mesh_data.ith_poly_matnr(i - 1); + const int16_t mat = obj_mesh_data.ith_poly_matnr(i); + if (mat != prev_mat) { + if (mat == NOT_FOUND) { + buf.write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED); + } + else { + if (export_params_.export_object_groups) { + write_object_group(buf, obj_mesh_data); + } + const char *mat_name = matname_fn(mat); + if (!mat_name) { + mat_name = MATERIAL_GROUP_DISABLED; + } + buf.write<eOBJSyntaxElement::poly_usemtl>(mat_name); + } + } + } + + /* Write polygon elements. */ + (this->*poly_element_writer)( + buf, offsets, poly_vertex_indices, poly_uv_indices, poly_normal_indices); + }); } -void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const +void OBJWriter::write_edges_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + const OBJMesh &obj_mesh_data) const { - obj_mesh_data.ensure_mesh_edges(); + /* Note: ensure_mesh_edges should be called before. */ const int tot_edges = obj_mesh_data.tot_edges(); for (int edge_index = 0; edge_index < tot_edges; edge_index++) { const std::optional<std::array<int, 2>> vertex_indices = @@ -311,13 +354,13 @@ void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const if (!vertex_indices) { continue; } - file_handler_->write<eOBJSyntaxElement::edge>( - (*vertex_indices)[0] + index_offsets_.vertex_offset + 1, - (*vertex_indices)[1] + index_offsets_.vertex_offset + 1); + fh.write<eOBJSyntaxElement::edge>((*vertex_indices)[0] + offsets.vertex_offset + 1, + (*vertex_indices)[1] + offsets.vertex_offset + 1); } } -void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const +void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, + const OBJCurve &obj_nurbs_data) const { const int total_splines = obj_nurbs_data.total_splines(); for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) { @@ -325,15 +368,15 @@ void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) { const float3 vertex_coords = obj_nurbs_data.vertex_coordinates( spline_idx, vertex_idx, export_params_.scaling_factor); - file_handler_->write<eOBJSyntaxElement::vertex_coords>( + fh.write<eOBJSyntaxElement::vertex_coords>( vertex_coords[0], vertex_coords[1], vertex_coords[2]); } const char *nurbs_name = obj_nurbs_data.get_curve_name(); const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx); - file_handler_->write<eOBJSyntaxElement::object_group>(nurbs_name); - file_handler_->write<eOBJSyntaxElement::cstype>(); - file_handler_->write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree); + fh.write<eOBJSyntaxElement::object_group>(nurbs_name); + fh.write<eOBJSyntaxElement::cstype>(); + fh.write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree); /** * The numbers written here are indices into the vertex coordinates written * earlier, relative to the line that is going to be written. @@ -342,23 +385,24 @@ void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices. */ const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx); - file_handler_->write<eOBJSyntaxElement::curve_element_begin>(); + fh.write<eOBJSyntaxElement::curve_element_begin>(); for (int i = 0; i < total_control_points; i++) { /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the * last vertex coordinate, -2 second last. */ - file_handler_->write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1)); + fh.write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1)); } - file_handler_->write<eOBJSyntaxElement::curve_element_end>(); + fh.write<eOBJSyntaxElement::curve_element_end>(); /** * In `parm u 0 0.1 ..` line:, (total control points + 2) equidistant numbers in the * parameter range are inserted. However for curves with endpoint flag, * first degree+1 numbers are zeroes, and last degree+1 numbers are ones */ + const short flagsu = obj_nurbs_data.get_nurbs_flagu(spline_idx); const bool cyclic = flagsu & CU_NURB_CYCLIC; const bool endpoint = !cyclic && (flagsu & CU_NURB_ENDPOINT); - file_handler_->write<eOBJSyntaxElement::nurbs_parameter_begin>(); + fh.write<eOBJSyntaxElement::nurbs_parameter_begin>(); for (int i = 1; i <= total_control_points + 2; i++) { float parm = 1.0f * i / (total_control_points + 2 + 1); if (endpoint) { @@ -369,21 +413,14 @@ void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const parm = 1; } } - file_handler_->write<eOBJSyntaxElement::nurbs_parameters>(parm); + fh.write<eOBJSyntaxElement::nurbs_parameters>(parm); } - file_handler_->write<eOBJSyntaxElement::nurbs_parameter_end>(); + fh.write<eOBJSyntaxElement::nurbs_parameter_end>(); - file_handler_->write<eOBJSyntaxElement::nurbs_group_end>(); + fh.write<eOBJSyntaxElement::nurbs_group_end>(); } } -void OBJWriter::update_index_offsets(const OBJMesh &obj_mesh_data) -{ - index_offsets_.vertex_offset += obj_mesh_data.tot_vertices(); - index_offsets_.uv_vertex_offset += obj_mesh_data.tot_uv_vertices(); - index_offsets_.normal_offset += obj_mesh_data.tot_normal_indices(); -} - /* -------------------------------------------------------------------- */ /** \name .MTL writers. * \{ */ @@ -406,18 +443,31 @@ MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false) if (!ok) { throw std::system_error(ENAMETOOLONG, std::system_category(), ""); } - file_handler_ = std::make_unique<FormattedFileHandler<eFileType::MTL>>(mtl_filepath_); + outfile_ = BLI_fopen(mtl_filepath_.c_str(), "wb"); + if (!outfile_) { + throw std::system_error(errno, std::system_category(), "Cannot open file " + mtl_filepath_); + } +} +MTLWriter::~MTLWriter() +{ + if (outfile_) { + fmt_handler_.write_to_file(outfile_); + if (std::fclose(outfile_)) { + std::cerr << "Error: could not close the file '" << mtl_filepath_ + << "' properly, it may be corrupted." << std::endl; + } + } } -void MTLWriter::write_header(const char *blen_filepath) const +void MTLWriter::write_header(const char *blen_filepath) { using namespace std::string_literals; const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ? BLI_path_basename(blen_filepath) : "None"; - file_handler_->write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + - " MTL File: '" + blen_basename + "'\n"); - file_handler_->write<eMTLSyntaxElement::string>("# www.blender.org\n"); + fmt_handler_.write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + + " MTL File: '" + blen_basename + "'\n"); + fmt_handler_.write<eMTLSyntaxElement::string>("# www.blender.org\n"); } StringRefNull MTLWriter::mtl_file_path() const @@ -427,18 +477,18 @@ StringRefNull MTLWriter::mtl_file_path() const void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material) { - file_handler_->write<eMTLSyntaxElement::Ns>(mtl_material.Ns); - file_handler_->write<eMTLSyntaxElement::Ka>( + fmt_handler_.write<eMTLSyntaxElement::Ns>(mtl_material.Ns); + fmt_handler_.write<eMTLSyntaxElement::Ka>( mtl_material.Ka.x, mtl_material.Ka.y, mtl_material.Ka.z); - file_handler_->write<eMTLSyntaxElement::Kd>( + fmt_handler_.write<eMTLSyntaxElement::Kd>( mtl_material.Kd.x, mtl_material.Kd.y, mtl_material.Kd.z); - file_handler_->write<eMTLSyntaxElement::Ks>( + fmt_handler_.write<eMTLSyntaxElement::Ks>( mtl_material.Ks.x, mtl_material.Ks.y, mtl_material.Ks.z); - file_handler_->write<eMTLSyntaxElement::Ke>( + fmt_handler_.write<eMTLSyntaxElement::Ke>( mtl_material.Ke.x, mtl_material.Ke.y, mtl_material.Ke.z); - file_handler_->write<eMTLSyntaxElement::Ni>(mtl_material.Ni); - file_handler_->write<eMTLSyntaxElement::d>(mtl_material.d); - file_handler_->write<eMTLSyntaxElement::illum>(mtl_material.illum); + fmt_handler_.write<eMTLSyntaxElement::Ni>(mtl_material.Ni); + fmt_handler_.write<eMTLSyntaxElement::d>(mtl_material.d); + fmt_handler_.write<eMTLSyntaxElement::illum>(mtl_material.illum); } void MTLWriter::write_texture_map( @@ -461,8 +511,8 @@ void MTLWriter::write_texture_map( #define SYNTAX_DISPATCH(eMTLSyntaxElement) \ if (texture_map.key == eMTLSyntaxElement) { \ - file_handler_->write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \ - texture_map.value.image_path); \ + fmt_handler_.write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \ + texture_map.value.image_path); \ return; \ } @@ -486,8 +536,8 @@ void MTLWriter::write_materials() mtlmaterials_.end(), [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; }); for (const MTLMaterial &mtlmat : mtlmaterials_) { - file_handler_->write<eMTLSyntaxElement::string>("\n"); - file_handler_->write<eMTLSyntaxElement::newmtl>(mtlmat.name); + fmt_handler_.write<eMTLSyntaxElement::string>("\n"); + fmt_handler_.write<eMTLSyntaxElement::newmtl>(mtlmat.name); write_bsdf_properties(mtlmat); for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map : mtlmat.texture_maps.items()) { 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 7385d9fabe2..c88955e5090 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 @@ -49,14 +49,29 @@ struct IndexOffsets { class OBJWriter : NonMovable, NonCopyable { private: const OBJExportParams &export_params_; - std::unique_ptr<FormattedFileHandler<eFileType::OBJ>> file_handler_ = nullptr; - IndexOffsets index_offsets_{0, 0, 0}; + std::string outfile_path_; + FILE *outfile_; public: OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false) - : export_params_(export_params) + : export_params_(export_params), outfile_path_(filepath), outfile_(nullptr) { - file_handler_ = std::make_unique<FormattedFileHandler<eFileType::OBJ>>(filepath); + outfile_ = BLI_fopen(filepath, "wb"); + if (!outfile_) { + throw std::system_error(errno, std::system_category(), "Cannot open file " + outfile_path_); + } + } + ~OBJWriter() + { + if (outfile_ && std::fclose(outfile_)) { + std::cerr << "Error: could not close the file '" << outfile_path_ + << "' properly, it may be corrupted." << std::endl; + } + } + + FILE *get_outfile() const + { + return outfile_; } void write_header() const; @@ -64,11 +79,11 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write object's name or group. */ - void write_object_name(const OBJMesh &obj_mesh_data) const; + void write_object_name(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const; /** * Write an object's group with mesh and/or material name appended conditionally. */ - void write_object_group(const OBJMesh &obj_mesh_data) const; + void write_object_group(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const; /** * Write file name of Material Library in .OBJ file. */ @@ -76,38 +91,17 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write vertex coordinates for all vertices as "v x y z". */ - void write_vertex_coords(const OBJMesh &obj_mesh_data) const; + void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const; /** * Write UV vertex coordinates for all vertices as `vt u v`. * \note UV indices are stored here, but written with polygons later. */ - void write_uv_coords(OBJMesh &obj_mesh_data) const; + void write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data) const; /** * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z". * \note Normal indices ares stored here, but written with polygons later. */ - void write_poly_normals(OBJMesh &obj_mesh_data); - /** - * Write smooth group if polygon at the given index is shaded smooth else "s 0" - */ - int write_smooth_group(const OBJMesh &obj_mesh_data, - int poly_index, - int last_poly_smooth_group) const; - /** - * Write material name and material group of a polygon in the .OBJ file. - * \return #mat_nr of the polygon at the given index. - * \note It doesn't write to the material library. - */ - int16_t write_poly_material(const OBJMesh &obj_mesh_data, - int poly_index, - int16_t last_poly_mat_nr, - std::function<const char *(int)> matname_fn) const; - /** - * Write the name of the deform group of a polygon. - */ - int16_t write_vertex_group(const OBJMesh &obj_mesh_data, - int poly_index, - int16_t last_poly_vertex_group) const; + void write_poly_normals(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data); /** * Write polygon elements with at least vertex indices, and conditionally with UV vertex * indices and polygon normal indices. Also write groups: smooth, vertex, material. @@ -115,25 +109,25 @@ class OBJWriter : NonMovable, NonCopyable { * name used in the .obj file. * \note UV indices were stored while writing UV vertices. */ - void write_poly_elements(const OBJMesh &obj_mesh_data, + void write_poly_elements(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + const OBJMesh &obj_mesh_data, std::function<const char *(int)> matname_fn); /** * Write loose edges of a mesh as "l v1 v2". */ - void write_edges_indices(const OBJMesh &obj_mesh_data) const; + void write_edges_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + const OBJMesh &obj_mesh_data) const; /** * Write a NURBS curve to the .OBJ file in parameter form. */ - void write_nurbs_curve(const OBJCurve &obj_nurbs_data) const; - - /** - * When there are multiple objects in a frame, the indices of previous objects' coordinates or - * normals add up. - */ - void update_index_offsets(const OBJMesh &obj_mesh_data); + void write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, const OBJCurve &obj_nurbs_data) const; private: - using func_vert_uv_normal_indices = void (OBJWriter::*)(Span<int> vert_indices, + using func_vert_uv_normal_indices = void (OBJWriter::*)(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> uv_indices, Span<int> normal_indices) const; /** @@ -144,25 +138,33 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...". */ - void write_vert_uv_normal_indices(Span<int> vert_indices, + void write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> uv_indices, Span<int> normal_indices) const; /** * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...". */ - void write_vert_normal_indices(Span<int> vert_indices, + void write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> /*uv_indices*/, Span<int> normal_indices) const; /** * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...". */ - void write_vert_uv_indices(Span<int> vert_indices, + void write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> uv_indices, Span<int> /*normal_indices*/) const; /** * Write one line of polygon indices as "f v1 v2 ...". */ - void write_vert_indices(Span<int> vert_indices, + void write_vert_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> /*uv_indices*/, Span<int> /*normal_indices*/) const; }; @@ -172,7 +174,8 @@ class OBJWriter : NonMovable, NonCopyable { */ class MTLWriter : NonMovable, NonCopyable { private: - std::unique_ptr<FormattedFileHandler<eFileType::MTL>> file_handler_ = nullptr; + FormatHandler<eFileType::MTL> fmt_handler_; + FILE *outfile_; std::string mtl_filepath_; Vector<MTLMaterial> mtlmaterials_; /* Map from a Material* to an index into mtlmaterials_. */ @@ -183,8 +186,9 @@ class MTLWriter : NonMovable, NonCopyable { * Create the .MTL file. */ MTLWriter(const char *obj_filepath) noexcept(false); + ~MTLWriter(); - void write_header(const char *blen_filepath) const; + void write_header(const char *blen_filepath); /** * Write all of the material specifications to the MTL file. * For consistency of output from run to run (useful for testing), 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 2eb2b66335d..7e5fe1ca526 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh @@ -24,6 +24,7 @@ #include <string> #include <system_error> #include <type_traits> +#include <vector> #include "BLI_compiler_attrs.h" #include "BLI_fileops.h" @@ -124,6 +125,14 @@ constexpr bool is_type_integral = (... && std::is_integral_v<std::decay_t<T>>); template<typename... T> constexpr bool is_type_string_related = (... && std::is_constructible_v<std::string, T>); +/* GCC (at least 9.3) while compiling the obj_exporter_tests.cc with optimizations on, + * results in "obj_export_io.hh:205:18: warning: ‘%s’ directive output truncated writing 34 bytes + * into a region of size 6" and similar warnings. Yes the output is truncated, and that is covered + * as an edge case by tests on purpose. */ +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-truncation" +#endif template<typename... T> constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key) { @@ -264,31 +273,52 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eMTLSyntaxElement key } } } +#if defined __GNUC__ +# pragma GCC diagnostic pop +#endif /** - * File format and syntax agnostic file writer. + * File format and syntax agnostic file buffer writer. + * All writes are done into an internal chunked memory buffer + * (list of default 64 kilobyte blocks). + * Call write_fo_file once in a while to write the memory buffer(s) + * into the given file. */ -template<eFileType filetype> class FormattedFileHandler : NonCopyable, NonMovable { +template<eFileType filetype, + size_t buffer_chunk_size = 64 * 1024, + size_t write_local_buffer_size = 1024> +class FormatHandler : NonCopyable, NonMovable { private: - std::FILE *outfile_ = nullptr; - std::string outfile_path_; + typedef std::vector<char> VectorChar; + std::vector<VectorChar> blocks_; public: - FormattedFileHandler(std::string outfile_path) noexcept(false) - : outfile_path_(std::move(outfile_path)) + /* Write contents to the buffer(s) into a file, and clear the buffers. */ + void write_to_file(FILE *f) { - outfile_ = BLI_fopen(outfile_path_.c_str(), "w"); - if (!outfile_) { - throw std::system_error(errno, std::system_category(), "Cannot open file " + outfile_path_); - } + for (const auto &b : blocks_) + fwrite(b.data(), 1, b.size(), f); + blocks_.clear(); } - ~FormattedFileHandler() + std::string get_as_string() const { - if (outfile_ && std::fclose(outfile_)) { - std::cerr << "Error: could not close the file '" << outfile_path_ - << "' properly, it may be corrupted." << std::endl; - } + std::string s; + for (const auto &b : blocks_) + s.append(b.data(), b.size()); + return s; + } + size_t get_block_count() const + { + return blocks_.size(); + } + + void append_from(FormatHandler<filetype, buffer_chunk_size, write_local_buffer_size> &v) + { + blocks_.insert(blocks_.end(), + std::make_move_iterator(v.blocks_.begin()), + std::make_move_iterator(v.blocks_.end())); + v.blocks_.clear(); } /** @@ -298,7 +328,7 @@ template<eFileType filetype> class FormattedFileHandler : NonCopyable, NonMovabl * `eFileType::MTL`. */ template<typename FileTypeTraits<filetype>::SyntaxType key, typename... T> - constexpr void write(T &&...args) const + constexpr void write(T &&...args) { /* Get format syntax, number of arguments expected and whether types of given arguments are * valid. @@ -339,13 +369,47 @@ template<eFileType filetype> class FormattedFileHandler : NonCopyable, NonMovabl } } - template<typename... T> constexpr void write_impl(const char *fmt, T &&...args) const + /* Ensure the last block contains at least this amount of free space. + * If not, add a new block with max of block size & the amount of space needed. */ + void ensure_space(size_t at_least) + { + if (blocks_.empty() || (blocks_.back().capacity() - blocks_.back().size() < at_least)) { + VectorChar &b = blocks_.emplace_back(VectorChar()); + b.reserve(std::max(at_least, buffer_chunk_size)); + } + } + + template<typename... T> constexpr void write_impl(const char *fmt, T &&...args) { if constexpr (sizeof...(T) == 0) { - std::fputs(fmt, outfile_); + /* No arguments: just emit the format string. */ + size_t len = strlen(fmt); + ensure_space(len); + VectorChar &bb = blocks_.back(); + bb.insert(bb.end(), fmt, fmt + len); } else { - std::fprintf(outfile_, fmt, convert_to_primitive(std::forward<T>(args))...); + /* Format into a local buffer. */ + char buf[write_local_buffer_size]; + int needed = std::snprintf( + buf, write_local_buffer_size, fmt, convert_to_primitive(std::forward<T>(args))...); + if (needed < 0) + throw std::system_error( + errno, std::system_category(), "Failed to format obj export string into a buffer"); + ensure_space(needed + 1); /* Ensure space for zero terminator. */ + VectorChar &bb = blocks_.back(); + if (needed < write_local_buffer_size) { + /* String formatted successfully into the local buffer, copy it. */ + bb.insert(bb.end(), buf, buf + needed); + } + else { + /* Would need more space than the local buffer: insert said space and format again into + * that. */ + size_t bbEnd = bb.size(); + bb.insert(bb.end(), needed, ' '); + std::snprintf( + bb.data() + bbEnd, needed + 1, fmt, convert_to_primitive(std::forward<T>(args))...); + } } } }; 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 14e50d726c0..468631cdd82 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -69,16 +69,28 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj */ OBJMesh::~OBJMesh() { - free_mesh_if_needed(); - if (poly_smooth_groups_) { - MEM_freeN(poly_smooth_groups_); - } + clear(); } void OBJMesh::free_mesh_if_needed() { if (mesh_eval_needs_free_ && export_mesh_eval_) { BKE_id_free(nullptr, export_mesh_eval_); + export_mesh_eval_ = nullptr; + mesh_eval_needs_free_ = false; + } +} + +void OBJMesh::clear() +{ + free_mesh_if_needed(); + uv_indices_.clear_and_make_inline(); + uv_coords_.clear_and_make_inline(); + loop_to_normal_index_.clear_and_make_inline(); + normal_coords_.clear_and_make_inline(); + if (poly_smooth_groups_) { + MEM_freeN(poly_smooth_groups_); + poly_smooth_groups_ = nullptr; } } @@ -256,7 +268,7 @@ Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const return r_poly_vertex_indices; } -void OBJMesh::store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords) +void OBJMesh::store_uv_coords_and_indices() { const MPoly *mpoly = export_mesh_eval_->mpoly; const MLoop *mloop = export_mesh_eval_->mloop; @@ -276,7 +288,7 @@ void OBJMesh::store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coo uv_indices_.resize(totpoly); /* At least total vertices of a mesh will be present in its texture map. So * reserve minimum space early. */ - r_uv_coords.reserve(totvert); + uv_coords_.reserve(totvert); tot_uv_vertices_ = 0; for (int vertex_index = 0; vertex_index < totvert; vertex_index++) { @@ -288,11 +300,10 @@ void OBJMesh::store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coo const int vertices_in_poly = mpoly[uv_vert->poly_index].totloop; /* Store UV vertex coordinates. */ - r_uv_coords.resize(tot_uv_vertices_); + uv_coords_.resize(tot_uv_vertices_); const int loopstart = mpoly[uv_vert->poly_index].loopstart; Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2); - r_uv_coords[tot_uv_vertices_ - 1][0] = vert_uv_coords[0]; - r_uv_coords[tot_uv_vertices_ - 1][1] = vert_uv_coords[1]; + uv_coords_[tot_uv_vertices_ - 1] = float2(vert_uv_coords[0], vert_uv_coords[1]); /* Store UV vertex indices. */ uv_indices_[uv_vert->poly_index].resize(vertices_in_poly); @@ -340,7 +351,7 @@ static float3 round_float3_to_n_digits(const float3 &v, int round_digits) return ans; } -void OBJMesh::store_normal_coords_and_indices(Vector<float3> &r_normal_coords) +void OBJMesh::store_normal_coords_and_indices() { /* We'll round normal components to 4 digits. * This will cover up some minor differences @@ -371,7 +382,7 @@ void OBJMesh::store_normal_coords_and_indices(Vector<float3> &r_normal_coords) if (loop_norm_index == -1) { loop_norm_index = cur_normal_index++; normal_to_index.add(rounded_loop_normal, loop_norm_index); - r_normal_coords.append(rounded_loop_normal); + normal_coords_.append(rounded_loop_normal); } loop_to_normal_index_[loop_index] = loop_norm_index; } @@ -383,7 +394,7 @@ void OBJMesh::store_normal_coords_and_indices(Vector<float3> &r_normal_coords) if (poly_norm_index == -1) { poly_norm_index = cur_normal_index++; normal_to_index.add(rounded_poly_normal, poly_norm_index); - r_normal_coords.append(rounded_poly_normal); + normal_coords_.append(rounded_poly_normal); } for (int i = 0; i < mpoly.totloop; ++i) { int loop_index = mpoly.loopstart + i; 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 f3ace140006..4cfbffdcebc 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -82,11 +82,19 @@ class OBJMesh : NonCopyable { * Per-polygon-per-vertex UV vertex indices. */ Vector<Vector<int>> uv_indices_; + /* + * UV vertices. + */ + Vector<float2> uv_coords_; /** * Per-loop normal index. */ Vector<int> loop_to_normal_index_; /* + * Normal coords. + */ + Vector<float3> normal_coords_; + /* * Total number of normal indices (maximum entry, plus 1, in * the loop_to_norm_index_ vector). */ @@ -108,6 +116,9 @@ class OBJMesh : NonCopyable { OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object); ~OBJMesh(); + /* Clear various arrays to release potentially large memory allocations. */ + void clear(); + int tot_vertices() const; int tot_polygons() const; int tot_uv_vertices() const; @@ -165,10 +176,14 @@ class OBJMesh : NonCopyable { Vector<int> calc_poly_vertex_indices(int poly_index) const; /** * Calculate UV vertex coordinates of an Object. - * - * \note Also store the UV vertex indices in the member variable. + * Stores the coordinates and UV vertex indices in the member variables. */ - void store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords); + void store_uv_coords_and_indices(); + /* Get UV coordinates computed by store_uv_coords_and_indices. */ + const Vector<float2> &get_uv_coords() const + { + return uv_coords_; + } Span<int> calc_poly_uv_indices(int poly_index) const; /** * Calculate polygon normal of a polygon at given index. @@ -177,10 +192,15 @@ class OBJMesh : NonCopyable { */ float3 calc_poly_normal(int poly_index) const; /** - * Find the unique normals of the mesh and return them in \a r_normal_coords. - * Store the indices into that vector with for each loop in this #OBJMesh. + * Find the unique normals of the mesh and stores them in a member variable. + * Also stores the indices into that vector with for each loop. */ - void store_normal_coords_and_indices(Vector<float3> &r_normal_coords); + void store_normal_coords_and_indices(); + /* Get normals calculate by store_normal_coords_and_indices. */ + const Vector<float3> &get_normal_coords() const + { + return normal_coords_; + } /** * Calculate a polygon's polygon/loop normal indices. * \param poly_index Index of the polygon to calculate indices for. diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc index 0c753ccdcac..187f50277f1 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc @@ -25,6 +25,7 @@ #include "BKE_scene.h" #include "BLI_path_util.h" +#include "BLI_task.hh" #include "BLI_vector.hh" #include "DEG_depsgraph_query.h" @@ -155,44 +156,97 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me MTLWriter *mtl_writer, const OBJExportParams &export_params) { + /* Parallelization is over meshes/objects, which means + * we have to have the output text buffer for each object, + * and write them all into the file at the end. */ + size_t count = exportable_as_mesh.size(); + std::vector<FormatHandler<eFileType::OBJ>> buffers(count); + + /* Serial: gather material indices, ensure normals & edges. */ + Vector<Vector<int>> mtlindices; if (mtl_writer) { obj_writer.write_mtllib_name(mtl_writer->mtl_file_path()); + mtlindices.reserve(count); } - - /* Smooth groups and UV vertex indices may make huge memory allocations, so they should be freed - * right after they're written, instead of waiting for #blender::Vector to clean them up after - * all the objects are exported. */ for (auto &obj_mesh : exportable_as_mesh) { - obj_writer.write_object_name(*obj_mesh); - obj_writer.write_vertex_coords(*obj_mesh); - Vector<int> obj_mtlindices; + OBJMesh &obj = *obj_mesh; + if (mtl_writer) { + mtlindices.append(mtl_writer->add_materials(obj)); + } + if (export_params.export_normals) { + obj.ensure_mesh_normals(); + } + obj.ensure_mesh_edges(); + } - if (obj_mesh->tot_polygons() > 0) { - if (export_params.export_smooth_groups) { - obj_mesh->calc_smooth_groups(export_params.smooth_groups_bitflags); - } + /* Parallel over meshes: store normal coords & indices, uv coords and indices. */ + blender::threading::parallel_for(IndexRange(count), 1, [&](IndexRange range) { + for (const int i : range) { + OBJMesh &obj = *exportable_as_mesh[i]; if (export_params.export_normals) { - obj_writer.write_poly_normals(*obj_mesh); + obj.store_normal_coords_and_indices(); } if (export_params.export_uv) { - obj_writer.write_uv_coords(*obj_mesh); - } - if (mtl_writer) { - obj_mtlindices = mtl_writer->add_materials(*obj_mesh); + obj.store_uv_coords_and_indices(); } - /* This function takes a 0-indexed slot index for the obj_mesh object and - * returns the material name that we are using in the .obj file for it. */ - std::function<const char *(int)> matname_fn = [&](int s) -> const char * { - if (!mtl_writer || s < 0 || s >= obj_mtlindices.size()) { - return nullptr; + } + }); + + /* Serial: calculate index offsets; these are sequentially added + * over all meshes, and requite normal/uv indices to be calculated. */ + Vector<IndexOffsets> index_offsets; + index_offsets.reserve(count); + IndexOffsets offsets{0, 0, 0}; + for (auto &obj_mesh : exportable_as_mesh) { + OBJMesh &obj = *obj_mesh; + index_offsets.append(offsets); + offsets.vertex_offset += obj.tot_vertices(); + offsets.uv_vertex_offset += obj.tot_uv_vertices(); + offsets.normal_offset += obj.tot_normal_indices(); + } + + /* Parallel over meshes: main result writing. */ + blender::threading::parallel_for(IndexRange(count), 1, [&](IndexRange range) { + for (const int i : range) { + OBJMesh &obj = *exportable_as_mesh[i]; + auto &fh = buffers[i]; + + obj_writer.write_object_name(fh, obj); + obj_writer.write_vertex_coords(fh, obj); + + if (obj.tot_polygons() > 0) { + if (export_params.export_smooth_groups) { + obj.calc_smooth_groups(export_params.smooth_groups_bitflags); + } + if (export_params.export_normals) { + obj_writer.write_poly_normals(fh, obj); } - return mtl_writer->mtlmaterial_name(obj_mtlindices[s]); - }; - obj_writer.write_poly_elements(*obj_mesh, matname_fn); + if (export_params.export_uv) { + obj_writer.write_uv_coords(fh, obj); + } + /* This function takes a 0-indexed slot index for the obj_mesh object and + * returns the material name that we are using in the .obj file for it. */ + const auto *obj_mtlindices = mtlindices.is_empty() ? nullptr : &mtlindices[i]; + std::function<const char *(int)> matname_fn = [&](int s) -> const char * { + if (!obj_mtlindices || s < 0 || s >= obj_mtlindices->size()) { + return nullptr; + } + return mtl_writer->mtlmaterial_name((*obj_mtlindices)[s]); + }; + obj_writer.write_poly_elements(fh, index_offsets[i], obj, matname_fn); + } + obj_writer.write_edges_indices(fh, index_offsets[i], obj); + + /* Nothing will need this object's data after this point, release + * various arrays here. */ + obj.clear(); } - obj_writer.write_edges_indices(*obj_mesh); + }); - obj_writer.update_index_offsets(*obj_mesh); + /* Write all the object text buffers into the output file. */ + FILE *f = obj_writer.get_outfile(); + for (auto &b : buffers) { + b.write_to_file(f); } } @@ -202,11 +256,13 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me static void write_nurbs_curve_objects(const Vector<std::unique_ptr<OBJCurve>> &exportable_as_nurbs, const OBJWriter &obj_writer) { + FormatHandler<eFileType::OBJ> fh; /* #OBJCurve doesn't have any dynamically allocated memory, so it's fine * to wait for #blender::Vector to clean the objects up. */ for (const std::unique_ptr<OBJCurve> &obj_curve : exportable_as_nurbs) { - obj_writer.write_nurbs_curve(*obj_curve); + obj_writer.write_nurbs_curve(fh, *obj_curve); } + fh.write_to_file(obj_writer.get_outfile()); } void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, const char *filepath) 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 dbadc33906d..58329f63650 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -238,6 +238,38 @@ TEST(obj_exporter_writer, mtllib) BLI_delete(out_file_path.c_str(), false, false); } +TEST(obj_exporter_writer, format_handler_buffer_chunking) +{ + /* Use a tiny buffer chunk size, so that the test below ends up creating several blocks. */ + FormatHandler<eFileType::OBJ, 16, 8> h; + h.write<eOBJSyntaxElement::object_name>("abc"); + h.write<eOBJSyntaxElement::object_name>("abcd"); + h.write<eOBJSyntaxElement::object_name>("abcde"); + h.write<eOBJSyntaxElement::object_name>("abcdef"); + h.write<eOBJSyntaxElement::object_name>("012345678901234567890123456789abcd"); + h.write<eOBJSyntaxElement::object_name>("123"); + h.write<eOBJSyntaxElement::curve_element_begin>(); + h.write<eOBJSyntaxElement::new_line>(); + h.write<eOBJSyntaxElement::nurbs_parameter_begin>(); + h.write<eOBJSyntaxElement::new_line>(); + + size_t got_blocks = h.get_block_count(); + ASSERT_EQ(got_blocks, 7); + + std::string got_string = h.get_as_string(); + using namespace std::string_literals; + const char *expected = R"(o abc +o abcd +o abcde +o abcdef +o 012345678901234567890123456789abcd +o 123 +curv 0.0 1.0 +parm u 0.0 +)"; + ASSERT_EQ(got_string, expected); +} + /* Return true if string #a and string #b are equal after their first newline. */ static bool strings_equal_after_first_lines(const std::string &a, const std::string &b) { @@ -391,8 +423,10 @@ TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs) _export.params.up_axis = OBJ_AXIS_Z_UP; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; - compare_obj_export_to_golden( - "io_tests/blend_geometry/nurbs_curves.blend", "io_tests/obj/nurbs_curves.obj", "", _export.params); + compare_obj_export_to_golden("io_tests/blend_geometry/nurbs_curves.blend", + "io_tests/obj/nurbs_curves.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, nurbs_as_mesh) diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 132121064c8..cfee35e147a 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -310,6 +310,13 @@ typedef struct IDOverrideLibrary { /** List of IDOverrideLibraryProperty structs. */ ListBase properties; + /** Override hierarchy root ID. Usually the actual root of the hierarchy, but not always + * in degenerated cases. + * + * All liboverrides of a same hierarchy (e.g. a character collection) share the same root. + */ + struct ID *hierarchy_root; + /* Read/write data. */ /* Temp ID storing extra override data (used for differential operations only currently). * Always NULL outside of read/write context. */ @@ -317,8 +324,6 @@ typedef struct IDOverrideLibrary { IDOverrideLibraryRuntime *runtime; - void *_pad_0; - unsigned int flag; char _pad_1[4]; } IDOverrideLibrary; @@ -890,7 +895,7 @@ typedef enum IDRecalcFlag { #define FILTER_ID_CF (1ULL << 28) #define FILTER_ID_WS (1ULL << 29) #define FILTER_ID_LP (1ULL << 31) -#define FILTER_ID_HA (1ULL << 32) +#define FILTER_ID_CV (1ULL << 32) #define FILTER_ID_PT (1ULL << 33) #define FILTER_ID_VO (1ULL << 34) #define FILTER_ID_SIM (1ULL << 35) @@ -901,7 +906,7 @@ typedef enum IDRecalcFlag { FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | \ FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | \ FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \ - FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM) + FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM) /** * This enum defines the index assigned to each type of IDs in the array returned by @@ -984,7 +989,7 @@ enum { INDEX_ID_ME, INDEX_ID_CU, INDEX_ID_MB, - INDEX_ID_HA, + INDEX_ID_CV, INDEX_ID_PT, INDEX_ID_VO, INDEX_ID_LT, diff --git a/source/blender/makesdna/DNA_ID_enums.h b/source/blender/makesdna/DNA_ID_enums.h index 45faf9e7f57..839c1e8933f 100644 --- a/source/blender/makesdna/DNA_ID_enums.h +++ b/source/blender/makesdna/DNA_ID_enums.h @@ -90,7 +90,7 @@ typedef enum ID_Type { ID_CF = MAKE_ID2('C', 'F'), /* CacheFile */ ID_WS = MAKE_ID2('W', 'S'), /* WorkSpace */ ID_LP = MAKE_ID2('L', 'P'), /* LightProbe */ - ID_HA = MAKE_ID2('H', 'A'), /* Hair */ + ID_CV = MAKE_ID2('C', 'V'), /* Curves */ ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */ ID_VO = MAKE_ID2('V', 'O'), /* Volume */ ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (geometry node groups) */ diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 82b20483902..1ca724b7108 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -478,9 +478,6 @@ typedef struct bPose { short flag; char _pad[2]; - /** Proxy layer: copy from armature, gets synced. */ - unsigned int proxy_layer; - char _pad1[4]; /** Local action time of this pose. */ float ctime; @@ -503,8 +500,6 @@ typedef struct bPose { /** Settings for visualization of bone animation. */ bAnimVizSettings avs; - /** Proxy active bone name, MAXBONENAME. */ - char proxy_act_bone[64]; } bPose; /* Pose->flag */ diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 566ffd19669..1005b5186aa 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -77,7 +77,7 @@ typedef struct Bone { /** dist, weight: for non-deformgroup deforms. */ float dist, weight; /** - * The width for block bones. + * The width for block bones. The final X/Z bone widths are double these values. * * \note keep in this order for transform code which stores a pointer to `xwidth`, * accessing length and `zwidth` as offsets. diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index d587bd8082b..b7ba05f5879 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * Constraint DNA data */ /** \file * \ingroup DNA + * Constraint DNA data. */ #pragma once @@ -714,8 +714,6 @@ typedef enum eBConstraint_Flags { CONSTRAINT_SPACEONCE = (1 << 6), /* influence ipo is on constraint itself, not in action channel */ CONSTRAINT_OWN_IPO = (1 << 7), - /* indicates that constraint was added locally (i.e. didn't come from the proxy-lib) */ - CONSTRAINT_PROXY_LOCAL = (1 << 8), /* indicates that constraint is temporarily disabled (only used in GE) */ CONSTRAINT_OFF = (1 << 9), /* use bbone curve shape when calculating headtail values (also used by dependency graph!) */ diff --git a/source/blender/makesdna/DNA_hair_defaults.h b/source/blender/makesdna/DNA_curves_defaults.h index 095e4fdf583..66c7a1bd71b 100644 --- a/source/blender/makesdna/DNA_hair_defaults.h +++ b/source/blender/makesdna/DNA_curves_defaults.h @@ -24,10 +24,10 @@ /* clang-format off */ /* -------------------------------------------------------------------- */ -/** \name Hair Struct +/** \name Curves Struct * \{ */ -#define _DNA_DEFAULT_Hair \ +#define _DNA_DEFAULT_Curves \ { \ .flag = 0, \ } diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h new file mode 100644 index 00000000000..c7f31557e48 --- /dev/null +++ b/source/blender/makesdna/DNA_curves_types.h @@ -0,0 +1,108 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup DNA + */ + +#pragma once + +#include "DNA_ID.h" +#include "DNA_customdata_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A reusable data structure for geometry consisting of many curves. All control point data is + * stored contiguously for better efficiency. Data for each curve is stored as a slice of the + * main #point_data array. + * + * The data structure is meant to be embedded in other data-blocks to allow reusing + * curve-processing algorithms for multiple Blender data-block types. + */ +typedef struct CurvesGeometry { + /** + * A runtime pointer to the "position" attribute data. + * \note This data is owned by #point_data. + */ + float (*position)[3]; + /** + * A runtime pointer to the "radius" attribute data. + * \note This data is owned by #point_data. + */ + float *radius; + + /** + * The start index of each curve in the point data. The size of each curve can be calculated by + * subtracting the offset from the next offset. That is valid even for the last curve because + * this array is allocated with a length one larger than the number of splines. + * + * \note This is *not* stored in #CustomData because its size is one larger than #curve_data. + */ + int *offsets; + + /** + * All attributes stored on control points (#ATTR_DOMAIN_POINT). + */ + CustomData point_data; + + /** + * All attributes stored on curves (#ATTR_DOMAIN_CURVE). + */ + CustomData curve_data; + + /** + * The total number of control points in all curves. + */ + int point_size; + /** + * The number of curves in the data-block. + */ + int curve_size; +} CurvesGeometry; + +typedef struct Curves { + ID id; + /* Animation data (must be immediately after id). */ + struct AnimData *adt; + + CurvesGeometry geometry; + + int flag; + int attributes_active_index; + + /* Materials. */ + struct Material **mat; + short totcol; + short _pad2[3]; + + /* Draw Cache. */ + void *batch_cache; +} Curves; + +/* Curves.flag */ +enum { + HA_DS_EXPAND = (1 << 0), +}; + +/* Only one material supported currently. */ +#define CURVES_MATERIAL_NR 1 + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 629a5e88de7..9c34d78c944 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -162,8 +162,8 @@ typedef enum CustomDataType { /* CD_LOCATION = 43, */ /* UNUSED */ /* CD_RADIUS = 44, */ /* UNUSED */ - CD_HAIRCURVE = 45, - CD_HAIRMAPPING = 46, + CD_PROP_INT8 = 45, + /* CD_HAIRMAPPING = 46, */ /* UNUSED, can be reused. */ CD_PROP_COLOR = 47, CD_PROP_FLOAT3 = 48, @@ -223,6 +223,7 @@ typedef enum CustomDataType { #define CD_MASK_PROP_FLOAT3 (1ULL << CD_PROP_FLOAT3) #define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2) #define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL) +#define CD_MASK_PROP_INT8 (1ULL << CD_PROP_INT8) #define CD_MASK_HAIRLENGTH (1ULL << CD_HAIRLENGTH) @@ -235,7 +236,8 @@ typedef enum CustomDataType { /* All generic attributes. */ #define CD_MASK_PROP_ALL \ (CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \ - CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL | CD_MASK_PROP_BOOL) + CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL | CD_MASK_PROP_BOOL | \ + CD_MASK_PROP_INT8) typedef struct CustomData_MeshMasks { uint64_t vmask; diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 0f570f8603d..3340782d64a 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -35,6 +35,7 @@ struct AnimData; struct Curve; struct Curve; struct MDeformVert; +struct GPencilUpdateCache; #define GP_DEFAULT_PIX_FACTOR 1.0f #define GP_DEFAULT_GRID_LINES 4 @@ -325,6 +326,8 @@ typedef struct bGPDstroke { /** Curve used to edit the stroke using Bezier handlers. */ struct bGPDcurve *editcurve; + /* NOTE: When adding new members, make sure to add them to BKE_gpencil_stroke_copy_settings as well! */ + bGPDstroke_Runtime runtime; void *_pad5; } bGPDstroke; @@ -409,6 +412,8 @@ typedef struct bGPDframe { /** Keyframe type (eBezTriple_KeyframeType). */ short key_type; + /* NOTE: When adding new members, make sure to add them to BKE_gpencil_frame_copy_settings as well! */ + bGPDframe_Runtime runtime; } bGPDframe; @@ -532,6 +537,8 @@ typedef struct bGPDlayer { float layer_mat[4][4], layer_invmat[4][4]; char _pad3[4]; + /* NOTE: When adding new members, make sure to add them to BKE_gpencil_layer_copy_settings as well! */ + bGPDlayer_Runtime runtime; } bGPDlayer; @@ -633,6 +640,8 @@ typedef struct bGPdata_Runtime { Brush *sbuffer_brush; struct GpencilBatchCache *gpencil_cache; struct LineartCache *lineart_cache; + + struct GPencilUpdateCache *update_cache; } bGPdata_Runtime; /* grid configuration */ @@ -726,6 +735,8 @@ typedef struct bGPdata { bGPgrid grid; + /* NOTE: When adding new members, make sure to add them to BKE_gpencil_data_copy_settings as well! */ + bGPdata_Runtime runtime; } bGPdata; diff --git a/source/blender/makesdna/DNA_hair_types.h b/source/blender/makesdna/DNA_hair_types.h deleted file mode 100644 index 2e819b32033..00000000000 --- a/source/blender/makesdna/DNA_hair_types.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup DNA - */ - -#pragma once - -#include "DNA_ID.h" -#include "DNA_customdata_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct HairCurve { - /* Index of first point of hair curve. */ - int firstpoint; - /* Number of points in hair curve, must be 2 or higher. */ - int numpoints; -} HairCurve; - -/* Hair attachment to a mesh. - * TODO: attach to tessellated triangles or polygons? - * TODO: what type of interpolation to use for uv? */ -typedef struct HairMapping { - float uv[2]; - int poly; -} HairMapping; - -typedef struct Hair { - ID id; - struct AnimData *adt; /* animation data (must be immediately after id) */ - - int flag; - int _pad1[1]; - - /* Geometry */ - float (*co)[3]; - float *radius; - struct HairCurve *curves; - struct HairMaping *mapping; - int totpoint; - int totcurve; - - /* Custom Data */ - struct CustomData pdata; - struct CustomData cdata; - int attributes_active_index; - int _pad3; - - /* Material */ - struct Material **mat; - short totcol; - short _pad2[3]; - - /* Draw Cache */ - void *batch_cache; -} Hair; - -/* Hair.flag */ -enum { - HA_DS_EXPAND = (1 << 0), -}; - -/* Only one material supported currently. */ -#define HAIR_MATERIAL_NR 1 - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 22c523901c0..f2493bd5b85 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -48,7 +48,6 @@ typedef struct MVert { /** #MVert.flag */ enum { /* SELECT = (1 << 0), */ - ME_VERT_TMP_TAG = (1 << 2), ME_HIDE = (1 << 4), ME_VERT_FACEDOT = (1 << 5), /* ME_VERT_MERGED = (1 << 6), */ @@ -266,6 +265,9 @@ typedef struct MStringProperty { typedef struct MBoolProperty { uint8_t b; } MBoolProperty; +typedef struct MInt8Property { + int8_t i; +} MInt8Property; /** \} */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 2bfd2e71eb7..fd77e8b9f1d 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -514,8 +514,10 @@ typedef struct bNodeTree { /** Information about how inputs and outputs of the node group interact with fields. */ FieldInferencingInterfaceHandle *field_inferencing_interface; - /** Set init on fileread. */ - int type, init; + int type; + + char _pad1[4]; + /** * Sockets in groups have unique identifiers, adding new sockets always * will increase this counter. @@ -599,9 +601,6 @@ typedef struct bNodeTree { #define NTREE_TEXTURE 2 #define NTREE_GEOMETRY 3 -/** #NodeTree.init, flag */ -#define NTREE_TYPE_INIT 1 - /** #NodeTree.flag */ #define NTREE_DS_EXPAND (1 << 0) /* for animation editors */ #define NTREE_COM_OPENCL (1 << 1) /* use opencl */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 602f968634e..ca8696d1326 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -263,9 +263,10 @@ typedef struct Object { /** String describing subobject info, MAX_ID_NAME-2. */ char parsubstr[64]; struct Object *parent, *track; - /* If `ob->proxy` (or proxy_group), this object is proxy for object `ob->proxy`. */ - /* proxy_from is set in target back to the proxy. */ - struct Object *proxy, *proxy_group, *proxy_from; + /* Proxy pointer are deprecated, only kept for conversion to liboverrides. */ + struct Object *proxy DNA_DEPRECATED; + struct Object *proxy_group DNA_DEPRECATED; + struct Object *proxy_from DNA_DEPRECATED; /** Old animation system, deprecated for 2.5. */ struct Ipo *ipo DNA_DEPRECATED; /* struct Path *path; */ @@ -504,7 +505,7 @@ enum { /** Grease Pencil object used in 3D view but not used for annotation in 2D. */ OB_GPENCIL = 26, - OB_HAIR = 27, + OB_CURVES = 27, OB_POINTCLOUD = 28, @@ -519,7 +520,15 @@ enum { (((_type) >= OB_MESH && (_type) <= OB_MBALL) || ((_type) >= OB_GPENCIL && (_type) <= OB_VOLUME)) /** Does the object have some render-able geometry (unlike empties, cameras, etc.). */ #define OB_TYPE_IS_GEOMETRY(_type) \ - (ELEM(_type, OB_MESH, OB_SURF, OB_FONT, OB_MBALL, OB_GPENCIL, OB_HAIR, OB_POINTCLOUD, OB_VOLUME)) + (ELEM(_type, \ + OB_MESH, \ + OB_SURF, \ + OB_FONT, \ + OB_MBALL, \ + OB_GPENCIL, \ + OB_CURVES, \ + OB_POINTCLOUD, \ + OB_VOLUME)) #define OB_TYPE_SUPPORT_VGROUP(_type) (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL)) #define OB_TYPE_SUPPORT_EDITMODE(_type) \ (ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)) @@ -541,7 +550,7 @@ enum { ID_LT, \ ID_GD, \ ID_AR, \ - ID_HA, \ + ID_CV, \ ID_PT, \ ID_VO)) @@ -556,7 +565,7 @@ enum { case ID_LT: \ case ID_GD: \ case ID_AR: \ - case ID_HA: \ + case ID_CV: \ case ID_PT: \ case ID_VO diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index a50d0524998..71a5c0eb2e5 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -101,7 +101,7 @@ typedef enum eTreeStoreElemType { TSE_DRIVER_BASE = 16, /* NO ID */ /* TSE_DRIVER = 17, */ /* UNUSED */ - TSE_PROXY = 18, + /* TSE_PROXY = 18, */ /* UNUSED */ TSE_R_LAYER_BASE = 19, TSE_R_LAYER = 20, /* TSE_R_PASS = 21, */ /* UNUSED */ diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 5fe67a34dae..622175a8429 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -73,13 +73,14 @@ typedef struct StripCrop { } StripCrop; typedef struct StripTransform { - int xofs; - int yofs; + float xofs; + float yofs; float scale_x; float scale_y; float rotation; /** 0-1 range, use SEQ_image_transform_origin_offset_pixelspace_get to convert to pixel space. */ float origin[2]; + int filter; } StripTransform; typedef struct StripColorBalance { @@ -788,6 +789,12 @@ typedef enum SequenceColorTag { SEQUENCE_COLOR_TOT, } SequenceColorTag; +/* Sequence->StripTransform->filter */ +enum { + SEQ_TRANSFORM_FILTER_NEAREST = 0, + SEQ_TRANSFORM_FILTER_BILINEAR = 1, +}; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 15bb1ef920d..d1b015485c9 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -651,7 +651,6 @@ typedef struct UserDef_Experimental { /* Debug options, always available. */ char use_undo_legacy; char no_override_auto_resync; - char no_proxy_to_override_conversion; char use_cycles_debug; char use_geometry_nodes_legacy; char show_asset_debug_info; @@ -659,14 +658,14 @@ typedef struct UserDef_Experimental { char SANITIZE_AFTER_HERE; /* The following options are automatically sanitized (set to 0) * when the release cycle is not alpha. */ - char use_new_hair_type; + char use_new_curves_type; char use_new_point_cloud_type; char use_full_frame_compositor; char use_sculpt_vertex_colors; char use_sculpt_tools_tilt; char use_extended_asset_browser; char use_override_templates; - char _pad[1]; + char _pad[2]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; @@ -1253,7 +1252,7 @@ typedef enum eDupli_ID_Flags { USER_DUP_PSYS = (1 << 11), USER_DUP_LIGHTPROBE = (1 << 12), USER_DUP_GPENCIL = (1 << 13), - USER_DUP_HAIR = (1 << 14), + USER_DUP_CURVES = (1 << 14), USER_DUP_POINTCLOUD = (1 << 15), USER_DUP_VOLUME = (1 << 16), USER_DUP_LATTICE = (1 << 17), diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index a3c54e91780..af30fa5cc9e 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -142,7 +142,7 @@ set(SRC ../DNA_defaults.h ../DNA_fluid_defaults.h ../DNA_gpencil_modifier_defaults.h - ../DNA_hair_defaults.h + ../DNA_curves_defaults.h ../DNA_image_defaults.h ../DNA_lattice_defaults.h ../DNA_light_defaults.h diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c index 5bc5de7a20b..93d8051d6c4 100644 --- a/source/blender/makesdna/intern/dna_defaults.c +++ b/source/blender/makesdna/intern/dna_defaults.c @@ -12,8 +12,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * DNA default value access. */ /** \file @@ -94,9 +92,9 @@ #include "DNA_cloth_types.h" #include "DNA_collection_types.h" #include "DNA_curve_types.h" +#include "DNA_curves_types.h" #include "DNA_fluid_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_hair_types.h" #include "DNA_image_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" @@ -127,9 +125,9 @@ #include "DNA_camera_defaults.h" #include "DNA_collection_defaults.h" #include "DNA_curve_defaults.h" +#include "DNA_curves_defaults.h" #include "DNA_fluid_defaults.h" #include "DNA_gpencil_modifier_defaults.h" -#include "DNA_hair_defaults.h" #include "DNA_image_defaults.h" #include "DNA_lattice_defaults.h" #include "DNA_light_defaults.h" @@ -184,8 +182,8 @@ SDNA_DEFAULT_DECL_STRUCT(FluidEffectorSettings); /* DNA_image_defaults.h */ SDNA_DEFAULT_DECL_STRUCT(Image); -/* DNA_hair_defaults.h */ -SDNA_DEFAULT_DECL_STRUCT(Hair); +/* DNA_curves_defaults.h */ +SDNA_DEFAULT_DECL_STRUCT(Curves); /* DNA_lattice_defaults.h */ SDNA_DEFAULT_DECL_STRUCT(Lattice); @@ -392,8 +390,8 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = { /* DNA_image_defaults.h */ SDNA_DEFAULT_DECL(Image), - /* DNA_hair_defaults.h */ - SDNA_DEFAULT_DECL(Hair), + /* DNA_curves_defaults.h */ + SDNA_DEFAULT_DECL(Curves), /* DNA_lattice_defaults.h */ SDNA_DEFAULT_DECL(Lattice), diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 6322cb459dd..634aa91cf95 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -15,11 +15,11 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * DNA handling */ /** \file * \ingroup DNA + * \brief DNA handling * * Lowest-level functions for decoding the parts of a saved .blend * file, including interpretation of its SDNA block and conversion of @@ -733,49 +733,73 @@ static void cast_primitive_type(const eSDNA_Type old_type, const int curlen = DNA_elem_type_size(new_type); double old_value_f = 0.0; + /* Intentionally overflow signed values into an unsigned type. + * Casting back to a signed value preserves the sign (when the new value is signed). */ uint64_t old_value_i = 0; for (int a = 0; a < array_len; a++) { switch (old_type) { - case SDNA_TYPE_CHAR: - old_value_i = *old_data; - old_value_f = (double)old_value_i; + case SDNA_TYPE_CHAR: { + const char value = *old_data; + old_value_i = value; + old_value_f = (double)value; break; - case SDNA_TYPE_UCHAR: - old_value_i = *((unsigned char *)old_data); - old_value_f = (double)old_value_i; + } + case SDNA_TYPE_UCHAR: { + const uchar value = *((uchar *)old_data); + old_value_i = value; + old_value_f = (double)value; break; - case SDNA_TYPE_SHORT: - old_value_i = *((short *)old_data); - old_value_f = (double)old_value_i; + } + case SDNA_TYPE_SHORT: { + const short value = *((short *)old_data); + old_value_i = value; + old_value_f = (double)value; break; - case SDNA_TYPE_USHORT: - old_value_i = *((unsigned short *)old_data); - old_value_f = (double)old_value_i; + } + case SDNA_TYPE_USHORT: { + const ushort value = *((unsigned short *)old_data); + old_value_i = value; + old_value_f = (double)value; break; - case SDNA_TYPE_INT: - old_value_i = *((int *)old_data); - old_value_f = (double)old_value_i; + } + case SDNA_TYPE_INT: { + const int value = *((int *)old_data); + old_value_i = value; + old_value_f = (double)value; break; - case SDNA_TYPE_FLOAT: - old_value_f = *((float *)old_data); - old_value_i = (uint64_t)(int64_t)old_value_f; + } + case SDNA_TYPE_FLOAT: { + const float value = *((float *)old_data); + /* `int64_t` range stored in a `uint64_t`. */ + old_value_i = (uint64_t)(int64_t)value; + old_value_f = value; break; - case SDNA_TYPE_DOUBLE: - old_value_f = *((double *)old_data); - old_value_i = (uint64_t)(int64_t)old_value_f; + } + case SDNA_TYPE_DOUBLE: { + const double value = *((double *)old_data); + /* `int64_t` range stored in a `uint64_t`. */ + old_value_i = (uint64_t)(int64_t)value; + old_value_f = value; break; - case SDNA_TYPE_INT64: - old_value_i = (uint64_t) * ((int64_t *)old_data); - old_value_f = (double)old_value_i; + } + case SDNA_TYPE_INT64: { + const int64_t value = *((int64_t *)old_data); + old_value_i = (uint64_t)value; + old_value_f = (double)value; break; - case SDNA_TYPE_UINT64: - old_value_i = *((uint64_t *)old_data); - old_value_f = (double)old_value_i; + } + case SDNA_TYPE_UINT64: { + const uint64_t value = *((uint64_t *)old_data); + old_value_i = value; + old_value_f = (double)value; break; - case SDNA_TYPE_INT8: - old_value_i = (uint64_t) * ((int8_t *)old_data); - old_value_f = (double)old_value_i; + } + case SDNA_TYPE_INT8: { + const int8_t value = *((int8_t *)old_data); + old_value_i = (uint64_t)value; + old_value_f = (double)value; + } } switch (new_type) { diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index cb8052856a7..b666a5dce56 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * DNA handling */ /** \file diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 114c0b40407..5156203b71f 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -134,7 +134,7 @@ static const char *includefiles[] = { "DNA_lightprobe_types.h", "DNA_curveprofile_types.h", "DNA_xr_types.h", - "DNA_hair_types.h", + "DNA_curves_types.h", "DNA_pointcloud_types.h", "DNA_volume_types.h", "DNA_simulation_types.h", @@ -1555,8 +1555,18 @@ int main(int argc, char **argv) base_directory = BASE_HEADER; } + /* NOTE: #init_structDNA() in dna_genfile.c expects `sdna->data` is 4-bytes aligned. + * `DNAstr[]` buffer written by `makesdna` is used for this data, so make `DNAstr` forcefully + * 4-bytes aligned. */ +#ifdef __GNUC__ +# define FORCE_ALIGN_4 " __attribute__((aligned(4))) " +#else +# define FORCE_ALIGN_4 " " +#endif fprintf(file_dna, "extern const unsigned char DNAstr[];\n"); - fprintf(file_dna, "const unsigned char DNAstr[] = {\n"); + fprintf(file_dna, "const unsigned char" FORCE_ALIGN_4 "DNAstr[] = {\n"); +#undef FORCE_ALIGN_4 + if (make_structDNA(base_directory, file_dna, file_dna_offsets, file_dna_verify)) { /* error */ fclose(file_dna); @@ -1626,6 +1636,7 @@ int main(int argc, char **argv) #include "DNA_constraint_types.h" #include "DNA_curve_types.h" #include "DNA_curveprofile_types.h" +#include "DNA_curves_types.h" #include "DNA_customdata_types.h" #include "DNA_dynamicpaint_types.h" #include "DNA_effect_types.h" @@ -1634,7 +1645,6 @@ int main(int argc, char **argv) #include "DNA_freestyle_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" #include "DNA_image_types.h" #include "DNA_ipo_types.h" #include "DNA_key_types.h" diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 1ade964854d..47afa0f9a13 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -104,6 +104,8 @@ extern StructRNA RNA_BuildGpencilModifier; extern StructRNA RNA_BuildModifier; extern StructRNA RNA_ByteColorAttribute; extern StructRNA RNA_ByteColorAttributeValue; +extern StructRNA RNA_ByteIntAttribute; +extern StructRNA RNA_ByteIntAttributeValue; extern StructRNA RNA_CacheFile; extern StructRNA RNA_CacheFileLayer; extern StructRNA RNA_Camera; @@ -143,6 +145,7 @@ extern StructRNA RNA_CompositorNodeCombHSVA; extern StructRNA RNA_CompositorNodeCombRGBA; extern StructRNA RNA_CompositorNodeCombYCCA; extern StructRNA RNA_CompositorNodeCombYUVA; +extern StructRNA RNA_CompositorNodeCombineXYZ; extern StructRNA RNA_CompositorNodeComposite; extern StructRNA RNA_CompositorNodeCornerPin; extern StructRNA RNA_CompositorNodeCrop; @@ -187,6 +190,7 @@ extern StructRNA RNA_CompositorNodeRLayers; extern StructRNA RNA_CompositorNodeRotate; extern StructRNA RNA_CompositorNodeScale; extern StructRNA RNA_CompositorNodeSceneTime; +extern StructRNA RNA_CompositorNodeSeparateXYZ; extern StructRNA RNA_CompositorNodeSepHSVA; extern StructRNA RNA_CompositorNodeSepRGBA; extern StructRNA RNA_CompositorNodeSepYCCA; @@ -304,7 +308,7 @@ extern StructRNA RNA_GizmoProperties; extern StructRNA RNA_GlowSequence; extern StructRNA RNA_GpencilModifier; extern StructRNA RNA_GreasePencil; -extern StructRNA RNA_Hair; +extern StructRNA RNA_Curves; extern StructRNA RNA_Header; extern StructRNA RNA_Histogram; extern StructRNA RNA_HookGpencilModifier; @@ -1512,10 +1516,21 @@ void RNA_collection_clear(PointerRNA *ptr, const char *name); /** * Check if the #IDproperty exists, for operators. + * + * \param use_ghost: Internally an #IDProperty may exist, + * without the RNA considering it to be "set", see #IDP_FLAG_GHOST. + * This is used for operators, where executing an operator that has run previously + * will re-use the last value (unless #PROP_SKIP_SAVE property is set). + * In this case, the presence of the an existing value shouldn't prevent it being initialized + * from the context. Even though the this value will be returned if it's requested, + * it's not considered to be set (as it would if the menu item or key-map defined it's value). + * Set `use_ghost` to true for default behavior, otherwise false to check if there is a value + * exists internally and would be returned on request. */ bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost); bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop); void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop); +/** See #RNA_property_is_set_ex documentation. */ bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost); bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier); bool RNA_property_is_idprop(const PropertyRNA *prop); diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index c5581c01921..e37eb9f7188 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -322,7 +322,7 @@ typedef enum PropertyFlag { * FREE FLAGS: 2, 3, 4, 5, 6, 7, 8, 9, 12 and above. */ typedef enum PropertyOverrideFlag { - /** Means the property can be overridden by a local 'proxy' of some linked datablock. */ + /** Means that the property can be overridden by a local override of some linked datablock. */ PROPOVERRIDE_OVERRIDABLE_LIBRARY = (1 << 0), /** diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index e3c89af6186..91d7c5a1394 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -101,9 +101,9 @@ set(DEFSRC if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_SIMULATION_DATABLOCK) - add_definitions(-DWITH_HAIR_NODES) + add_definitions(-DWITH_NEW_CURVES_TYPE) list(APPEND DEFSRC - rna_hair.c + rna_curves.c rna_simulation.c ) endif() diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 1e9cebbc3ea..0fadbda5a18 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4376,8 +4376,8 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint}, {"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve}, {"rna_gpencil.c", NULL, RNA_def_gpencil}, -#ifdef WITH_HAIR_NODES - {"rna_hair.c", NULL, RNA_def_hair}, +#ifdef WITH_NEW_CURVES_TYPE + {"rna_curves.c", NULL, RNA_def_curves}, #endif {"rna_image.c", "rna_image_api.c", RNA_def_image}, {"rna_key.c", NULL, RNA_def_key}, diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 1ae036a254e..e7f885b2160 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -76,7 +76,7 @@ const EnumPropertyItem rna_enum_id_type_items[] = { {ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""}, {ID_TXT, "TEXT", ICON_TEXT, "Text", ""}, {ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""}, - {ID_HA, "HAIR", ICON_HAIR_DATA, "Hair", ""}, + {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", ""}, @@ -151,7 +151,7 @@ const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = { ICON_OUTLINER_COLLECTION, "Collections", "Show Collection data-blocks"}, - {FILTER_ID_HA, "filter_hair", ICON_HAIR_DATA, "Hairs", "Show/hide Hair data-blocks"}, + {FILTER_ID_CV, "filter_hair", ICON_CURVES_DATA, "Hairs", "Show/hide Hair data-blocks"}, {FILTER_ID_IM, "filter_image", ICON_IMAGE_DATA, "Images", "Show Image data-blocks"}, {FILTER_ID_LA, "filter_light", ICON_LIGHT_DATA, "Lights", "Show Light data-blocks"}, {FILTER_ID_LP, @@ -385,9 +385,9 @@ short RNA_type_to_ID_code(const StructRNA *type) if (base_type == &RNA_FreestyleLineStyle) { return ID_LS; } -# ifdef WITH_HAIR_NODES - if (base_type == &RNA_Hair) { - return ID_HA; +# ifdef WITH_NEW_CURVES_TYPE + if (base_type == &RNA_Curves) { + return ID_CV; } # endif if (base_type == &RNA_Lattice) { @@ -492,9 +492,9 @@ StructRNA *ID_code_to_RNA_type(short idcode) return &RNA_GreasePencil; case ID_GR: return &RNA_Collection; - case ID_HA: -# ifdef WITH_HAIR_NODES - return &RNA_Hair; + case ID_CV: +# ifdef WITH_NEW_CURVES_TYPE + return &RNA_Curves; # else return &RNA_ID; # endif @@ -719,7 +719,8 @@ static ID *rna_ID_override_hierarchy_create( BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); ID *id_root_override = NULL; - BKE_lib_override_library_create(bmain, scene, view_layer, id, id_reference, &id_root_override); + BKE_lib_override_library_create( + bmain, scene, view_layer, NULL, id, id_reference, &id_root_override); WM_main_add_notifier(NC_ID | NA_ADDED, NULL); WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); @@ -948,9 +949,9 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) } } -static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool clear_proxy) +static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool UNUSED(clear_proxy)) { - BKE_lib_id_make_local(bmain, self, clear_proxy ? 0 : LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); + BKE_lib_id_make_local(bmain, self, 0); ID *ret_id = self->newid ? self->newid : self; BKE_id_newptr_and_tag_clear(self); @@ -1821,6 +1822,13 @@ static void rna_def_ID_override_library(BlenderRNA *brna) srna, "reference", "ID", "Reference ID", "Linked ID used as reference by this override"); RNA_def_property_update(prop, NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + RNA_def_pointer( + srna, + "hierarchy_root", + "ID", + "Hierarchy Root ID", + "Library override ID used as root of the override hierarchy this ID is a member of"); + prop = RNA_def_boolean(srna, "is_in_hierarchy", true, @@ -2088,13 +2096,7 @@ static void rna_def_ID(BlenderRNA *brna) "Make this datablock local, return local one " "(may be a copy of the original, in case it is also indirectly used)"); RNA_def_function_flag(func, FUNC_USE_MAIN); - parm = RNA_def_boolean( - func, - "clear_proxy", - true, - "", - "Whether to clear proxies (the default behavior, " - "note that if object has to be duplicated to be made local, proxies are always cleared)"); + parm = RNA_def_boolean(func, "clear_proxy", true, "", "Deprecated, has no effect"); parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 6b134977c5a..f4236a860ab 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -625,11 +625,11 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_FILE, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - prop = RNA_def_property(srna, "show_hairs", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "show_hair_curves", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag2", ADS_FILTER_NOHAIR); RNA_def_property_ui_text( prop, "Display Hair", "Include visualization of hair related animation data"); - RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_HAIR, 0); + RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_CURVES, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); prop = RNA_def_property(srna, "show_pointclouds", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 28e50e80f32..b22d3654431 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -151,18 +151,9 @@ static void rna_Armature_edit_bone_remove(bArmature *arm, RNA_POINTER_INVALIDATE(ebone_ptr); } -static void rna_Armature_update_layers(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Armature_update_layers(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { bArmature *arm = (bArmature *)ptr->owner_id; - Object *ob; - - /* proxy lib exception, store it here so we can restore layers on file - * load, since it would otherwise get lost due to being linked data */ - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->data == arm && ob->pose) { - ob->pose->proxy_layer = arm->layer; - } - } DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); WM_main_add_notifier(NC_GEOM | ND_DATA, arm); diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index e79cbc838d4..e80c8559020 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -237,7 +237,7 @@ static void rna_AssetMetaData_catalog_id_set(PointerRNA *ptr, const char *value) } if (!BLI_uuid_parse_string(&new_uuid, value)) { - // TODO(Sybren): raise ValueError exception once that's possible from an RNA setter. + /* TODO(@sybren): raise ValueError exception once that's possible from an RNA setter. */ printf("UUID %s not formatted correctly, ignoring new value\n", value); return; } diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 35da353a043..dc0d00aaa77 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -26,8 +26,8 @@ #include "rna_internal.h" +#include "DNA_curves_types.h" #include "DNA_customdata_types.h" -#include "DNA_hair_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_pointcloud_types.h" @@ -46,6 +46,7 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = { {CD_PROP_STRING, "STRING", 0, "String", "Text string"}, {CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"}, {CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"}, + {CD_PROP_INT8, "INT8", 0, "8-Bit Integer", "Smaller integer with a range from -128 to 127"}, {0, NULL, 0, NULL, NULL}, }; @@ -59,6 +60,7 @@ const EnumPropertyItem rna_enum_attribute_type_with_auto_items[] = { {CD_PROP_STRING, "STRING", 0, "String", "Text string"}, {CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"}, {CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"}, + {CD_PROP_INT8, "INT8", 0, "8-Bit Integer", "Smaller integer with a range from -128 to 127"}, {0, NULL, 0, NULL, NULL}, }; @@ -133,6 +135,8 @@ static StructRNA *srna_by_custom_data_layer_type(const CustomDataType type) return &RNA_BoolAttribute; case CD_PROP_FLOAT2: return &RNA_Float2Attribute; + case CD_PROP_INT8: + return &RNA_ByteIntAttribute; default: return NULL; } @@ -184,7 +188,7 @@ const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, if (id_type == ID_PT && !ELEM(domain_item->value, ATTR_DOMAIN_POINT)) { continue; } - if (id_type == ID_HA && !ELEM(domain_item->value, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) { + if (id_type == ID_CV && !ELEM(domain_item->value, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) { continue; } if (id_type == ID_ME && ELEM(domain_item->value, ATTR_DOMAIN_CURVE)) { @@ -253,6 +257,9 @@ static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRN case CD_PROP_FLOAT2: struct_size = sizeof(float[2]); break; + case CD_PROP_INT8: + struct_size = sizeof(int8_t); + break; default: struct_size = 0; length = 0; @@ -294,6 +301,28 @@ static void rna_ByteColorAttributeValue_color_set(PointerRNA *ptr, const float * linearrgb_to_srgb_uchar4(&mlcol->r, values); } +/* Int8 Attribute. */ + +static int rna_ByteIntAttributeValue_get(PointerRNA *ptr) +{ + int8_t *value = (int8_t *)ptr->data; + return (int)(*value); +} + +static void rna_ByteIntAttributeValue_set(PointerRNA *ptr, const int new_value) +{ + int8_t *value = (int8_t *)ptr->data; + if (new_value > INT8_MAX) { + *value = INT8_MAX; + } + else if (new_value < INT8_MIN) { + *value = INT8_MIN; + } + else { + *value = (int8_t)new_value; + } +} + /* Attribute Group */ static PointerRNA rna_AttributeGroup_new( @@ -648,6 +677,36 @@ static void rna_def_attribute_bool(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "b", 0x01); } +static void rna_def_attribute_int8(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ByteIntAttribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text(srna, "8-bit Int Attribute", "8-bit int geometry attribute"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "ByteIntAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + srna = RNA_def_struct(brna, "ByteIntAttributeValue", NULL); + RNA_def_struct_sdna(srna, "MInt8Property"); + RNA_def_struct_ui_text( + srna, "8-bit Integer Attribute Value", "8-bit value in geometry attribute"); + prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs( + prop, "rna_ByteIntAttributeValue_get", "rna_ByteIntAttributeValue_set", NULL); +} + static void rna_def_attribute_float2(BlenderRNA *brna) { StructRNA *srna; @@ -723,6 +782,7 @@ static void rna_def_attribute(BlenderRNA *brna) rna_def_attribute_string(brna); rna_def_attribute_bool(brna); rna_def_attribute_float2(brna); + rna_def_attribute_int8(brna); } /* Mesh/PointCloud/Hair.attributes */ diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 0c993660f39..e3a06c44eee 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -3543,14 +3543,6 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_ACTIVE); RNA_def_property_ui_text(prop, "Active", "Constraint is the one being edited"); - prop = RNA_def_property(srna, "is_proxy_local", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_PROXY_LOCAL); - RNA_def_property_ui_text( - prop, - "Proxy Local", - "Constraint was added in this proxy instance (i.e. did not belong to source Armature)"); - /* values */ prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "enforce"); diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c new file mode 100644 index 00000000000..faa067000bb --- /dev/null +++ b/source/blender/makesrna/intern/rna_curves.c @@ -0,0 +1,296 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup RNA + */ + +#include <stdlib.h> + +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "rna_internal.h" + +#include "DNA_curves_types.h" + +#include "BLI_math_base.h" +#include "BLI_string.h" + +#ifdef RNA_RUNTIME + +# include "BLI_math_vector.h" + +# include "BKE_attribute.h" +# include "BKE_curves.h" + +# include "DEG_depsgraph.h" + +# include "WM_api.h" +# include "WM_types.h" + +static Curves *rna_curves(PointerRNA *ptr) +{ + return (Curves *)ptr->owner_id; +} + +static int rna_Curves_curve_offset_data_length(PointerRNA *ptr) +{ + const Curves *curves = rna_curves(ptr); + return curves->geometry.curve_size + 1; +} + +static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + const Curves *curves = rna_curves(ptr); + rna_iterator_array_begin(iter, + (void *)curves->geometry.offsets, + sizeof(int), + curves->geometry.curve_size + 1, + false, + NULL); +} + +static int rna_CurvePoint_index_get(PointerRNA *ptr) +{ + const Curves *curves = rna_curves(ptr); + const float(*co)[3] = ptr->data; + return (int)(co - curves->geometry.position); +} + +static void rna_CurvePoint_location_get(PointerRNA *ptr, float value[3]) +{ + copy_v3_v3(value, (const float *)ptr->data); +} + +static void rna_CurvePoint_location_set(PointerRNA *ptr, const float value[3]) +{ + copy_v3_v3((float *)ptr->data, value); +} + +static float rna_CurvePoint_radius_get(PointerRNA *ptr) +{ + const Curves *curves = rna_curves(ptr); + if (curves->geometry.radius == NULL) { + return 0.0f; + } + const float(*co)[3] = ptr->data; + return curves->geometry.radius[co - curves->geometry.position]; +} + +static void rna_CurvePoint_radius_set(PointerRNA *ptr, float value) +{ + const Curves *curves = rna_curves(ptr); + if (curves->geometry.radius == NULL) { + return; + } + const float(*co)[3] = ptr->data; + curves->geometry.radius[co - curves->geometry.position] = value; +} + +static char *rna_CurvePoint_path(PointerRNA *ptr) +{ + return BLI_sprintfN("points[%d]", rna_CurvePoint_index_get(ptr)); +} + +static int rna_CurveSlice_index_get(PointerRNA *ptr) +{ + Curves *curves = rna_curves(ptr); + return (int)((int *)ptr->data - curves->geometry.offsets); +} + +static char *rna_CurveSlice_path(PointerRNA *ptr) +{ + return BLI_sprintfN("curves[%d]", rna_CurveSlice_index_get(ptr)); +} + +static void rna_CurveSlice_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Curves *curves = rna_curves(ptr); + const int *offset_ptr = (int *)ptr->data; + const int offset = *offset_ptr; + const int size = *(offset_ptr + 1) - offset; + float(*co)[3] = curves->geometry.position + *offset_ptr; + rna_iterator_array_begin(iter, co, sizeof(float[3]), size, 0, NULL); +} + +static int rna_CurveSlice_first_point_index_get(PointerRNA *ptr) +{ + const int *offset_ptr = (int *)ptr->data; + return *offset_ptr; +} + +static int rna_CurveSlice_points_length_get(PointerRNA *ptr) +{ + const int *offset_ptr = (int *)ptr->data; + const int offset = *offset_ptr; + return *(offset_ptr + 1) - offset; +} + +static void rna_Curves_update_data(struct Main *UNUSED(bmain), + struct Scene *UNUSED(scene), + PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + + /* cheating way for importers to avoid slow updates */ + if (id->us > 0) { + DEG_id_tag_update(id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, id); + } +} + +#else + +static void rna_def_curves_point(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CurvePoint", NULL); + RNA_def_struct_ui_text(srna, "Curve Point", "Curve curve control point"); + RNA_def_struct_path_func(srna, "rna_CurvePoint_path"); + + prop = RNA_def_property(srna, "position", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_array(prop, 3); + RNA_def_property_float_funcs( + prop, "rna_CurvePoint_location_get", "rna_CurvePoint_location_set", NULL); + RNA_def_property_ui_text(prop, "Position", ""); + RNA_def_property_update(prop, 0, "rna_Curves_update_data"); + + prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_funcs( + prop, "rna_CurvePoint_radius_get", "rna_CurvePoint_radius_set", NULL); + RNA_def_property_ui_text(prop, "Radius", ""); + RNA_def_property_update(prop, 0, "rna_Curves_update_data"); + + prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_funcs(prop, "rna_CurvePoint_index_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Index", "Index of this points"); +} + +static void rna_def_curves_curve(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CurveSlice", NULL); + RNA_def_struct_ui_text(srna, "Curve Slice", "A single curve from a curves data-block"); + RNA_def_struct_path_func(srna, "rna_CurveSlice_path"); + + prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "CurvePoint"); + RNA_def_property_ui_text(prop, "Points", "Control points of the curve"); + RNA_def_property_collection_funcs(prop, + "rna_CurveSlice_points_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_CurveSlice_points_length_get", + NULL, + NULL, + NULL); + + prop = RNA_def_property(srna, "first_point_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_funcs(prop, "rna_CurveSlice_first_point_index_get", NULL, NULL); + RNA_def_property_ui_text( + prop, "First Point Index", "The index of this curve's first control point"); + + prop = RNA_def_property(srna, "points_length", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_funcs(prop, "rna_CurveSlice_points_length_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Number of Points", "Number of control points in the curve"); + + prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_funcs(prop, "rna_CurveSlice_index_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Index", "Index of this curve"); +} + +static void rna_def_curves(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "Curves", "ID"); + RNA_def_struct_ui_text(srna, "Hair Curves", "Hair data-block for hair curves"); + RNA_def_struct_ui_icon(srna, ICON_CURVES_DATA); + + /* Point and Curve RNA API helpers. */ + + prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "geometry.offsets", "geometry.curve_size"); + RNA_def_property_struct_type(prop, "CurveSlice"); + RNA_def_property_ui_text(prop, "Curves", "All curves in the data-block"); + + /* TODO: better solution for (*co)[3] parsing issue. */ + + RNA_define_verify_sdna(0); + prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_size"); + RNA_def_property_struct_type(prop, "CurvePoint"); + RNA_def_property_ui_text(prop, "Points", "Control points of all curves"); + RNA_define_verify_sdna(1); + + /* Direct access to built-in attributes. */ + + RNA_define_verify_sdna(0); + prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_size"); + RNA_def_property_struct_type(prop, "FloatVectorAttributeValue"); + RNA_def_property_update(prop, 0, "rna_Curves_update_data"); + RNA_define_verify_sdna(1); + + prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "geometry.offsets", NULL); + RNA_def_property_struct_type(prop, "IntAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Curves_curve_offset_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Curves_curve_offset_data_length", + NULL, + NULL, + NULL); + RNA_def_property_update(prop, 0, "rna_Curves_update_data"); + + /* materials */ + prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol"); + RNA_def_property_struct_type(prop, "Material"); + RNA_def_property_ui_text(prop, "Materials", ""); + RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */ + RNA_def_property_collection_funcs( + prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); + + /* attributes */ + rna_def_attributes_common(srna); + + /* common */ + rna_def_animdata_common(srna); +} + +void RNA_def_curves(BlenderRNA *brna) +{ + rna_def_curves_point(brna); + rna_def_curves_curve(brna); + rna_def_curves(brna); +} + +#endif diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 3f380cd1830..ff194e2c52a 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -172,6 +172,7 @@ static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { # include "BKE_gpencil.h" # include "BKE_gpencil_curve.h" # include "BKE_gpencil_geom.h" +# include "BKE_gpencil_update_cache.h" # include "BKE_icons.h" # include "DEG_depsgraph.h" @@ -179,6 +180,12 @@ static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { +#if 0 + /* In case a property on a layer changed, tag it with a light update. */ + if (ptr->type == &RNA_GPencilLayer) { + BKE_gpencil_tag_light_update((bGPdata *)(ptr->owner_id), (bGPDlayer *)(ptr->data), NULL, NULL); + } +#endif DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } @@ -2228,7 +2235,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) prop = RNA_def_property(srna, "use_solo_mode", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SOLO_MODE); RNA_def_property_ui_text( - prop, "Solo Mode", "In Paint mode display only layers with keyframe in current frame"); + prop, "Solo Mode", "In Draw Mode only display layers with keyframe in current frame"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Layer is used as Ruler. */ diff --git a/source/blender/makesrna/intern/rna_hair.c b/source/blender/makesrna/intern/rna_hair.c deleted file mode 100644 index 4ca66c6b583..00000000000 --- a/source/blender/makesrna/intern/rna_hair.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup RNA - */ - -#include <stdlib.h> - -#include "RNA_define.h" -#include "RNA_enum_types.h" - -#include "rna_internal.h" - -#include "DNA_hair_types.h" - -#include "BLI_math_base.h" -#include "BLI_string.h" - -#ifdef RNA_RUNTIME - -# include "BLI_math_vector.h" - -# include "BKE_attribute.h" -# include "BKE_hair.h" - -# include "DEG_depsgraph.h" - -# include "WM_api.h" -# include "WM_types.h" - -static Hair *rna_hair(PointerRNA *ptr) -{ - return (Hair *)ptr->owner_id; -} - -static int rna_HairPoint_index_get(PointerRNA *ptr) -{ - const Hair *hair = rna_hair(ptr); - const float(*co)[3] = ptr->data; - return (int)(co - hair->co); -} - -static void rna_HairPoint_location_get(PointerRNA *ptr, float value[3]) -{ - copy_v3_v3(value, (const float *)ptr->data); -} - -static void rna_HairPoint_location_set(PointerRNA *ptr, const float value[3]) -{ - copy_v3_v3((float *)ptr->data, value); -} - -static float rna_HairPoint_radius_get(PointerRNA *ptr) -{ - const Hair *hair = rna_hair(ptr); - if (hair->radius == NULL) { - return 0.0f; - } - const float(*co)[3] = ptr->data; - return hair->radius[co - hair->co]; -} - -static void rna_HairPoint_radius_set(PointerRNA *ptr, float value) -{ - const Hair *hair = rna_hair(ptr); - if (hair->radius == NULL) { - return; - } - const float(*co)[3] = ptr->data; - hair->radius[co - hair->co] = value; -} - -static char *rna_HairPoint_path(PointerRNA *ptr) -{ - return BLI_sprintfN("points[%d]", rna_HairPoint_index_get(ptr)); -} - -static int rna_HairCurve_index_get(PointerRNA *ptr) -{ - Hair *hair = rna_hair(ptr); - return (int)((HairCurve *)ptr->data - hair->curves); -} - -static char *rna_HairCurve_path(PointerRNA *ptr) -{ - return BLI_sprintfN("curves[%d]", rna_HairCurve_index_get(ptr)); -} - -static void rna_HairCurve_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) -{ - Hair *hair = rna_hair(ptr); - HairCurve *curve = ptr->data; - float(*co)[3] = hair->co + curve->firstpoint; - rna_iterator_array_begin(iter, co, sizeof(float[3]), curve->numpoints, 0, NULL); -} - -static int rna_HairCurve_points_length(PointerRNA *ptr) -{ - HairCurve *curve = ptr->data; - return curve->numpoints; -} - -static void rna_Hair_update_data(struct Main *UNUSED(bmain), - struct Scene *UNUSED(scene), - PointerRNA *ptr) -{ - ID *id = ptr->owner_id; - - /* cheating way for importers to avoid slow updates */ - if (id->us > 0) { - DEG_id_tag_update(id, 0); - WM_main_add_notifier(NC_GEOM | ND_DATA, id); - } -} - -#else - -static void rna_def_hair_point(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "HairPoint", NULL); - RNA_def_struct_ui_text(srna, "Hair Point", "Hair curve control point"); - RNA_def_struct_path_func(srna, "rna_HairPoint_path"); - - prop = RNA_def_property(srna, "co", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_array(prop, 3); - RNA_def_property_float_funcs( - prop, "rna_HairPoint_location_get", "rna_HairPoint_location_set", NULL); - RNA_def_property_ui_text(prop, "Location", ""); - RNA_def_property_update(prop, 0, "rna_Hair_update_data"); - - prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_float_funcs(prop, "rna_HairPoint_radius_get", "rna_HairPoint_radius_set", NULL); - RNA_def_property_ui_text(prop, "Radius", ""); - RNA_def_property_update(prop, 0, "rna_Hair_update_data"); - - prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_int_funcs(prop, "rna_HairPoint_index_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Index", "Index of this points"); -} - -static void rna_def_hair_curve(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "HairCurve", NULL); - RNA_def_struct_ui_text(srna, "Hair Curve", "Hair curve"); - RNA_def_struct_path_func(srna, "rna_HairCurve_path"); - - prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "HairPoint"); - RNA_def_property_ui_text(prop, "Points", "Control points of the curve"); - RNA_def_property_collection_funcs(prop, - "rna_HairCurve_points_begin", - "rna_iterator_array_next", - "rna_iterator_array_end", - "rna_iterator_array_get", - "rna_HairCurve_points_length", - NULL, - NULL, - NULL); - - /* TODO: naming consistency, editable? */ - prop = RNA_def_property(srna, "first_point_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "firstpoint"); - RNA_def_property_ui_text(prop, "First Point Index", "Index of the first loop of this polygon"); - - prop = RNA_def_property(srna, "num_points", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "numpoints"); - RNA_def_property_ui_text(prop, "Number of Points", "Number of loops used by this polygon"); - - prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_int_funcs(prop, "rna_HairCurve_index_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Index", "Index of this curve"); -} - -static void rna_def_hair(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "Hair", "ID"); - RNA_def_struct_ui_text(srna, "Hair", "Hair data-block for hair curves"); - RNA_def_struct_ui_icon(srna, ICON_HAIR_DATA); - - /* geometry */ - prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "curves", "totcurve"); - RNA_def_property_struct_type(prop, "HairCurve"); - RNA_def_property_ui_text(prop, "Curves", "All hair curves"); - - /* TODO: better solution for (*co)[3] parsing issue. */ - RNA_define_verify_sdna(0); - prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "co", "totpoint"); - RNA_def_property_struct_type(prop, "HairPoint"); - RNA_def_property_ui_text(prop, "Points", "Control points of all hair curves"); - RNA_define_verify_sdna(1); - - /* materials */ - prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol"); - RNA_def_property_struct_type(prop, "Material"); - RNA_def_property_ui_text(prop, "Materials", ""); - RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */ - RNA_def_property_collection_funcs( - prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); - - /* attributes */ - rna_def_attributes_common(srna); - - /* common */ - rna_def_animdata_common(srna); -} - -void RNA_def_hair(BlenderRNA *brna) -{ - rna_def_hair_point(brna); - rna_def_hair_curve(brna); - rna_def_hair(brna); -} - -#endif diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 0d86572357f..af13baad5a2 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -1107,7 +1107,7 @@ static void rna_def_image(BlenderRNA *brna) prop, "Duration", "Duration (in frames) of the image (1 when not a video/sequence)"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - /* NOTE about pixels/channels/is_float: + /* NOTE: About pixels/channels/is_float: * These properties describe how the image is stored internally (inside of ImBuf), * not how it was saved to disk or how it'll be saved on disk. */ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index d4de20b5328..407f474ddab 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -170,7 +170,7 @@ void RNA_def_fcurve(struct BlenderRNA *brna); void RNA_def_gpencil(struct BlenderRNA *brna); void RNA_def_greasepencil_modifier(struct BlenderRNA *brna); void RNA_def_shader_fx(struct BlenderRNA *brna); -void RNA_def_hair(struct BlenderRNA *brna); +void RNA_def_curves(struct BlenderRNA *brna); void RNA_def_image(struct BlenderRNA *brna); void RNA_def_key(struct BlenderRNA *brna); void RNA_def_light(struct BlenderRNA *brna); @@ -369,9 +369,10 @@ void rna_ViewLayer_active_aov_index_range( PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax); int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr); void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value); -/** Set `r_rna_path` with the base viewlayer path. +/** + * Set `r_rna_path` with the base view-layer path. * `rna_path_buffer_size` should be at least `sizeof(ViewLayer.name) * 3`. - * \return actual length of the generayted RNA path. + * \return actual length of the generated RNA path. */ size_t rna_ViewLayer_path_buffer_get(struct ViewLayer *view_layer, char *r_rna_path, @@ -495,8 +496,8 @@ void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop); void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop); void RNA_def_main_workspaces(BlenderRNA *brna, PropertyRNA *cprop); void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop); -#ifdef WITH_HAIR_NODES -void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop); +#ifdef WITH_NEW_CURVES_TYPE +void RNA_def_main_hair_curves(BlenderRNA *brna, PropertyRNA *cprop); #endif void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop); void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop); diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index 57a2a867d0a..230c04bfd9c 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -110,8 +110,8 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(collections) RNA_MAIN_LISTBASE_FUNCS_DEF(curves) RNA_MAIN_LISTBASE_FUNCS_DEF(fonts) RNA_MAIN_LISTBASE_FUNCS_DEF(gpencils) -# ifdef WITH_HAIR_NODES -RNA_MAIN_LISTBASE_FUNCS_DEF(hairs) +# ifdef WITH_NEW_CURVES_TYPE +RNA_MAIN_LISTBASE_FUNCS_DEF(hair_curves) # endif RNA_MAIN_LISTBASE_FUNCS_DEF(images) RNA_MAIN_LISTBASE_FUNCS_DEF(lattices) @@ -389,8 +389,17 @@ void RNA_def_main(BlenderRNA *brna) "Light Probes", "Light Probe data-blocks", RNA_def_main_lightprobes}, -# ifdef WITH_HAIR_NODES - {"hairs", "Hair", "rna_Main_hairs_begin", "Hairs", "Hair data-blocks", RNA_def_main_hairs}, +# ifdef WITH_NEW_CURVES_TYPE + /** + * \note The name `hair_curves` is chosen to be different than `curves`, + * but they are generic curve data-blocks, not just for hair. + */ + {"hair_curves", + "Curves", + "rna_Main_hair_curves_begin", + "Hair Curves", + "Hair curve data-blocks", + RNA_def_main_hair_curves}, # endif {"pointclouds", "PointCloud", diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 4344ed0dff5..f8d2d6524c2 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -46,9 +46,9 @@ # include "BKE_camera.h" # include "BKE_collection.h" # include "BKE_curve.h" +# include "BKE_curves.h" # include "BKE_displist.h" # include "BKE_gpencil.h" -# include "BKE_hair.h" # include "BKE_icons.h" # include "BKE_idtype.h" # include "BKE_image.h" @@ -86,8 +86,8 @@ # include "DNA_camera_types.h" # include "DNA_collection_types.h" # include "DNA_curve_types.h" +# include "DNA_curves_types.h" # include "DNA_gpencil_types.h" -# include "DNA_hair_types.h" # include "DNA_lattice_types.h" # include "DNA_light_types.h" # include "DNA_lightprobe_types.h" @@ -763,18 +763,18 @@ static bGPdata *rna_Main_gpencils_new(Main *bmain, const char *name) return gpd; } -# ifdef WITH_HAIR_NODES -static Hair *rna_Main_hairs_new(Main *bmain, const char *name) +# ifdef WITH_NEW_CURVES_TYPE +static Curves *rna_Main_hair_curves_new(Main *bmain, const char *name) { char safe_name[MAX_ID_NAME - 2]; rna_idname_validate(name, safe_name); - Hair *hair = BKE_hair_add(bmain, safe_name); - id_us_min(&hair->id); + Curves *curves = BKE_curves_add(bmain, safe_name); + id_us_min(&curves->id); WM_main_add_notifier(NC_ID | NA_ADDED, NULL); - return hair; + return curves; } # endif @@ -861,8 +861,8 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(cachefiles, cachefiles, ID_CF) RNA_MAIN_ID_TAG_FUNCS_DEF(paintcurves, paintcurves, ID_PC) RNA_MAIN_ID_TAG_FUNCS_DEF(workspaces, workspaces, ID_WS) RNA_MAIN_ID_TAG_FUNCS_DEF(lightprobes, lightprobes, ID_LP) -# ifdef WITH_HAIR_NODES -RNA_MAIN_ID_TAG_FUNCS_DEF(hairs, hairs, ID_HA) +# ifdef WITH_NEW_CURVES_TYPE +RNA_MAIN_ID_TAG_FUNCS_DEF(hair_curves, hair_curves, ID_CV) # endif RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT) RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO) @@ -2269,47 +2269,47 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } -# ifdef WITH_HAIR_NODES -void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop) +# ifdef WITH_NEW_CURVES_TYPE +void RNA_def_main_hair_curves(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; FunctionRNA *func; PropertyRNA *parm; - RNA_def_property_srna(cprop, "BlendDataHairs"); - srna = RNA_def_struct(brna, "BlendDataHairs", NULL); + RNA_def_property_srna(cprop, "BlendDataHairCurves"); + srna = RNA_def_struct(brna, "BlendDataHairCurves", NULL); RNA_def_struct_sdna(srna, "Main"); - RNA_def_struct_ui_text(srna, "Main Hairs", "Collection of hairs"); + RNA_def_struct_ui_text(srna, "Main Hair Curves", "Collection of hair curves"); - func = RNA_def_function(srna, "new", "rna_Main_hairs_new"); + func = RNA_def_function(srna, "new", "rna_Main_hair_curves_new"); RNA_def_function_ui_description(func, "Add a new hair to the main database"); - parm = RNA_def_string(func, "name", "Hair", 0, "", "New name for the data-block"); + parm = RNA_def_string(func, "name", "Curves", 0, "", "New name for the data-block"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ - parm = RNA_def_pointer(func, "hair", "Hair", "", "New hair data-block"); + parm = RNA_def_pointer(func, "curves", "Curves", "", "New curves data-block"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - RNA_def_function_ui_description(func, "Remove a hair from the current blendfile"); - parm = RNA_def_pointer(func, "hair", "Hair", "", "Hair to remove"); + RNA_def_function_ui_description(func, "Remove a curves data-block from the current blendfile"); + parm = RNA_def_pointer(func, "curves", "Curves", "", "Curves data-block to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", - "Unlink all usages of this hair before deleting it " - "(WARNING: will also delete objects instancing that hair data)"); + "Unlink all usages of this curves before deleting it " + "(WARNING: will also delete objects instancing that curves data)"); RNA_def_boolean(func, "do_id_user", true, "", - "Decrement user counter of all datablocks used by this hair data"); + "Decrement user counter of all datablocks used by this curves data"); RNA_def_boolean( - func, "do_ui_user", true, "", "Make sure interface does not reference this hair data"); + func, "do_ui_user", true, "", "Make sure interface does not reference this curves data"); - func = RNA_def_function(srna, "tag", "rna_Main_hairs_tag"); + func = RNA_def_function(srna, "tag", "rna_Main_hair_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 8c6d51b1bfa..6dea0dbbf7d 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -718,7 +718,7 @@ void RNA_def_material(BlenderRNA *brna) {MA_FLAT, "FLAT", ICON_MATPLANE, "Flat", "Flat XY plane"}, {MA_SPHERE, "SPHERE", ICON_MATSPHERE, "Sphere", "Sphere"}, {MA_CUBE, "CUBE", ICON_MATCUBE, "Cube", "Cube"}, - {MA_HAIR, "HAIR", ICON_HAIR, "Hair", "Hair strands"}, + {MA_HAIR, "HAIR", ICON_CURVES, "Hair", "Hair strands"}, {MA_SHADERBALL, "SHADERBALL", ICON_MATSHADERBALL, "Shader Ball", "Shader ball"}, {MA_CLOTH, "CLOTH", ICON_MATCLOTH, "Cloth", "Cloth"}, {MA_FLUID, "FLUID", ICON_MATFLUID, "Fluid", "Fluid"}, diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 38a447a9657..bd74f86c79a 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -465,7 +465,8 @@ static const EnumPropertyItem rna_enum_node_tex_dimensions_items[] = { const EnumPropertyItem rna_enum_node_filter_items[] = { {0, "SOFTEN", 0, "Soften", ""}, - {1, "SHARPEN", 0, "Sharpen", ""}, + {1, "SHARPEN", 0, "Box Sharpen", "An aggressive sharpening filter"}, + {7, "SHARPEN_DIAMOND", 0, "Diamond Sharpen", "A moderate sharpening filter"}, {2, "LAPLACE", 0, "Laplace", ""}, {3, "SOBEL", 0, "Sobel", ""}, {4, "PREWITT", 0, "Prewitt", ""}, @@ -10524,7 +10525,7 @@ static void def_geo_object_info(StructRNA *srna) RNA_def_property_enum_items(prop, rna_node_geometry_object_info_transform_space_items); RNA_def_property_ui_text( prop, "Transform Space", "The transformation of the vector and geometry outputs"); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations"); } static void def_geo_legacy_points_to_volume(StructRNA *srna) @@ -10608,7 +10609,7 @@ static void def_geo_collection_info(StructRNA *srna) prop = RNA_def_property(srna, "transform_space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_collection_info_transform_space_items); RNA_def_property_ui_text(prop, "Transform Space", "The transformation of the geometry output"); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations"); } static void def_geo_legacy_attribute_proximity(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a098693459b..be37e574c9c 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -271,7 +271,7 @@ const EnumPropertyItem rna_enum_object_type_items[] = { OBTYPE_CU_SURF, {OB_MBALL, "META", ICON_OUTLINER_OB_META, "Metaball", ""}, OBTYPE_CU_FONT, - {OB_HAIR, "HAIR", ICON_OUTLINER_OB_HAIR, "Hair", ""}, + {OB_CURVES, "CURVES", ICON_OUTLINER_OB_CURVES, "Hair Curves", ""}, {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", ""}, @@ -613,9 +613,9 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr) return &RNA_LightProbe; case OB_GPENCIL: return &RNA_GreasePencil; - case OB_HAIR: -# ifdef WITH_HAIR_NODES - return &RNA_Hair; + case OB_CURVES: +# ifdef WITH_NEW_CURVES_TYPE + return &RNA_Curves; # else return &RNA_ID; # endif @@ -3150,19 +3150,6 @@ static void rna_def_object(BlenderRNA *brna) "Align to Vertex Normal is enabled)"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update"); - /* proxy */ - prop = RNA_def_property(srna, "proxy", PROP_POINTER, PROP_NONE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); - RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_ui_text(prop, "Proxy", "Library object this proxy object controls"); - - prop = RNA_def_property(srna, "proxy_collection", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "proxy_group"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); - RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_ui_text( - prop, "Proxy Collection", "Library collection duplicator object this proxy object controls"); - /* materials */ prop = RNA_def_property(srna, "material_slots", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "MaterialSlot"); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 23ec5148f00..df6c12ffb27 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -12,8 +12,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * Adaptive time step - * Copyright 2011 AutoCRC + * + * Copyright 2011 AutoCRC (adaptive time step) */ /** \file diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 76bfea00a79..7714e4d1e59 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -140,7 +140,7 @@ static char *rna_PoseBone_path(PointerRNA *ptr) static bool rna_bone_group_poll(Object *ob, ReportList *reports) { - if ((ob->proxy != NULL) || (ob->proxy_group != NULL) || ID_IS_OVERRIDE_LIBRARY(ob)) { + if (ID_IS_OVERRIDE_LIBRARY(ob)) { BKE_report(reports, RPT_ERROR, "Cannot edit bone groups for proxies or library overrides"); return false; } @@ -717,7 +717,7 @@ static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info) bArmature *arm = ob->data; bPoseChannel *pchan = (bPoseChannel *)ptr->data; - if (ob->proxy && pchan->bone && (pchan->bone->layer & arm->layer_protected)) { + if (false && pchan->bone && (pchan->bone->layer & arm->layer_protected)) { *r_info = "Can't edit property of a proxy on a protected layer"; return 0; } diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 6c3e3ab3058..15b3a2fe998 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1456,6 +1456,12 @@ static void rna_def_strip_crop(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_SequenceCrop_path"); } +static const EnumPropertyItem transform_filter_items[] = { + {SEQ_TRANSFORM_FILTER_NEAREST, "NEAREST", 0, "Nearest", ""}, + {SEQ_TRANSFORM_FILTER_BILINEAR, "BILINEAR", 0, "Bilinear", ""}, + {0, NULL, 0, NULL, NULL}, +}; + static void rna_def_strip_transform(BlenderRNA *brna) { StructRNA *srna; @@ -1479,16 +1485,16 @@ static void rna_def_strip_transform(BlenderRNA *brna) RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); - prop = RNA_def_property(srna, "offset_x", PROP_INT, PROP_PIXEL); - RNA_def_property_int_sdna(prop, NULL, "xofs"); + prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_PIXEL); + RNA_def_property_float_sdna(prop, NULL, "xofs"); RNA_def_property_ui_text(prop, "Translate X", "Move along X axis"); - RNA_def_property_ui_range(prop, INT_MIN, INT_MAX, 1, 6); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 100, 3); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); - prop = RNA_def_property(srna, "offset_y", PROP_INT, PROP_PIXEL); - RNA_def_property_int_sdna(prop, NULL, "yofs"); + prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_PIXEL); + RNA_def_property_float_sdna(prop, NULL, "yofs"); RNA_def_property_ui_text(prop, "Translate Y", "Move along Y axis"); - RNA_def_property_ui_range(prop, INT_MIN, INT_MAX, 1, 6); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 100, 3); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE); @@ -1502,6 +1508,13 @@ static void rna_def_strip_transform(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0, 1, 1, 3); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); + prop = RNA_def_property(srna, "filter", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "filter"); + RNA_def_property_enum_items(prop, transform_filter_items); + RNA_def_property_enum_default(prop, SEQ_TRANSFORM_FILTER_BILINEAR); + RNA_def_property_ui_text(prop, "Filter", "Type of filter to use for image transformation"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); + RNA_def_struct_path_func(srna, "rna_SequenceTransform_path"); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 9a3c40bf306..07521d39256 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3277,7 +3277,7 @@ static struct IDFilterEnumPropertyItem rna_enum_space_file_id_filter_categories[ ICON_OUTLINER_COLLECTION, "Objects & Collections", "Show objects and collections"}, - {FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME | FILTER_ID_HA | + {FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO, "category_geometry", ICON_NODETREE, @@ -5004,7 +5004,7 @@ static void rna_def_space_view3d(BlenderRNA *brna) {"Surface", (1 << OB_SURF), {"show_object_viewport_surf", "show_object_select_surf"}}, {"Meta", (1 << OB_MBALL), {"show_object_viewport_meta", "show_object_select_meta"}}, {"Font", (1 << OB_FONT), {"show_object_viewport_font", "show_object_select_font"}}, - {"Hair", (1 << OB_HAIR), {"show_object_viewport_hair", "show_object_select_hair"}}, + {"Hair", (1 << OB_CURVES), {"show_object_viewport_hair", "show_object_select_hair"}}, {"Point Cloud", (1 << OB_POINTCLOUD), {"show_object_viewport_pointcloud", "show_object_select_pointcloud"}}, diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 4379b4ebe1d..53af3f5bed5 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5293,7 +5293,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop, "Duplicate GPencil", "Causes grease pencil data to be duplicated with the object"); prop = RNA_def_property(srna, "use_duplicate_hair", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_HAIR); + RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_CURVES); RNA_def_property_ui_text( prop, "Duplicate Hair", "Causes hair data to be duplicated with the object"); @@ -6386,13 +6386,6 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "Enable library overrides automatic resync detection and process on file load. Disable when " "dealing with older .blend files that need manual Resync (Enforce) handling"); - prop = RNA_def_property(srna, "proxy_to_override_auto_conversion", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "no_proxy_to_override_conversion", 1); - RNA_def_property_ui_text( - prop, - "Proxy to Override Auto Conversion", - "Enable automatic conversion of proxies to library overrides on file load"); - prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1); RNA_def_property_ui_text( @@ -6406,9 +6399,9 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "reduces execution time and memory usage)"); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "use_new_hair_type", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "use_new_hair_type", 1); - RNA_def_property_ui_text(prop, "New Hair Type", "Enable the new hair type in the ui"); + prop = RNA_def_property(srna, "use_new_curves_type", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_new_curves_type", 1); + RNA_def_property_ui_text(prop, "New Curves Type", "Enable the new curves data type in the UI"); prop = RNA_def_property(srna, "use_cycles_debug", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_cycles_debug", 1); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index c64a47fc2ab..178a50c4d29 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -2175,7 +2175,8 @@ static void rna_def_event(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Mouse Previous Y Position", "The window relative vertical location of the mouse"); - prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_default(prop, 1.0f); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_funcs(prop, "rna_Event_pressure_get", NULL, NULL); RNA_def_property_ui_text( diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index bb933ba97a5..719a07adbab 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -183,10 +183,6 @@ if(WITH_BULLET) add_definitions(-DWITH_BULLET) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - # To disable adaptive subdivision test in subsurf UI without cycles if(WITH_CYCLES) add_definitions(-DWITH_CYCLES) @@ -236,7 +232,7 @@ endif() if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_SIMULATION_DATABLOCK) - add_definitions(-DWITH_HAIR_NODES) + add_definitions(-DWITH_NEW_CURVES_TYPE) endif() # So we can have special tricks in modifier system. diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 828b8b79664..a86a667974e 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -296,7 +296,6 @@ ModifierTypeInfo modifierType_Armature = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ deformMatricesEM, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 56db68b163c..c2b1478c1b2 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -1037,7 +1037,6 @@ ModifierTypeInfo modifierType_Array = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index add95a0d248..984e85f58ef 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -446,7 +446,6 @@ ModifierTypeInfo modifierType_Bevel = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, /* requiredDataMask */ requiredDataMask, diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index bb05ae3e1b3..7b084d608fb 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -641,7 +641,6 @@ ModifierTypeInfo modifierType_Boolean = { /* deformVertsEM */ nullptr, /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyHair */ nullptr, /* modifyGeometrySet */ nullptr, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index 86f0df1418b..867c1e9b5bb 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -345,7 +345,6 @@ ModifierTypeInfo modifierType_Build = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 715bc26e5d3..defc7df31dc 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -589,7 +589,6 @@ ModifierTypeInfo modifierType_Cast = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 8aff29dc17d..4b8928009fe 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -308,7 +308,6 @@ ModifierTypeInfo modifierType_Cloth = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 02e1f61b824..658a569627b 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -317,7 +317,6 @@ ModifierTypeInfo modifierType_Collision = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index dd62e354de8..d75c2a13587 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -850,7 +850,6 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 20dbb299767..b01b70000b8 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -234,7 +234,6 @@ ModifierTypeInfo modifierType_Curve = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 34bb93cbbbc..a289b9c918a 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -484,7 +484,6 @@ ModifierTypeInfo modifierType_DataTransfer = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 975f80a04f8..ad5391d2b6c 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -298,7 +298,6 @@ ModifierTypeInfo modifierType_Decimate = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index c81e6cafa39..94cdcad3b6a 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -508,7 +508,6 @@ ModifierTypeInfo modifierType_Displace = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index a696ce216c7..676433b14b1 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -221,7 +221,6 @@ ModifierTypeInfo modifierType_DynamicPaint = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 1039bcb2b3b..55707435e52 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -185,7 +185,6 @@ ModifierTypeInfo modifierType_EdgeSplit = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 68d6b4a3626..c788633f978 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -1255,7 +1255,6 @@ ModifierTypeInfo modifierType_Explode = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c index a21eb603300..748633b78b3 100644 --- a/source/blender/modifiers/intern/MOD_fluid.c +++ b/source/blender/modifiers/intern/MOD_fluid.c @@ -273,7 +273,6 @@ ModifierTypeInfo modifierType_Fluid = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 18ce37c5d85..b4c081906ba 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -572,7 +572,6 @@ ModifierTypeInfo modifierType_Hook = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index 6efeec1970f..090973f12c0 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -887,7 +887,6 @@ ModifierTypeInfo modifierType_LaplacianDeform = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index a36a8c386b4..8cc34d43d82 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -633,7 +633,6 @@ ModifierTypeInfo modifierType_LaplacianSmooth = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ init_data, diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index 29d1ecf6050..709b617d3ec 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -191,7 +191,6 @@ ModifierTypeInfo modifierType_Lattice = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index 0de8b26a1b7..097f7241205 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -837,7 +837,6 @@ ModifierTypeInfo modifierType_Mask = { /* deformVertsEM */ nullptr, /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyHair */ nullptr, /* modifyGeometrySet */ nullptr, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc index 910b52dea67..a8e1c91dd20 100644 --- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc +++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc @@ -308,7 +308,6 @@ ModifierTypeInfo modifierType_MeshToVolume = { /* deformVertsEM */ nullptr, /* deformMatricesEM */ nullptr, /* modifyMesh */ nullptr, - /* modifyHair */ nullptr, /* modifyGeometrySet */ modifyGeometrySet, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index 74f9887a973..48ff4f7d6af 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -446,7 +446,6 @@ ModifierTypeInfo modifierType_MeshCache = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index bfca5a39e8d..5c6bcb4ba24 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -642,7 +642,6 @@ ModifierTypeInfo modifierType_MeshDeform = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index b5dd0566215..8bde0cab3dc 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -456,7 +456,6 @@ ModifierTypeInfo modifierType_MeshSequenceCache = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 1bdc97f0a8b..721906a6a01 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -238,7 +238,6 @@ ModifierTypeInfo modifierType_Mirror = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index c3b34f3cd23..205839774d8 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -518,7 +518,6 @@ ModifierTypeInfo modifierType_Multires = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index c5ee4b9fb52..f16fc8ff764 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -141,56 +141,85 @@ static void initData(ModifierData *md) MEMCPY_STRUCT_AFTER(nmd, DNA_struct_default_get(NodesModifierData), modifier); } -static void addIdsUsedBySocket(const ListBase *sockets, Set<ID *> &ids) +static void add_used_ids_from_sockets(const ListBase &sockets, Set<ID *> &ids) { - LISTBASE_FOREACH (const bNodeSocket *, socket, sockets) { - if (socket->type == SOCK_OBJECT) { - Object *object = ((bNodeSocketValueObject *)socket->default_value)->value; - if (object != nullptr) { - ids.add(&object->id); + LISTBASE_FOREACH (const bNodeSocket *, socket, &sockets) { + switch (socket->type) { + case SOCK_OBJECT: { + if (Object *object = ((bNodeSocketValueObject *)socket->default_value)->value) { + ids.add(&object->id); + } + break; } - } - else if (socket->type == SOCK_COLLECTION) { - Collection *collection = ((bNodeSocketValueCollection *)socket->default_value)->value; - if (collection != nullptr) { - ids.add(&collection->id); + case SOCK_COLLECTION: { + if (Collection *collection = + ((bNodeSocketValueCollection *)socket->default_value)->value) { + ids.add(&collection->id); + } + break; } - } - else if (socket->type == SOCK_MATERIAL) { - Material *material = ((bNodeSocketValueMaterial *)socket->default_value)->value; - if (material != nullptr) { - ids.add(&material->id); + case SOCK_MATERIAL: { + if (Material *material = ((bNodeSocketValueMaterial *)socket->default_value)->value) { + ids.add(&material->id); + } + break; } - } - else if (socket->type == SOCK_TEXTURE) { - Tex *texture = ((bNodeSocketValueTexture *)socket->default_value)->value; - if (texture != nullptr) { - ids.add(&texture->id); + case SOCK_TEXTURE: { + if (Tex *texture = ((bNodeSocketValueTexture *)socket->default_value)->value) { + ids.add(&texture->id); + } + break; } - } - else if (socket->type == SOCK_IMAGE) { - Image *image = ((bNodeSocketValueImage *)socket->default_value)->value; - if (image != nullptr) { - ids.add(&image->id); + case SOCK_IMAGE: { + if (Image *image = ((bNodeSocketValueImage *)socket->default_value)->value) { + ids.add(&image->id); + } + break; } } } } -static void find_used_ids_from_nodes(const bNodeTree &tree, Set<ID *> &ids) +/** + * \note We can only check properties here that cause the dependency graph to update relations when + * they are changed, otherwise there may be a missing relation after editing. So this could check + * more properties like whether the node is muted, but we would have to accept the cost of updating + * relations when those properties are changed. + */ +static bool node_needs_own_transform_relation(const bNode &node) +{ + if (node.type == GEO_NODE_COLLECTION_INFO) { + const NodeGeometryCollectionInfo &storage = *static_cast<const NodeGeometryCollectionInfo *>( + node.storage); + return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE; + } + + if (node.type == GEO_NODE_OBJECT_INFO) { + const NodeGeometryObjectInfo &storage = *static_cast<const NodeGeometryObjectInfo *>( + node.storage); + return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE; + } + + return false; +} + +static void process_nodes_for_depsgraph(const bNodeTree &tree, + Set<ID *> &ids, + bool &needs_own_transform_relation) { Set<const bNodeTree *> handled_groups; LISTBASE_FOREACH (const bNode *, node, &tree.nodes) { - addIdsUsedBySocket(&node->inputs, ids); - addIdsUsedBySocket(&node->outputs, ids); + add_used_ids_from_sockets(node->inputs, ids); + add_used_ids_from_sockets(node->outputs, ids); if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { const bNodeTree *group = (bNodeTree *)node->id; if (group != nullptr && handled_groups.add(group)) { - find_used_ids_from_nodes(*group, ids); + process_nodes_for_depsgraph(*group, ids, needs_own_transform_relation); } } + needs_own_transform_relation |= node_needs_own_transform_relation(*node); } } @@ -240,37 +269,43 @@ static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Objec static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md); - DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier"); - if (nmd->node_group != nullptr) { - DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier"); - - Set<ID *> used_ids; - find_used_ids_from_settings(nmd->settings, used_ids); - find_used_ids_from_nodes(*nmd->node_group, used_ids); - for (ID *id : used_ids) { - switch ((ID_Type)GS(id->name)) { - case ID_OB: { - Object *object = reinterpret_cast<Object *>(id); - add_object_relation(ctx, *object); - break; - } - case ID_GR: { - Collection *collection = reinterpret_cast<Collection *>(id); - add_collection_relation(ctx, *collection); - break; - } - case ID_IM: - case ID_TE: { - DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier"); - } - default: { - /* Purposefully don't add relations for materials. While there are material sockets, - * the pointers are only passed around as handles rather than dereferenced. */ - break; - } + if (nmd->node_group == nullptr) { + return; + } + + DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier"); + + bool needs_own_transform_relation = false; + Set<ID *> used_ids; + find_used_ids_from_settings(nmd->settings, used_ids); + process_nodes_for_depsgraph(*nmd->node_group, used_ids, needs_own_transform_relation); + for (ID *id : used_ids) { + switch ((ID_Type)GS(id->name)) { + case ID_OB: { + Object *object = reinterpret_cast<Object *>(id); + add_object_relation(ctx, *object); + break; + } + case ID_GR: { + Collection *collection = reinterpret_cast<Collection *>(id); + add_collection_relation(ctx, *collection); + break; + } + case ID_IM: + case ID_TE: { + DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier"); + } + default: { + /* Purposefully don't add relations for materials. While there are material sockets, + * the pointers are only passed around as handles rather than dereferenced. */ + break; } } } + + if (needs_own_transform_relation) { + DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier"); + } } static bool check_tree_for_time_node(const bNodeTree &tree, @@ -1691,7 +1726,6 @@ ModifierTypeInfo modifierType_Nodes = { /* deformVertsEM */ nullptr, /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyHair */ nullptr, /* modifyGeometrySet */ modifyGeometrySet, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 5362d86a87f..f59af9074ce 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -1347,7 +1347,7 @@ class GeometryNodesEvaluator { } input_state.usage = ValueUsage::Unused; - /* If the input is unused, it's value can be destructed now. */ + /* If the input is unused, its value can be destructed now. */ this->destruct_input_value_if_exists(locked_node, socket); if (input_state.was_ready_for_execution) { diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c index a01f63be791..cce3434f6e3 100644 --- a/source/blender/modifiers/intern/MOD_none.c +++ b/source/blender/modifiers/intern/MOD_none.c @@ -58,7 +58,6 @@ ModifierTypeInfo modifierType_None = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ NULL, diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 61099fedf46..8b58b575d24 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -336,8 +336,6 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, if (do_polynors_fix && polygons_check_flip( mloop, nos, &mesh->ldata, mpoly, BKE_mesh_poly_normals_for_write(mesh), num_polys)) { - /* XXX TODO: is this still needed? */ - // mesh->dirty |= DM_DIRTY_TESS_CDLAYERS; /* We need to recompute vertex normals! */ BKE_mesh_normals_tag_dirty(mesh); } @@ -788,7 +786,6 @@ ModifierTypeInfo modifierType_NormalEdit = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index d821caf25a7..0c00f807df3 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -741,7 +741,6 @@ ModifierTypeInfo modifierType_Ocean = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index 4fffa7c93f3..67a492d4154 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -677,7 +677,6 @@ ModifierTypeInfo modifierType_ParticleInstance = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 2a4cc1c2747..6fb60fffcf4 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -334,7 +334,6 @@ ModifierTypeInfo modifierType_ParticleSystem = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index 937a73fddd9..67f83b17f3f 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -299,7 +299,6 @@ ModifierTypeInfo modifierType_Remesh = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index f5db3bced7a..33c62197dbd 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -27,6 +27,7 @@ #include "BLI_utildefines.h" #include "BLI_alloca.h" +#include "BLI_bitmap.h" #include "BLI_math.h" #include "BLT_translation.h" @@ -134,6 +135,8 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result, const float axis_offset[3], const float merge_threshold) { + BLI_bitmap *vert_tag = BLI_BITMAP_NEW(totvert, __func__); + const float merge_threshold_sq = square_f(merge_threshold); const bool use_offset = axis_offset != NULL; uint tot_doubles = 0; @@ -150,13 +153,10 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result, } const float dist_sq = len_squared_v3v3(axis_co, mvert_new[i].co); if (dist_sq <= merge_threshold_sq) { - mvert_new[i].flag |= ME_VERT_TMP_TAG; + BLI_BITMAP_ENABLE(vert_tag, i); tot_doubles += 1; copy_v3_v3(mvert_new[i].co, axis_co); } - else { - mvert_new[i].flag &= ~ME_VERT_TMP_TAG & 0xFF; - } } if (tot_doubles != 0) { @@ -166,7 +166,7 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result, uint tot_doubles_left = tot_doubles; for (uint i = 0; i < totvert; i += 1) { - if (mvert_new[i].flag & ME_VERT_TMP_TAG) { + if (BLI_BITMAP_TEST(vert_tag, i)) { int *doubles_map = &full_doubles_map[totvert + i]; for (uint step = 1; step < step_tot; step += 1) { *doubles_map = (int)i; @@ -184,6 +184,9 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result, MESH_MERGE_VERTS_DUMP_IF_MAPPED); MEM_freeN(full_doubles_map); } + + MEM_freeN(vert_tag); + return result; } @@ -439,6 +442,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * mv_new = mvert_new; mv_orig = mvert_orig; + BLI_bitmap *vert_tag = BLI_BITMAP_NEW(totvert, __func__); + /* Copy the first set of edges */ med_orig = medge_orig; med_new = medge_new; @@ -447,10 +452,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * med_new->v2 = med_orig->v2; med_new->crease = med_orig->crease; med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; - /* Tag mvert as not loose. - * NOTE: ME_VERT_TMP_TAG is given to be cleared by BKE_mesh_new_nomain_from_template. */ - mvert_new[med_orig->v1].flag |= ME_VERT_TMP_TAG; - mvert_new[med_orig->v2].flag |= ME_VERT_TMP_TAG; + + /* Tag mvert as not loose. */ + BLI_BITMAP_ENABLE(vert_tag, med_orig->v1); + BLI_BITMAP_ENABLE(vert_tag, med_orig->v1); } /* build polygon -> edge map */ @@ -910,7 +915,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * med_new->v1 = varray_stride + j; med_new->v2 = med_new->v1 - totvert; med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; - if ((mv_new_base->flag & ME_VERT_TMP_TAG) == 0) { + if (!BLI_BITMAP_TEST(vert_tag, j)) { med_new->flag |= ME_LOOSEEDGE; } med_new++; @@ -931,7 +936,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * med_new->v1 = i; med_new->v2 = varray_stride + i; med_new->flag = ME_EDGEDRAW | ME_EDGERENDER; - if ((mvert_new[i].flag & ME_VERT_TMP_TAG) == 0) { + if (!BLI_BITMAP_TEST(vert_tag, i)) { med_new->flag |= ME_LOOSEEDGE; } med_new++; @@ -1119,6 +1124,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } #endif + MEM_freeN(vert_tag); + if (edge_poly_map) { MEM_freeN(edge_poly_map); } @@ -1257,7 +1264,6 @@ ModifierTypeInfo modifierType_Screw = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c index b517bc102f8..8c5299a965d 100644 --- a/source/blender/modifiers/intern/MOD_shapekey.c +++ b/source/blender/modifiers/intern/MOD_shapekey.c @@ -139,7 +139,6 @@ ModifierTypeInfo modifierType_ShapeKey = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ deformMatricesEM, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ NULL, diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index a12724ec23c..4d10df91331 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -291,7 +291,6 @@ ModifierTypeInfo modifierType_Shrinkwrap = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 39ebc415021..25c3acb0c4f 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -596,7 +596,6 @@ ModifierTypeInfo modifierType_SimpleDeform = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 07ce819e91c..d1cb120132d 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -2101,7 +2101,6 @@ ModifierTypeInfo modifierType_Skin = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index 97027e2ecff..3228a72d958 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -284,7 +284,6 @@ ModifierTypeInfo modifierType_Smooth = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index 46e960e10d4..f0178a817dc 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -120,7 +120,6 @@ ModifierTypeInfo modifierType_Softbody = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ NULL, diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 736dd08a713..09933fef7ff 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -274,7 +274,6 @@ ModifierTypeInfo modifierType_Solidify = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index a8c6687193b..65ad298cff1 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -500,7 +500,6 @@ ModifierTypeInfo modifierType_Subsurf = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index c8be2bd2829..a54af766b2f 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -245,7 +245,6 @@ ModifierTypeInfo modifierType_Surface = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index fd5a87571fc..70a05002a4f 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1715,7 +1715,6 @@ ModifierTypeInfo modifierType_SurfaceDeform = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index b713df05b80..d4fcebb3216 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -170,7 +170,6 @@ ModifierTypeInfo modifierType_Triangulate = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 238952fde00..5721834c032 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -383,7 +383,6 @@ ModifierTypeInfo modifierType_UVProject = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index 3f161d339c2..552cf1d5d3b 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -233,9 +233,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * settings.use_threading = (numPolys > 1000); BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, &settings); - /* XXX TODO: is this still needed? */ - // me_eval->dirty |= DM_DIRTY_TESS_CDLAYERS; - mesh->runtime.is_original = false; return mesh; @@ -340,7 +337,6 @@ ModifierTypeInfo modifierType_UVWarp = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index af3a502162d..2b9ee97ea09 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -339,7 +339,6 @@ ModifierTypeInfo modifierType_VolumeDisplace = { /* deformVertsEM */ nullptr, /* deformMatricesEM */ nullptr, /* modifyMesh */ nullptr, - /* modifyHair */ nullptr, /* modifyGeometrySet */ modifyGeometrySet, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc index 72358844838..9557abf0a8a 100644 --- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc +++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc @@ -221,7 +221,6 @@ ModifierTypeInfo modifierType_VolumeToMesh = { /* deformVertsEM */ nullptr, /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyHair */ nullptr, /* modifyGeometrySet */ nullptr, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 25e33b22bde..777ae4d9b10 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -539,7 +539,6 @@ ModifierTypeInfo modifierType_Warp = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index b7ab5dac388..5a56ec1d9e5 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -494,7 +494,6 @@ ModifierTypeInfo modifierType_Wave = { /* deformVertsEM */ deformVertsEM, /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index bfe389eb080..21e6ed46908 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -757,7 +757,6 @@ ModifierTypeInfo modifierType_WeightedNormal = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index a9d01c64ff1..6e4f8be8c50 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -428,7 +428,6 @@ ModifierTypeInfo modifierType_WeightVGEdit = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index b369b82ebb7..1b2608afa12 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -514,7 +514,6 @@ ModifierTypeInfo modifierType_WeightVGMix = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 7ee19e1c537..27242b32432 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -767,7 +767,6 @@ ModifierTypeInfo modifierType_WeightVGProximity = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weld.cc b/source/blender/modifiers/intern/MOD_weld.cc index 64871acabea..e9d98429ff2 100644 --- a/source/blender/modifiers/intern/MOD_weld.cc +++ b/source/blender/modifiers/intern/MOD_weld.cc @@ -218,7 +218,6 @@ ModifierTypeInfo modifierType_Weld = { /* deformVertsEM */ nullptr, /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyHair */ nullptr, /* modifyGeometrySet */ nullptr, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 706960182cf..72bc4336eff 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -194,7 +194,6 @@ ModifierTypeInfo modifierType_Wireframe = { /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, /* modifyGeometrySet */ NULL, /* initData */ initData, diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 402a71af27f..43fb90a52cd 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -133,10 +133,6 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_TBB) list(APPEND INC_SYS ${TBB_INCLUDE_DIRS} diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 82faccc2c2d..71acc738472 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -140,6 +140,8 @@ void register_node_type_cmp_pixelate(void); void register_node_type_cmp_trackpos(void); void register_node_type_cmp_planetrackdeform(void); void register_node_type_cmp_cornerpin(void); +void register_node_type_cmp_separate_xyz(void); +void register_node_type_cmp_combine_xyz(void); void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node); void node_cmp_rlayers_register_pass(struct bNodeTree *ntree, diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 8cbde6adcad..8fd71a978e3 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -230,6 +230,8 @@ DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIAL DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" ) DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" ) DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" ) +DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" ) +DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt index 8d2b2befd1a..8581ab7f82f 100644 --- a/source/blender/nodes/composite/CMakeLists.txt +++ b/source/blender/nodes/composite/CMakeLists.txt @@ -110,6 +110,7 @@ set(SRC nodes/node_composite_sepcomb_rgba.cc nodes/node_composite_sepcomb_ycca.cc nodes/node_composite_sepcomb_yuva.cc + nodes/node_composite_sepcomb_xyz.cc nodes/node_composite_setalpha.cc nodes/node_composite_split_viewer.cc nodes/node_composite_stabilize2d.cc @@ -133,10 +134,6 @@ set(SRC node_composite_util.hh ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_IMAGE_OPENEXR) add_definitions(-DWITH_OPENEXR) endif() diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc index fcc04a85b38..d889130c2fa 100644 --- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc +++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2017 Blender Foundation. * All rights reserved. - * - * The Original Code is: all of this file. */ /** \file diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc index dd0a6db74c1..96dbf0def4a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_blur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Juho Vepsäläinen */ /** \file diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc index 282328b5e10..b7ab28f3465 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Juho Vepsäläinen */ /** \file diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc index d5f7279398e..a3fa940460b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.cc +++ b/source/blender/nodes/composite/nodes/node_composite_common.cc @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Juho Vepsäläinen */ /** \file diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc index d407bcbde63..8b9ccfe47e0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc +++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc @@ -15,8 +15,6 @@ * * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. - * - * The Original Code is: all of this file. */ /** \file diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc new file mode 100644 index 00000000000..5dfcf5dca1e --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup cmpnodes + */ + +#include "node_composite_util.hh" + +/* **************** SEPARATE XYZ ******************** */ +namespace blender::nodes { + +static void cmp_node_separate_xyz_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f); + b.add_output<decl::Float>("X"); + b.add_output<decl::Float>("Y"); + b.add_output<decl::Float>("Z"); +} + +} // namespace blender::nodes + +void register_node_type_cmp_separate_xyz() +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_SEPARATE_XYZ, "Separate XYZ", NODE_CLASS_CONVERTER); + ntype.declare = blender::nodes::cmp_node_separate_xyz_declare; + + nodeRegisterType(&ntype); +} + +/* **************** COMBINE XYZ ******************** */ + +namespace blender::nodes { + +static void cmp_node_combine_xyz_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>("X").min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>("Y").min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>("Z").min(-10000.0f).max(10000.0f); + b.add_output<decl::Vector>("Vector"); +} + +} // namespace blender::nodes + +void register_node_type_cmp_combine_xyz() +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_COMBINE_XYZ, "Combine XYZ", NODE_CLASS_CONVERTER); + ntype.declare = blender::nodes::cmp_node_combine_xyz_declare; + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.cc b/source/blender/nodes/composite/nodes/node_composite_switchview.cc index 678d7fe1a9b..606eaa8ed99 100644 --- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc +++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Dalai Felinto */ /** \file diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt index 0c3c6a34995..6418c525776 100644 --- a/source/blender/nodes/function/CMakeLists.txt +++ b/source/blender/nodes/function/CMakeLists.txt @@ -63,10 +63,6 @@ set(LIB bf_functions ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_nodes_function "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_UNITY_BUILD) diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index b4add633b0c..2a8faf65a6d 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -239,10 +239,6 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_TBB) list(APPEND INC_SYS ${TBB_INCLUDE_DIRS} diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index e78c4d7bc35..ab1afeb39f4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -67,7 +67,7 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh, BM_elem_flag_set(BM_face_at_index(bm, i_face), BM_ELEM_TAG, true); } - BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, true, NULL, NULL, NULL); + BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, true, nullptr, nullptr, nullptr); Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, &mesh); BM_mesh_free(bm); BKE_mesh_normals_tag_dirty(result); diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index c8eb0b8d570..598b0c81b51 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -158,10 +158,6 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.cc b/source/blender/nodes/shader/nodes/node_shader_bump.cc index 252abd02ad7..690eacf30ff 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc @@ -60,6 +60,17 @@ static int gpu_shader_bump(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { + /* If there is no Height input, the node becomes a no-op. */ + if (!in[2].link) { + if (!in[5].link) { + return GPU_link(mat, "world_normals_get", &out[0].link); + } + else { + /* Actually running the bump code would normalize, but Cycles handles it as total no-op. */ + return GPU_link(mat, "vector_copy", in[5].link, &out[0].link); + } + } + if (!in[5].link) { GPU_link(mat, "world_normals_get", &in[5].link); } diff --git a/source/blender/nodes/shader/nodes/node_shader_common.cc b/source/blender/nodes/shader/nodes/node_shader_common.cc index 3f0fff34533..f7a17f0722c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.cc +++ b/source/blender/nodes/shader/nodes/node_shader_common.cc @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Juho Vepsäläinen */ /** \file 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 bc7ca661a77..254ab9f866d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -66,6 +66,16 @@ 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); + if (data_type == CD_PROP_FLOAT3) { + return NODE_CLASS_OP_VECTOR; + } + return NODE_CLASS_CONVERTER; +} + static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { const NodeMapRange &storage = node_storage(*node); @@ -665,6 +675,7 @@ void register_node_type_sh_map_range() sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER); ntype.declare = file_ns::sh_node_map_range_declare; ntype.draw_buttons = file_ns::node_shader_buts_map_range; + ntype.ui_class = file_ns::node_shader_map_range_ui_class; node_type_init(&ntype, file_ns::node_shader_init_map_range); node_type_storage( &ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt index 053b17e4e57..e595343b7d2 100644 --- a/source/blender/nodes/texture/CMakeLists.txt +++ b/source/blender/nodes/texture/CMakeLists.txt @@ -82,8 +82,5 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() blender_add_lib(bf_nodes_texture "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index d68cfe78b44..9bd16a318c9 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -15,7 +15,6 @@ * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. - * Juho Vepsäläinen */ /** \file diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index faa668df775..cbbf2a3cb43 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -12,8 +12,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Chris Keith, Chris Want, Ken Hughes, Campbell Barton */ /** \file diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 2e684faf61b..11e3ad0bcf4 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -94,7 +94,7 @@ static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_d } if (cb_flag & IDWALK_CB_LOOPBACK) { - /* We skip loop-back pointers like Object.proxy_from or Key.from here, + /* We skip loop-back pointers like Key.from here, * since it's some internal pointer which is not relevant info for py/API level. */ return IDWALK_RET_NOP; } diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index a7c1b12982c..a49fc21d7ff 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -95,9 +95,5 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib_nolist(bf_render "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index c1392b24023..6374b70ae1f 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -31,6 +31,7 @@ struct Image; struct ImageFormatData; struct Main; struct Object; +struct ImBuf; struct RenderData; struct RenderResult; struct ReportList; @@ -209,7 +210,7 @@ void RE_FreeAllPersistentData(void); /** * Free persistent render data, optionally only for the given scene. */ -void RE_FreePersistentData(const Scene *scene); +void RE_FreePersistentData(const struct Scene *scene); /** * Get results and statistics. diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h index c6ccc547ff4..4d58d866e9f 100644 --- a/source/blender/render/RE_texture.h +++ b/source/blender/render/RE_texture.h @@ -103,7 +103,7 @@ void RE_point_density_fix_linking(void); typedef struct TexResult { float tin; float trgba[4]; - /* Is acually a bool true->use alpha, false->set alpha to 1.0. */ + /* Is actually a boolean: When true -> use alpha, false -> set alpha to 1.0. */ int talpha; float *nor; } TexResult; diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index 5cf328a3a73..9468e4c5b0f 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -33,11 +33,14 @@ #include "BLI_math.h" #include "BLI_threads.h" +#include "BKE_DerivedMesh.h" #include "BKE_ccg.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_lib_id.h" #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_mesh_tangent.h" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_subsurf.h" @@ -488,9 +491,35 @@ static void do_multires_bake(MultiresBakeRender *bkr, void *bake_data = NULL; + Mesh *temp_mesh = BKE_mesh_new_nomain( + dm->getNumVerts(dm), dm->getNumEdges(dm), 0, dm->getNumLoops(dm), dm->getNumPolys(dm)); + memcpy(temp_mesh->mvert, dm->getVertArray(dm), temp_mesh->totvert * sizeof(*temp_mesh->mvert)); + memcpy(temp_mesh->medge, dm->getEdgeArray(dm), temp_mesh->totedge * sizeof(*temp_mesh->medge)); + memcpy(temp_mesh->mpoly, dm->getPolyArray(dm), temp_mesh->totpoly * sizeof(*temp_mesh->mpoly)); + memcpy(temp_mesh->mloop, dm->getLoopArray(dm), temp_mesh->totloop * sizeof(*temp_mesh->mloop)); + const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(temp_mesh); + if (require_tangent) { if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) { - DM_calc_loop_tangents(dm, true, NULL, 0); + BKE_mesh_calc_loop_tangent_ex( + dm->getVertArray(dm), + dm->getPolyArray(dm), + dm->getNumPolys(dm), + dm->getLoopArray(dm), + dm->getLoopTriArray(dm), + dm->getNumLoopTri(dm), + &dm->loopData, + true, + NULL, + 0, + vert_normals, + (const float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL), + (const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL), + (const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */ + /* result */ + &dm->loopData, + dm->getNumLoops(dm), + &dm->tangent_mask); } pvtangent = DM_get_loop_data_layer(dm, CD_TANGENT); @@ -524,6 +553,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, handle->data.mpoly = mpoly; handle->data.mvert = mvert; + handle->data.vert_normals = vert_normals; handle->data.mloopuv = mloopuv; handle->data.mlooptri = mlooptri; handle->data.mloop = mloop; @@ -575,6 +605,8 @@ static void do_multires_bake(MultiresBakeRender *bkr, MEM_freeN(handles); + BKE_id_free(NULL, temp_mesh); + BKE_image_release_ibuf(ima, ibuf, NULL); } } diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index 5a9d9db5367..7aff01242e3 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -48,16 +48,17 @@ namespace blender::render::texturemargin { -/* The map class contains both a pixel map which maps out polygon indices for all UV-polygons and +/** + * The map class contains both a pixel map which maps out polygon indices for all UV-polygons and * adjacency tables. */ class TextureMarginMap { static const int directions[8][2]; static const int distances[8]; - /* Maps UV-edges to their corresponding UV-edge. */ + /** Maps UV-edges to their corresponding UV-edge. */ Vector<int> loop_adjacency_map_; - /* Maps UV-edges to their corresponding polygon. */ + /** Maps UV-edges to their corresponding polygon. */ Vector<int> loop_to_poly_map_; int w_, h_; @@ -122,7 +123,7 @@ class TextureMarginMap { void rasterize_tri(float *v1, float *v2, float *v3, uint32_t value, char *mask) { /* NOTE: This is not thread safe, because the value to be written by the rasterizer is - * a class member. If this is ever made multi-threaded each thread needs to get it's own. */ + * a class member. If this is ever made multi-threaded each thread needs to get its own. */ value_to_store_ = value; mask_ = mask; zspan_scanconvert( @@ -132,9 +133,7 @@ class TextureMarginMap { static void zscan_store_pixel( void *map, int x, int y, [[maybe_unused]] float u, [[maybe_unused]] float v) { - /* NOTE: Not thread safe, see comment above. - * - */ + /* NOTE: Not thread safe, see comment above. */ TextureMarginMap *m = static_cast<TextureMarginMap *>(map); m->set_pixel(x, y, m->value_to_store_); if (m->mask_) { @@ -153,7 +152,8 @@ class TextureMarginMap { #define IsDijkstraPixel(dp) ((dp)&0x80000000) #define DijkstraPixelIsUnset(dp) ((dp) == 0xFFFFFFFF) - /* Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map. + /** + * Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map. * For each pixel mark which direction is the shortest way to a polygon. */ void grow_dijkstra(int margin) @@ -188,8 +188,10 @@ class TextureMarginMap { } } - // std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun); - // Not strictly needed because at this point it already is a heap. + /* Not strictly needed because at this point it already is a heap. */ +#if 0 + std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun); +#endif while (active_pixels.size()) { std::pop_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun); @@ -215,7 +217,8 @@ class TextureMarginMap { } } - /* Walk over the map and for margin pixels follow the direction stored in the bottom 3 + /** + * Walk over the map and for margin pixels follow the direction stored in the bottom 3 * bits back to the polygon. * Then look up the pixel from the next polygon. */ @@ -324,10 +327,12 @@ class TextureMarginMap { } } - /* Call lookup_pixel for the start_poly. If that fails, try the adjacent polygons as well. - * Because the Dijkstra is not vey exact in determining which polygon is the closest, the + /** + * Call lookup_pixel for the start_poly. If that fails, try the adjacent polygons as well. + * Because the Dijkstra is not very exact in determining which polygon is the closest, the * polygon we need can be the one next to the one the Dijkstra map provides. To prevent missing - * pixels also check the neighbouring polygons. */ + * pixels also check the neighboring polygons. + */ bool lookup_pixel_polygon_neighbourhood( float x, float y, uint32_t *r_start_poly, float *r_destx, float *r_desty, int *r_other_poly) { @@ -344,8 +349,8 @@ class TextureMarginMap { float mindist = -1.f; - /* Loop over all adjacent polyons and determine which edge is closest. - * This could be optimized by only inspecting neigbours which are on the edge of an island. + /* Loop over all adjacent polygons and determine which edge is closest. + * This could be optimized by only inspecting neighbors which are on the edge of an island. * But it seems fast enough for now and that would add a lot of complexity. */ for (int i = 0; i < totloop; i++) { int otherloop = loop_adjacency_map_[i + loopstart]; @@ -370,10 +375,12 @@ class TextureMarginMap { return mindist >= 0.f; } - /* Find which edge of the src_poly is closest to x,y. Look up it's adjacent UV-edge and polygon. + /** + * Find which edge of the src_poly is closest to x,y. Look up its adjacent UV-edge and polygon. * Then return the location of the equivalent pixel in the other polygon. * Returns true if a new pixel location was found, false if it wasn't, which can happen if the - * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon. */ + * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon. + */ bool lookup_pixel(float x, float y, int src_poly, @@ -463,7 +470,7 @@ class TextureMarginMap { float2 other_edgepoint1 = uv_to_xy(mloopuv_[other_edge]); float2 other_edgepoint2 = uv_to_xy(mloopuv_[other_edge2]); - /* Calculate the vector from the order edges last point to it's first point. */ + /* Calculate the vector from the order edges last point to its first point. */ float2 other_ab = other_edgepoint1 - other_edgepoint2; float2 other_reflect_point = other_edgepoint2 + (found_t * other_ab); float2 perpendicular_other_ab; @@ -568,7 +575,9 @@ static void generate_margin(ImBuf *ibuf, vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f); } - BLI_assert(lt->poly < 0x80000000); // NOTE: we need the top bit for the dijkstra distance map + /* NOTE: we need the top bit for the dijkstra distance map. */ + BLI_assert(lt->poly < 0x80000000); + map.rasterize_tri(vec[0], vec[1], vec[2], lt->poly, draw_new_mask ? mask : nullptr); } diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c index 886ee89595b..82599a5fb69 100644 --- a/source/blender/sequencer/intern/clipboard.c +++ b/source/blender/sequencer/intern/clipboard.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index a35e83a8632..909954b99f1 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index 51e4613f088..3caf965a608 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Peter Schlaile <peter [at] schlaile [dot] de> 2010 + * Copyright 2010 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c index 6cd53f08b3a..42a5f5df787 100644 --- a/source/blender/sequencer/intern/iterator.c +++ b/source/blender/sequencer/intern/iterator.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/multiview.c b/source/blender/sequencer/intern/multiview.c index 68d2a33fd5c..2658846209f 100644 --- a/source/blender/sequencer/intern/multiview.c +++ b/source/blender/sequencer/intern/multiview.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index 5982f89a287..906474f301d 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/proxy_job.c b/source/blender/sequencer/intern/proxy_job.c index afdac04d998..8989d7959c9 100644 --- a/source/blender/sequencer/intern/proxy_job.c +++ b/source/blender/sequencer/intern/proxy_job.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 482425e70d3..08c81096b14 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file @@ -524,8 +522,15 @@ static void sequencer_preprocess_transform_crop( const float crop_scale_factor = do_scale_to_render_size ? preview_scale_factor : 1.0f; sequencer_image_crop_init(seq, in, crop_scale_factor, &source_crop); - const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR : - IMB_FILTER_NEAREST; + eIMBInterpolationFilterMode filter; + const StripTransform *transform = seq->strip->transform; + if (transform->filter == SEQ_TRANSFORM_FILTER_NEAREST) { + filter = IMB_FILTER_NEAREST; + } + else { + filter = IMB_FILTER_BILINEAR; + } + IMB_transform(in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, transform_matrix, &source_crop); if (!seq_image_transform_transparency_gained(context, seq)) { diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index 1c7fe927381..387b65648a4 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file @@ -85,6 +83,7 @@ static Strip *seq_strip_alloc(int type) strip->transform->scale_y = 1; strip->transform->origin[0] = 0.5f; strip->transform->origin[1] = 0.5f; + strip->transform->filter = SEQ_TRANSFORM_FILTER_BILINEAR; strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop"); } diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c index 0788003fb12..141b07cebbe 100644 --- a/source/blender/sequencer/intern/sound.c +++ b/source/blender/sequencer/intern/sound.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index be29dcfcd0c..eb34d287dcc 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file @@ -297,7 +295,7 @@ static void seq_add_sound_av_sync(Main *bmain, Scene *scene, Sequence *seq, SeqL const double av_stream_offset = sound_stream.start - load_data->r_video_stream_start; const int frame_offset = av_stream_offset * FPS; - /* Set subframe offset. */ + /* Set sub-frame offset. */ seq->sound->offset_time = ((double)frame_offset / FPS) - av_stream_offset; SEQ_transform_translate_sequence(scene, seq, frame_offset); } diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 0479d3012fa..0d6a94a806d 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 7e7fc9e6bf7..a716bd6fed8 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/strip_select.c b/source/blender/sequencer/intern/strip_select.c index 8927e092864..c73e7d3a420 100644 --- a/source/blender/sequencer/intern/strip_select.c +++ b/source/blender/sequencer/intern/strip_select.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 31ee20cb6ca..2d36ab0654b 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 432fc1c166f..f4f492708eb 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 140aa2d67c5..fa34f0d6c79 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -13,11 +13,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * - Blender Foundation, 2003-2009 - * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * Copyright 2001-2002 NaN Holding BV. All rights reserved. + * 2003-2009 Blender Foundation. + * 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de> */ /** \file diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt index 0167591c3ba..ae78d9964e5 100644 --- a/source/blender/shader_fx/CMakeLists.txt +++ b/source/blender/shader_fx/CMakeLists.txt @@ -63,9 +63,5 @@ set(SRC set(LIB ) -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - blender_add_lib(bf_shader_fx "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 03b2fb49085..37b233d85d2 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -135,10 +135,6 @@ if(WITH_CYCLES) add_definitions(-DWITH_CYCLES) endif() -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - if(WITH_OPENCOLLADA) add_definitions(-DWITH_COLLADA) endif() diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index d1f790ce3e2..929b39715b9 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -1048,6 +1048,10 @@ typedef struct wmDragActiveDropState { * it as needed. */ struct ARegion *region_from; + /** If `active_dropbox` is set, additional context provided by the active (i.e. hovered) button. + * Activated before context sensitive operations (polling, drawing, dropping). */ + struct bContextStore *ui_context; + /** Text to show when a dropbox poll succeeds (so the dropbox itself is available) but the * operator poll fails. Typically the message the operator set with * CTX_wm_operator_poll_msg_set(). */ diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c index 6f10e4f3f0d..2a93e279576 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c @@ -706,7 +706,7 @@ wmKeyMap *WM_gizmogroup_setup_keymap_generic_maybe_drag(const wmGizmoGroupType * /** * Variation of #WM_gizmogroup_keymap_common but with keymap items for selection * - * TODO(campbell): move to Python. + * TODO(@campbellbarton): move to Python. * * \param name: Typically #wmGizmoGroupType.name * \param params: Typically #wmGizmoGroupType.gzmap_params @@ -719,7 +719,7 @@ static wmKeyMap *WM_gizmogroup_keymap_template_select_ex( wmKeyMap *km = WM_keymap_ensure(kc, name, params->spaceid, params->regionid); const bool do_init = BLI_listbase_is_empty(&km->items); - /* FIXME(campbell) */ + /* FIXME(@campbellbarton): Currently hard coded. */ #if 0 const int select_mouse = (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE; const int select_tweak = (U.flag & USER_LMOUSESELECT) ? EVT_TWEAK_L : EVT_TWEAK_R; diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index ab955a9e233..83e6e347ce7 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -572,7 +572,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); rcti rect; /* Almost certainly overkill, but allow for many custom gizmos. */ - uint buffer[MAXPICKBUF]; + GPUSelectResult buffer[MAXPICKELEMS]; short hits; BLI_rcti_init_pt_radius(&rect, co, hotspot); @@ -582,19 +582,19 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, * - #GPU_SELECT_ALL: Use it to check if there is anything at the cursor location * (only ever runs once). * - #GPU_SELECT_PICK_NEAREST: Use if there are more than 1 item at the cursor location, - * select the best one. + * pick the nearest one. * - #GPU_SELECT_PICK_ALL: Use for the same purpose as #GPU_SELECT_PICK_NEAREST * when the selection depths need to re-ordered based on a bias. * */ - const int gpu_select_mode = (use_depth_test ? - (has_3d_select_bias ? - /* Using select bias means the depths need to be - * re-calculated based on the bias to pick the best. */ - GPU_SELECT_PICK_ALL : - /* No bias, just pick the closest. */ - GPU_SELECT_PICK_NEAREST) : - /* Fast-path (occlusion queries). */ - GPU_SELECT_ALL); + const eGPUSelectMode gpu_select_mode = + (use_depth_test ? (has_3d_select_bias ? + /* Using select bias means the depths need to be + * re-calculated based on the bias to pick the best. */ + GPU_SELECT_PICK_ALL : + /* No bias, just pick the closest. */ + GPU_SELECT_PICK_NEAREST) : + /* Fast-path (occlusion queries). */ + GPU_SELECT_ALL); /* When switching between modes and the mouse pointer is over a gizmo, the highlight test is * performed before the viewport is fully initialized (region->draw_buffer = NULL). @@ -657,14 +657,14 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); - uint *buf_iter = buffer; + GPUSelectResult *buf_iter = buffer; float dot_best = FLT_MAX; - for (int i = 0; i < hits; i++, buf_iter += 4) { - BLI_assert(buf_iter[3] != -1); - wmGizmo *gz = visible_gizmos[buf_iter[3] >> 8]; + for (int i = 0; i < hits; i++, buf_iter++) { + BLI_assert(buf_iter->id != -1); + wmGizmo *gz = visible_gizmos[buf_iter->id >> 8]; float co_3d[3]; - co_screen[2] = int_as_float(buf_iter[1]); + co_screen[2] = int_as_float(buf_iter->depth); GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d); float select_bias = gz->select_bias; if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { @@ -674,14 +674,14 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, const float dot_test = dot_v3v3(co_3d, co_direction) - select_bias; if (dot_best > dot_test) { dot_best = dot_test; - hit_found = buf_iter[3]; + hit_found = buf_iter->id; } } } else { - const uint *hit_near = GPU_select_buffer_near(buffer, hits); + const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits); if (hit_near) { - hit_found = hit_near[3]; + hit_found = hit_near->id; } } diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 96cb66b44ea..3bc77db45ca 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -226,6 +226,30 @@ void wm_drags_exit(wmWindowManager *wm, wmWindow *win) } } +static bContextStore *wm_drop_ui_context_create(const bContext *C) +{ + uiBut *active_but = UI_region_active_but_get(CTX_wm_region(C)); + if (!active_but) { + return NULL; + } + + bContextStore *but_context = UI_but_context_get(active_but); + if (!but_context) { + return NULL; + } + + return CTX_store_copy(but_context); +} + +static void wm_drop_ui_context_free(bContextStore **context_store) +{ + if (!*context_store) { + return; + } + CTX_store_free(*context_store); + *context_store = NULL; +} + void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy) { drag->imb = imb; @@ -259,6 +283,7 @@ void WM_drag_free(wmDrag *drag) if (drag->flags & WM_DRAG_FREE_DATA) { WM_drag_data_free(drag->type, drag->poin); } + wm_drop_ui_context_free(&drag->drop_state.ui_context); if (drag->drop_state.free_disabled_info) { MEM_SAFE_FREE(drag->drop_state.disabled_info); } @@ -317,6 +342,10 @@ static wmDropBox *dropbox_active(bContext *C, } const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); + if (drag->drop_state.ui_context) { + CTX_store_set(C, drag->drop_state.ui_context); + } + if (WM_operator_poll_context(C, drop->ot, opcontext)) { return drop; } @@ -367,6 +396,10 @@ static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *even return; } + /* Update UI context, before polling so polls can query this context. */ + wm_drop_ui_context_free(&drag->drop_state.ui_context); + drag->drop_state.ui_context = wm_drop_ui_context_create(C); + wmDropBox *drop_prev = drag->drop_state.active_dropbox; wmDropBox *drop = wm_dropbox_active(C, drag, event); if (drop != drop_prev) { @@ -381,11 +414,20 @@ static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *even drag->drop_state.area_from = drop ? CTX_wm_area(C) : NULL; drag->drop_state.region_from = drop ? CTX_wm_region(C) : NULL; } + + if (!drag->drop_state.active_dropbox) { + wm_drop_ui_context_free(&drag->drop_state.ui_context); + } } void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop) { const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); + + if (drag->drop_state.ui_context) { + CTX_store_set(C, drag->drop_state.ui_context); + } + /* Optionally copy drag information to operator properties. Don't call it if the * operator fails anyway, it might do more than just set properties (e.g. * typically import an asset). */ @@ -396,6 +438,11 @@ void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop) wm_drags_exit(CTX_wm_manager(C), CTX_wm_window(C)); } +void wm_drop_end(bContext *C, wmDrag *UNUSED(drag), wmDropBox *UNUSED(drop)) +{ + CTX_store_set(C, NULL); +} + void wm_drags_check_ops(bContext *C, const wmEvent *event) { wmWindowManager *wm = CTX_wm_manager(C); @@ -897,6 +944,7 @@ void wm_drags_draw(bContext *C, wmWindow *win) if (drag->drop_state.active_dropbox) { CTX_wm_area_set(C, drag->drop_state.area_from); CTX_wm_region_set(C, drag->drop_state.region_from); + CTX_store_set(C, drag->drop_state.ui_context); /* Drawing should be allowed to assume the context from handling and polling (that's why we * restore it above). */ @@ -915,4 +963,5 @@ void wm_drags_draw(bContext *C, wmWindow *win) GPU_blend(GPU_BLEND_NONE); CTX_wm_area_set(C, NULL); CTX_wm_region_set(C, NULL); + CTX_store_set(C, NULL); } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 0cc2db661ec..5210b315af6 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1081,7 +1081,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons } } - /* XXX(mont29) Disabled the repeat check to address part 2 of T31840. + /* XXX(@mont29): Disabled the repeat check to address part 2 of T31840. * Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason * why this was needed, but worth to note it in case something turns bad. */ if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */) { @@ -3076,6 +3076,8 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis event->customdata = NULL; event->custom = 0; + wm_drop_end(C, drag, drop); + /* XXX fileread case. */ if (CTX_wm_window(C) == NULL) { return action; diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 1478712c3cd..9b9aa37a251 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -874,18 +874,16 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports) duration_lib_override_recursive_resync_seconds); } - if (bf_reports->count.linked_proxies != 0 || - bf_reports->count.proxies_to_lib_overrides_success != 0 || + if (bf_reports->count.proxies_to_lib_overrides_success != 0 || bf_reports->count.proxies_to_lib_overrides_failures != 0) { - BKE_reportf(bf_reports->reports, - RPT_WARNING, - "Proxies are deprecated (%d proxies were automatically converted to library " - "overrides, %d proxies could not be converted and %d linked proxies were kept " - "untouched). If you need to keep proxies for the time being, please disable the " - "`Proxy to Override Auto Conversion` in Experimental user preferences", - bf_reports->count.proxies_to_lib_overrides_success, - bf_reports->count.proxies_to_lib_overrides_failures, - bf_reports->count.linked_proxies); + BKE_reportf( + bf_reports->reports, + RPT_WARNING, + "Proxies have been removed from Blender (%d proxies were automatically converted " + "to library overrides, %d proxies could not be converted and were cleared). " + "Please also consider re-saving any library .blend file with the newest Blender version.", + bf_reports->count.proxies_to_lib_overrides_success, + bf_reports->count.proxies_to_lib_overrides_failures); } if (bf_reports->count.sequence_strips_skipped != 0) { @@ -2706,7 +2704,7 @@ static char *wm_open_mainfile_description(struct bContext *UNUSED(C), BLI_stat_t stats; if (BLI_stat(path, &stats) == -1) { - return BLI_sprintfN("%s\n\n%s", path, N_("File Not Found")); + return BLI_sprintfN("%s\n\n%s", path, TIP_("File Not Found")); } /* Date. */ @@ -2716,7 +2714,7 @@ static char *wm_open_mainfile_description(struct bContext *UNUSED(C), BLI_filelist_entry_datetime_to_string( NULL, (int64_t)stats.st_mtime, false, time_st, date_st, &is_today, &is_yesterday); if (is_today || is_yesterday) { - BLI_strncpy(date_st, is_today ? N_("Today") : N_("Yesterday"), sizeof(date_st)); + BLI_strncpy(date_st, is_today ? TIP_("Today") : TIP_("Yesterday"), sizeof(date_st)); } /* Size. */ @@ -2724,7 +2722,7 @@ static char *wm_open_mainfile_description(struct bContext *UNUSED(C), BLI_filelist_entry_size_to_string(NULL, (uint64_t)stats.st_size, false, size_str); return BLI_sprintfN( - "%s\n\n%s: %s %s\n%s: %s", path, N_("Modified"), date_st, time_st, N_("Size"), size_str); + "%s\n\n%s: %s %s\n%s: %s", path, TIP_("Modified"), date_st, time_st, TIP_("Size"), size_str); } /* currently fits in a pointer */ @@ -3171,8 +3169,8 @@ static char *wm_save_as_mainfile_get_description(bContext *UNUSED(C), PointerRNA *ptr) { if (RNA_boolean_get(ptr, "copy")) { - return BLI_strdup( - "Save the current file in the desired location but do not make the saved file active"); + return BLI_strdup(TIP_( + "Save the current file in the desired location but do not make the saved file active")); } return NULL; } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 6caac79c4d5..cff4287a2d0 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -356,10 +356,10 @@ void WM_init(bContext *C, int argc, const char **argv) if (!G.background) { if (wm_start_with_console) { - GHOST_toggleConsole(1); + setConsoleWindowState(GHOST_kConsoleWindowStateShow); } else { - GHOST_toggleConsole(3); + setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch); } } @@ -594,9 +594,7 @@ void WM_exit_ex(bContext *C, const bool do_python) DRW_opengl_context_destroy(); } -#ifdef WITH_INTERNATIONAL BLT_lang_free(); -#endif ANIM_keyingset_infos_exit(); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 6c9b0af5186..2c82d8f5b6b 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2046,7 +2046,7 @@ static void WM_OT_quit_blender(wmOperatorType *ot) static int wm_console_toggle_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) { - GHOST_toggleConsole(2); + setConsoleWindowState(GHOST_kConsoleWindowStateToggle); return OPERATOR_FINISHED; } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index a1854a8ed86..7e4acf709b7 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -13,9 +13,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2007 Blender Foundation but based - * on ghostwinlay.c (C) 2001-2002 by NaN Holding BV - * All rights reserved. + * Copyright 2001-2002 by NaN Holding BV. All rights reserved. + * 2007 Blender Foundation */ /** \file @@ -1483,7 +1482,11 @@ static bool wm_window_timer(const bContext *C) wt->delta = time - wt->ltime; wt->duration += wt->delta; wt->ltime = time; - wt->ntime = wt->stime + wt->timestep * ceil(wt->duration / wt->timestep); + + wt->ntime = wt->stime; + if (wt->timestep != 0.0f) { + wt->ntime += wt->timestep * ceil(wt->duration / wt->timestep); + } if (wt->event_type == TIMERJOBS) { wm_jobs_timer(wm, wt); @@ -1596,6 +1599,7 @@ void WM_event_timer_sleep(wmWindowManager *wm, wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep) { wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer"); + BLI_assert(timestep >= 0.0f); wt->event_type = event_type; wt->ltime = PIL_check_seconds_timer(); @@ -1615,6 +1619,7 @@ wmTimer *WM_event_add_timer_notifier(wmWindowManager *wm, double timestep) { wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer"); + BLI_assert(timestep >= 0.0f); wt->event_type = TIMERNOTIFIER; wt->ltime = PIL_check_seconds_timer(); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 925be8ab183..252ff228bc1 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -199,6 +199,7 @@ void wm_dropbox_free(void); */ void wm_drags_exit(wmWindowManager *wm, wmWindow *win); void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop); +void wm_drop_end(bContext *C, wmDrag *drag, wmDropBox *drop); /** * Called in inner handler loop, region context. */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index a6685e97c4f..6fcaad92661 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -60,7 +60,7 @@ enum { /* ********** Start of Input devices. ********** */ - /* MOUSE : 0x000x, 0x001x */ + /* MOUSE: 0x000x, 0x001x */ LEFTMOUSE = 0x0001, MIDDLEMOUSE = 0x0002, RIGHTMOUSE = 0x0003, @@ -71,7 +71,7 @@ enum { /* More mouse buttons - can't use 9 and 10 here (wheel) */ BUTTON6MOUSE = 0x0012, BUTTON7MOUSE = 0x0013, - /* Extra trackpad gestures */ + /* Extra track-pad gestures. */ MOUSEPAN = 0x000e, MOUSEZOOM = 0x000f, MOUSEROTATE = 0x0010, |