diff options
Diffstat (limited to 'source')
809 files changed, 26965 insertions, 11672 deletions
diff --git a/source/blender/blenfont/BLF_translation.h b/source/blender/blenfont/BLF_translation.h index c11996799ff..b42e6f80022 100644 --- a/source/blender/blenfont/BLF_translation.h +++ b/source/blender/blenfont/BLF_translation.h @@ -163,6 +163,8 @@ const char *BLF_translate_do_new_dataname(const char *msgctxt, const char *msgid #define BLF_I18NCONTEXT_ID_MESH "Mesh" #define BLF_I18NCONTEXT_ID_NODETREE "NodeTree" #define BLF_I18NCONTEXT_ID_OBJECT "Object" +#define BLF_I18NCONTEXT_ID_PAINTCURVE "PaintCurve" +#define BLF_I18NCONTEXT_ID_PALETTE "Palette" #define BLF_I18NCONTEXT_ID_PARTICLESETTINGS "ParticleSettings" #define BLF_I18NCONTEXT_ID_SCENE "Scene" #define BLF_I18NCONTEXT_ID_SCREEN "Screen" @@ -207,11 +209,15 @@ typedef struct BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_LAMP, "id_lamp"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_LIBRARY, "id_library"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_LATTICE, "id_lattice"), \ + BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_MASK, "id_mask"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_MATERIAL, "id_material"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_METABALL, "id_metaball"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_MESH, "id_mesh"), \ + BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_MOVIECLIP, "id_movieclip"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_NODETREE, "id_nodetree"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_OBJECT, "id_object"), \ + BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_PAINTCURVE, "id_paintcurve"), \ + BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_PALETTE, "id_palette"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_PARTICLESETTINGS, "id_particlesettings"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_SCENE, "id_scene"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_SCREEN, "id_screen"), \ @@ -223,8 +229,6 @@ typedef struct BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_VFONT, "id_vfont"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_WORLD, "id_world"), \ BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_WINDOWMANAGER, "id_windowmanager"), \ - BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_MOVIECLIP, "id_movieclip"), \ - BLF_I18NCONTEXTS_ITEM(BLF_I18NCONTEXT_ID_MASK, "id_mask"), \ {NULL, NULL, NULL} \ } diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index 346d5bc64b8..392a9ede100 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -56,6 +56,12 @@ set(SRC intern/blf_internal_types.h ) +if(WIN32) + list(APPEND SRC + intern/blf_font_win32_compat.c + ) +endif() + if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 4891c332c87..087c7c7345e 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -65,6 +65,10 @@ #include "BLI_strict_flags.h" +#ifdef WIN32 +# define FT_New_Face FT_New_Face__win32_compat +#endif + /* freetype2 handle ONLY for this file!. */ static FT_Library ft_lib; static SpinLock ft_lib_mutex; diff --git a/source/blender/blenfont/intern/blf_font_win32_compat.c b/source/blender/blenfont/intern/blf_font_win32_compat.c new file mode 100644 index 00000000000..dd4a443e69f --- /dev/null +++ b/source/blender/blenfont/intern/blf_font_win32_compat.c @@ -0,0 +1,145 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenfont/intern/blf_font_win32_compat.c + * \ingroup blf + * + * Workaround for win32 which needs to use BLI_fopen to access files. + * + * defines #FT_New_Face__win32_compat, a drop-in replacement for \a #FT_New_Face. + */ + +#ifdef WIN32 + +#include <stdio.h> + +#include <ft2build.h> +#include FT_FREETYPE_H + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_fileops.h" + +#include "blf_internal.h" + +/* internal freetype defines */ +#define STREAM_FILE(stream) ((FILE *)stream->descriptor.pointer) +#define FT_THROW(e) -1 + +static void ft_ansi_stream_close( + FT_Stream stream) +{ + fclose(STREAM_FILE(stream)); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + + /* WARNING: this works but be careful! + * Checked freetype sources, there isn't any access after closing. */ + MEM_freeN(stream); +} + +static unsigned long ft_ansi_stream_io( + FT_Stream stream, + unsigned long offset, + unsigned char *buffer, + unsigned long count) +{ + FILE *file; + if (!count && offset > stream->size) + return 1; + + file = STREAM_FILE(stream); + + if (stream->pos != offset) + fseek(file, offset, SEEK_SET); + + return fread(buffer, 1, count, file); +} + +static FT_Error FT_Stream_Open__win32_compat(FT_Stream stream, const char *filepathname) +{ + FILE *file; + BLI_assert(stream); + + stream->descriptor.pointer = NULL; + stream->pathname.pointer = (char *)filepathname; + stream->base = 0; + stream->pos = 0; + stream->read = NULL; + stream->close = NULL; + + file = BLI_fopen(filepathname, "rb"); + if (!file) { + fprintf(stderr, + "FT_Stream_Open: " + "could not open `%s'\n", filepathname); + return FT_THROW(Cannot_Open_Resource); + } + + fseek(file, 0, SEEK_END); + stream->size = ftell(file); + if (!stream->size) { + fprintf(stderr, + "FT_Stream_Open: " + "opened `%s' but zero-sized\n", filepathname); + fclose(file); + return FT_THROW(Cannot_Open_Stream); + } + + fseek(file, 0, SEEK_SET); + + stream->descriptor.pointer = file; + stream->read = ft_ansi_stream_io; + stream->close = ft_ansi_stream_close; + + return FT_Err_Ok; +} + +FT_Error FT_New_Face__win32_compat( + FT_Library library, + const char *pathname, + FT_Long face_index, + FT_Face *aface) +{ + FT_Error err; + FT_Open_Args open; + FT_Stream stream = NULL; + stream = MEM_callocN(sizeof(*stream), __func__); + + open.flags = FT_OPEN_STREAM; + open.stream = stream; + stream->pathname.pointer = (char *)pathname; + + err = FT_Stream_Open__win32_compat(stream, pathname); + if (err) { + MEM_freeN(stream); + return err; + } + + err = FT_Open_Face(library, &open, face_index, aface); + /* no need to free 'stream', its handled by FT_Open_Face if an error occurs */ + + return err; +} + +#endif /* WIN32 */ diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 7978d28a4ef..c65a0825a49 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -262,8 +262,8 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) g->xoff = -1; g->yoff = -1; bitmap = slot->bitmap; - g->width = bitmap.width; - g->height = bitmap.rows; + g->width = (int)bitmap.width; + g->height = (int)bitmap.rows; if (g->width && g->height) { if (sharp) { diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 8cb2d377449..39b3e3397be 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -75,4 +75,11 @@ struct GlyphBLF *blf_glyph_add(struct FontBLF *font, unsigned int index, unsigne void blf_glyph_free(struct GlyphBLF *g); void blf_glyph_render(struct FontBLF *font, struct GlyphBLF *g, float x, float y); +#ifdef WIN32 +/* blf_font_win32_compat.c */ +# ifdef FT_FREETYPE_H +extern FT_Error FT_New_Face__win32_compat(FT_Library library, const char *pathname, FT_Long face_index, FT_Face *aface); +# endif +#endif + #endif /* __BLF_INTERNAL_H__ */ diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 12d71827136..10614e8ca59 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -42,6 +42,7 @@ #include "BLI_path_util.h" #include "BLI_string.h" +#include "BKE_appdir.h" #include "DNA_userdef_types.h" @@ -79,7 +80,7 @@ static void free_locales(void) static void fill_locales(void) { - const char * const languages_path = BLI_get_folder(BLENDER_DATAFILES, "locale"); + const char * const languages_path = BKE_appdir_folder_id(BLENDER_DATAFILES, "locale"); char languages[FILE_MAX]; LinkNode *lines = NULL, *line; char *str; @@ -187,7 +188,7 @@ EnumPropertyItem *BLF_RNA_lang_enum_properties(void) void BLF_lang_init(void) { #ifdef WITH_INTERNATIONAL - const char * const messagepath = BLI_get_folder(BLENDER_DATAFILES, "locale"); + const char * const messagepath = BKE_appdir_folder_id(BLENDER_DATAFILES, "locale"); if (messagepath) { bl_locale_init(messagepath, TEXT_DOMAIN_NAME); diff --git a/source/blender/blenfont/intern/blf_translation.c b/source/blender/blenfont/intern/blf_translation.c index 150ff1b2107..e7d2c14b16f 100644 --- a/source/blender/blenfont/intern/blf_translation.c +++ b/source/blender/blenfont/intern/blf_translation.c @@ -42,6 +42,8 @@ #include "BLI_path_util.h" #include "BLI_string.h" +#include "BKE_appdir.h" + #include "DNA_userdef_types.h" /* For user settings. */ #include "BPY_extern.h" @@ -62,7 +64,7 @@ unsigned char *BLF_get_unifont(int *r_unifont_size) { #ifdef WITH_INTERNATIONAL if (unifont_ttf == NULL) { - const char * const fontpath = BLI_get_folder(BLENDER_DATAFILES, "fonts"); + const char * const fontpath = BKE_appdir_folder_id(BLENDER_DATAFILES, "fonts"); if (fontpath) { char unifont_path[1024]; @@ -97,7 +99,7 @@ unsigned char *BLF_get_unifont_mono(int *r_unifont_size) { #ifdef WITH_INTERNATIONAL if (unifont_mono_ttf == NULL) { - const char *fontpath = BLI_get_folder(BLENDER_DATAFILES, "fonts"); + const char *fontpath = BKE_appdir_folder_id(BLENDER_DATAFILES, "fonts"); if (fontpath) { char unifont_path[1024]; diff --git a/source/blender/blenfont/intern/blf_util.c b/source/blender/blenfont/intern/blf_util.c index 06309a944e9..cdd81e33b0a 100644 --- a/source/blender/blenfont/intern/blf_util.c +++ b/source/blender/blenfont/intern/blf_util.c @@ -38,7 +38,6 @@ #include "blf_internal.h" #include "BLI_utildefines.h" -#include "BLI_string_utf8.h" unsigned int blf_next_p2(unsigned int x) { diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 229d2fc17cd..da4fcb4eca4 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -147,6 +147,7 @@ typedef int (*DMSetMaterial)(int mat_nr, void *attribs); typedef int (*DMCompareDrawOptions)(void *userData, int cur_index, int next_index); typedef void (*DMSetDrawInterpOptions)(void *userData, int index, float t); typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index); +typedef DMDrawOption (*DMSetDrawOptionsMappedTex)(void *userData, int origindex, int mat_nr); typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTFace *tface, const bool has_vcol, int matnr); typedef enum DMDrawFlag { @@ -423,7 +424,7 @@ struct DerivedMesh { * - Drawing options too complicated to enumerate, look at code. */ void (*drawMappedFacesTex)(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, + DMSetDrawOptionsMappedTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag uvflag); diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h new file mode 100644 index 00000000000..5e42f17be03 --- /dev/null +++ b/source/blender/blenkernel/BKE_appdir.h @@ -0,0 +1,80 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_APPDIR_H__ +#define __BKE_APPDIR_H__ + +/** \file BKE_appdir.h + * \ingroup bli + */ + +/* note on naming: typical _get() suffix is omitted here, + * since its the main purpose of the API. */ +const char *BKE_appdir_folder_default(void); +const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder); +const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder); +const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder); +const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check); + +/* Initialize path to program executable */ +void BKE_appdir_program_path_init(const char *argv0); + +const char *BKE_appdir_program_path(void); +const char *BKE_appdir_program_dir(void); + +/* Initialize path to temporary directory. */ +void BKE_tempdir_init(char *userdir); +void BKE_tempdir_system_init(char *dir); + +const char *BKE_tempdir_base(void); +const char *BKE_tempdir_session(void); +void BKE_tempdir_session_purge(void); + + +/* folder_id */ +enum { + /* general, will find based on user/local/system priority */ + BLENDER_DATAFILES = 2, + + /* user-specific */ + BLENDER_USER_CONFIG = 31, + BLENDER_USER_DATAFILES = 32, + BLENDER_USER_SCRIPTS = 33, + BLENDER_USER_AUTOSAVE = 34, + + /* system */ + BLENDER_SYSTEM_DATAFILES = 52, + BLENDER_SYSTEM_SCRIPTS = 53, + BLENDER_SYSTEM_PYTHON = 54, +}; + +/* for BKE_appdir_folder_id_version only */ +enum { + BLENDER_RESOURCE_PATH_USER = 0, + BLENDER_RESOURCE_PATH_LOCAL = 1, + BLENDER_RESOURCE_PATH_SYSTEM = 2, +}; + +#define BLENDER_STARTUP_FILE "startup.blend" +#define BLENDER_USERPREF_FILE "userpref.blend" +#define BLENDER_QUIT_FILE "quit.blend" +#define BLENDER_BOOKMARK_FILE "bookmarks.txt" +#define BLENDER_HISTORY_FILE "recent-files.txt" + +#endif /* __BKE_APPDIR_H__ */ diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 4c333c8332b..0215becd2a0 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,7 +41,7 @@ extern "C" { /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 272 +#define BLENDER_VERSION 273 #define BLENDER_SUBVERSION 2 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 270 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index d48753590bb..49975fa0276 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -62,12 +62,11 @@ int BKE_brush_clone_image_delete(struct Brush *brush); /* jitter */ void BKE_brush_jitter_pos(const struct Scene *scene, struct Brush *brush, const float pos[2], float jitterpos[2]); -void BKE_brush_randomize_texture_coordinates(struct UnifiedPaintSettings *ups, bool mask); +void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool mask); /* brush curve */ void BKE_brush_curve_preset(struct Brush *b, int preset); -float BKE_brush_curve_strength_clamp(struct Brush *br, float p, const float len); -float BKE_brush_curve_strength(struct Brush *br, float p, const float len); /* used for sculpt */ +float BKE_brush_curve_strength(struct Brush *br, float p, const float len); /* sampling */ float BKE_brush_sample_tex_3D(const Scene *scene, struct Brush *br, const float point[3], diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 4bc8fc44bb4..a360511dcd3 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -31,6 +31,7 @@ * \ingroup bke */ +#include "BLI_bitmap.h" #include "BLI_kdopbvh.h" /* @@ -56,8 +57,8 @@ typedef struct BVHTreeFromMesh { struct MEdge *edge; /* only used for BVHTreeFromMeshEdges */ struct MFace *face; bool vert_allocated; - bool face_allocated; bool edge_allocated; + bool face_allocated; /* radius for raycast */ float sphere_radius; @@ -69,36 +70,28 @@ typedef struct BVHTreeFromMesh { } BVHTreeFromMesh; /* - * Builds a bvh tree where nodes are the vertexs of the given mesh. + * Builds a bvh tree where nodes are the relevant elements of the given mesh. * Configures BVHTreeFromMesh. * * The tree is build in mesh space coordinates, this means special care must be made on queries * so that the coordinates and rays are first translated on the mesh local coordinates. - * Reason for this is that later bvh_from_mesh_* might use a cache system and so it becomes possible to reuse - * a BVHTree. + * Reason for this is that bvh_from_mesh_* can use a cache in some cases and so it becomes possible to reuse a BVHTree. * * free_bvhtree_from_mesh should be called when the tree is no longer needed. */ BVHTree *bvhtree_from_mesh_verts(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); - -/* - * Builds a bvh tree where nodes are the faces of the given mesh. - * Configures BVHTreeFromMesh. - * - * The tree is build in mesh space coordinates, this means special care must be made on queries - * so that the coordinates and rays are first translated on the mesh local coordinates. - * Reason for this is that later bvh_from_mesh_* might use a cache system and so it becomes possible to reuse - * a BVHTree. - * - * The returned value is the same as in data->tree, its only returned to make it easier to test - * the success - * - * free_bvhtree_from_mesh should be called when the tree is no longer needed. - */ -BVHTree *bvhtree_from_mesh_faces(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data, struct MVert *vert, const int numVerts, + const bool vert_allocated, BLI_bitmap *mask, int numVerts_active, + float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_mesh_edges(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_mesh_faces(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data, struct MVert *vert, const bool vert_allocated, + struct MFace *face, const int numFaces, const bool face_allocated, + BLI_bitmap *mask, int numFaces_active, + float epsilon, int tree_type, int axis); + /* * Frees data allocated by a call to bvhtree_from_mesh_*. */ @@ -114,12 +107,13 @@ float nearest_point_in_tri_surface_squared(const float v0[3], const float v1[3], * BVHCache */ -//Using local coordinates -#define BVHTREE_FROM_FACES 0 -#define BVHTREE_FROM_VERTICES 1 -#define BVHTREE_FROM_EDGES 2 - -#define BVHTREE_FROM_FACES_EDITMESH 3 +/* Using local coordinates */ +enum { + BVHTREE_FROM_VERTS = 0, + BVHTREE_FROM_EDGES = 1, + BVHTREE_FROM_FACES = 2, + BVHTREE_FROM_FACES_EDITMESH = 3, +}; typedef struct LinkNode *BVHCache; diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index 01b401c6bcc..26d4986d93e 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -118,7 +118,9 @@ void BKE_camera_view_frame_ex(struct Scene *scene, struct Camera *camera, float void BKE_camera_view_frame(struct Scene *scene, struct Camera *camera, float r_vec[4][3]); bool BKE_camera_view_frame_fit_to_scene(struct Scene *scene, struct View3D *v3d, struct Object *camera_ob, - float r_co[3]); + float r_co[3], float *r_scale); +bool BKE_camera_view_frame_fit_to_coords(struct Scene *scene, float (*cos)[3], int num_cos, + struct Object *camera_ob, float r_co[3], float *r_scale); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 87da74dc119..82ae4930526 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -141,7 +141,8 @@ bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *p struct bConstraintOb *BKE_constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); void BKE_constraints_clear_evalob(struct bConstraintOb *cob); -void BKE_constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to); +void BKE_constraint_mat_convertspace( + struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale); void BKE_constraint_target_matrix_get(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); void BKE_constraint_targets_for_solving_get(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 877e376b343..ae0ef9ce314 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -56,6 +56,9 @@ struct Text; struct ImBuf; struct EditBone; struct bPoseChannel; +struct bGPdata; +struct bGPDlayer; +struct bGPDframe; struct wmWindow; struct wmWindowManager; struct SpaceText; @@ -275,6 +278,14 @@ struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C); int CTX_data_selected_pose_bones(const bContext *C, ListBase *list); int CTX_data_visible_pose_bones(const bContext *C, ListBase *list); +struct bGPdata *CTX_data_gpencil_data(const bContext *C); +struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C); +struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C); +int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); +int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); +int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); + + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 30a58891bda..f11aad27e4b 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -41,6 +41,8 @@ extern "C" { #include "BLI_sys_types.h" #include "BLI_utildefines.h" +#include "DNA_customdata_types.h" + struct BMesh; struct ID; struct CustomData; @@ -77,6 +79,9 @@ extern const CustomDataMask CD_MASK_EVERYTHING; void customData_mask_layers__print(CustomDataMask mask); +typedef void (*cd_interp)(void **sources, const float *weights, const float *sub_weights, int count, void *dest); +typedef void (*cd_copy)(const void *source, void *dest, int count); + /** * Checks if the layer at physical offset \a layer_n (in data->layers) support math * the below operations. @@ -96,6 +101,9 @@ bool CustomData_bmesh_has_free(const struct CustomData *data); * implemented for mloopuv/mloopcol, for now.*/ void CustomData_data_copy_value(int type, const void *source, void *dest); +/* Same as above, but doing advanced mixing. Only available for a few types of data (like colors...). */ +void CustomData_data_mix_value(int type, const void *source, void *dest, const int mixmode, const float mixfactor); + /* compares if data1 is equal to data2. type is a valid CustomData type * enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare * the data, if it exists, otherwise memcmp is used.*/ @@ -246,14 +254,14 @@ void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int typ void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n); bool CustomData_set_layer_name(const struct CustomData *data, int type, int n, const char *name); +const char *CustomData_get_layer_name(const struct CustomData *data, int type, int n); /* gets a pointer to the active or first layer of type * returns NULL if there is no layer of type */ void *CustomData_get_layer(const struct CustomData *data, int type); void *CustomData_get_layer_n(const struct CustomData *data, int type, int n); -void *CustomData_get_layer_named(const struct CustomData *data, int type, - const char *name); +void *CustomData_get_layer_named(const struct CustomData *data, int type, const char *name); int CustomData_get_offset(const struct CustomData *data, int type); int CustomData_get_n_offset(const struct CustomData *data, int type, int n); @@ -362,6 +370,82 @@ void CustomData_external_read(struct CustomData *data, void CustomData_external_reload(struct CustomData *data, struct ID *id, CustomDataMask mask, int totelem); +/* Mesh-to-mesh transfer data. */ + +struct MeshPairRemap; +struct CustomDataTransferLayerMap; + +typedef void (*cd_datatransfer_interp)( + const struct CustomDataTransferLayerMap *laymap, void *dest, + void **sources, const float *weights, const int count, const float mix_factor); + +/** + * Fake CD_LAYERS (those are actually 'real' data stored directly into elements' structs, or otherwise not (directly) + * accessible to usual CDLayer system). */ +enum { + CD_FAKE = 1 << 8, + + /* Vertices. */ + CD_FAKE_MDEFORMVERT = CD_FAKE | CD_MDEFORMVERT, /* *sigh* due to how vgroups are stored :( . */ + CD_FAKE_SHAPEKEY = CD_FAKE | CD_SHAPEKEY, /* Not available as real CD layer in non-bmesh context. */ + + /* Edges. */ + CD_FAKE_SEAM = CD_FAKE | 100, /* UV seam flag for edges. */ + CD_FAKE_CREASE = CD_FAKE | CD_CREASE, /* *sigh*. */ + + /* Multiple types of mesh elements... */ + CD_FAKE_BWEIGHT = CD_FAKE | CD_BWEIGHT, /* *sigh*. */ + CD_FAKE_UV = CD_FAKE | CD_MLOOPUV, /* UV flag, because we handle both loop's UVs and poly's textures. */ + + CD_FAKE_SHARP = CD_FAKE | 200, /* Sharp flag for edges, smooth flag for faces. */ +}; + +enum { + ME_VERT = 1 << 0, + ME_EDGE = 1 << 1, + ME_POLY = 1 << 2, + ME_LOOP = 1 << 3, +}; + +/** + * How to filter out some elements (to leave untouched). + * Note those options are highly dependent on type of transferred data! */ +enum { + CDT_MIX_NOMIX = -1, /* Special case, only used because we abuse 'copy' CD callback. */ + CDT_MIX_TRANSFER = 0, + CDT_MIX_REPLACE_ABOVE_THRESHOLD = 1, + CDT_MIX_REPLACE_BELOW_THRESHOLD = 2, + CDT_MIX_MIX = 16, + CDT_MIX_ADD = 17, + CDT_MIX_SUB = 18, + CDT_MIX_MUL = 19, + /* etc. etc. */ +}; + +typedef struct CustomDataTransferLayerMap { + struct CustomDataTransferLayerMap *next, *prev; + + int data_type; + int mix_mode; + float mix_factor; + const float *mix_weights; /* If non-NULL, array of weights, one for each dest item, replaces mix_factor. */ + + void *data_src; /* Data source array (can be regular CD data, vertices/edges/etc., keyblocks...). */ + void *data_dst; /* Data dest array (same type as dat_src). */ + int data_src_n; /* Index to affect in data_src (used e.g. for vgroups). */ + int data_dst_n; /* Index to affect in data_dst (used e.g. for vgroups). */ + size_t elem_size; /* Size of one element of data_src/data_dst. */ + + size_t data_size; /* Size of actual data we transfer. */ + size_t data_offset; /* Offset of actual data we transfer (in element contained in data_src/dst). */ + uint64_t data_flag; /* For bitflag transfer, flag(s) to affect in transfered data. */ + + cd_datatransfer_interp interp; +} CustomDataTransferLayerMap; + +/* Those functions assume src_n and dst_n layers of given type exist in resp. src and dst. */ +void CustomData_data_transfer(const struct MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h new file mode 100644 index 00000000000..d31804b3cae --- /dev/null +++ b/source/blender/blenkernel/BKE_data_transfer.h @@ -0,0 +1,158 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/BKE_data_transfer.h + * \ingroup bke + */ + +#ifndef __BKE_DATA_TRANSFER_H__ +#define __BKE_DATA_TRANSFER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BKE_customdata.h" + +struct Object; +struct Scene; +struct SpaceTransform; +struct ReportList; + +/* Warning, those def are stored in files (TransferData modifier), *DO NOT* modify those values. */ +enum { + DT_TYPE_MDEFORMVERT = 1 << 0, + DT_TYPE_SHAPEKEY = 1 << 1, + DT_TYPE_SKIN = 1 << 2, + DT_TYPE_BWEIGHT_VERT = 1 << 3, + + DT_TYPE_SHARP_EDGE = 1 << 8, + DT_TYPE_SEAM = 1 << 9, + DT_TYPE_CREASE = 1 << 10, + DT_TYPE_BWEIGHT_EDGE = 1 << 11, + DT_TYPE_FREESTYLE_EDGE = 1 << 12, + + DT_TYPE_VCOL = 1 << 16, + + DT_TYPE_UV = 1 << 24, + DT_TYPE_SHARP_FACE = 1 << 25, + DT_TYPE_FREESTYLE_FACE = 1 << 26, +#define \ + DT_TYPE_MAX 27 + + DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT, + DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE | + DT_TYPE_FREESTYLE_EDGE, + DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_UV, + DT_TYPE_POLY_ALL = DT_TYPE_UV | DT_TYPE_SHARP_FACE | DT_TYPE_FREESTYLE_FACE, +}; + + +CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types); +bool BKE_object_data_transfer_get_dttypes_capacity( + const int dtdata_types, bool *r_advanced_mixing, bool *r_threshold); +int BKE_object_data_transfer_get_dttypes_item_types(const int dtdata_types); + +int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type); +int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type); + +#define DT_DATATYPE_IS_VERT(_dt) \ + ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT) +#define DT_DATATYPE_IS_EDGE(_dt) \ + ELEM(_dt, DT_TYPE_CREASE, DT_TYPE_SHARP_EDGE, DT_TYPE_SEAM, DT_TYPE_BWEIGHT_EDGE, DT_TYPE_FREESTYLE_EDGE) +#define DT_DATATYPE_IS_LOOP(_dt) \ + ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL) +#define DT_DATATYPE_IS_POLY(_dt) \ + ELEM(_dt, DT_TYPE_UV, DT_TYPE_SHARP_FACE, DT_TYPE_FREESTYLE_FACE) + +#define DT_DATATYPE_IS_MULTILAYERS(_dt) \ + ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_VCOL, DT_TYPE_UV) + + +enum { + DT_MULTILAYER_INDEX_INVALID = -1, + DT_MULTILAYER_INDEX_MDEFORMVERT = 0, + DT_MULTILAYER_INDEX_SHAPEKEY = 1, + DT_MULTILAYER_INDEX_VCOL = 2, + DT_MULTILAYER_INDEX_UV = 3, + DT_MULTILAYER_INDEX_MAX = 4, +}; + +/* Below we keep positive values for real layers idx (generated dynamically). */ + +/* How to select data layers, for types supporting multi-layers. + * Here too, some options are highly dependent on type of transferred data! */ +enum { + DT_LAYERS_ACTIVE_SRC = -1, + DT_LAYERS_ALL_SRC = -2, + /* Datatype-specific. */ + DT_LAYERS_VGROUP_SRC = 1 << 8, + DT_LAYERS_VGROUP_SRC_BONE_SELECT = -(DT_LAYERS_VGROUP_SRC | 1), + DT_LAYERS_VGROUP_SRC_BONE_DEFORM = -(DT_LAYERS_VGROUP_SRC | 2), + /* Other types-related modes... */ +}; + +/* How to map a source layer to a destination layer, for types supporting multi-layers. + * Note: if no matching layer can be found, it will be created. */ +enum { + DT_LAYERS_ACTIVE_DST = -1, /* Only for DT_LAYERS_FROMSEL_ACTIVE. */ + DT_LAYERS_NAME_DST = -2, + DT_LAYERS_INDEX_DST = -3, +#if 0 /* TODO */ + DT_LAYERS_CREATE_DST = -4, /* Never replace existing data in dst, always create new layers. */ +#endif +}; + +void BKE_object_data_transfer_layout( + struct Scene *scene, struct Object *ob_src, struct Object *ob_dst, const int data_types, const bool use_delete, + const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]); + +bool BKE_object_data_transfer_mesh( + struct Scene *scene, + struct Object *ob_src, struct Object *ob_dst, const int data_types, bool use_create, + const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, + struct SpaceTransform *space_transform, const float max_distance, const float ray_radius, + const float islands_handling_precision, + const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], + const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, + struct ReportList *reports); +bool BKE_object_data_transfer_dm( + struct Scene *scene, + struct Object *ob_src, struct Object *ob_dst, struct DerivedMesh *dm_dst, + const int data_types, bool use_create, + const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, + struct SpaceTransform *space_transform, const float max_distance, const float ray_radius, + const float islands_handling_precision, + const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], + const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, + struct ReportList *reports); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_DATA_TRANSFER_H__ */ diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index e203549fef5..08312035e40 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -39,6 +39,10 @@ struct Object; struct ListBase; struct bDeformGroup; struct MDeformVert; +struct MVert; +struct MEdge; +struct MLoop; +struct MPoly; struct bDeformGroup *BKE_defgroup_new(struct Object *ob, const char *name); void defgroup_copy_list(struct ListBase *lb1, struct ListBase *lb2); @@ -85,6 +89,19 @@ void defvert_normalize_lock_map(struct MDeformVert *dvert, const bool *vgroup_subset, const int vgroup_tot, const bool *lock_flags, const int defbase_tot); +/* Utilities to 'extract' a given vgroup into a simple float array, for verts, but also edges/polys/loops. */ +void BKE_defvert_extract_vgroup_to_vertweights( + struct MDeformVert *dvert, const int defgroup, const int num_verts, float *r_weights, const bool invert_vgroup); +void BKE_defvert_extract_vgroup_to_edgeweights( + struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MEdge *edges, const int num_edges, + float *r_weights, const bool invert_vgroup); +void BKE_defvert_extract_vgroup_to_loopweights( + struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops, + float *r_weights, const bool invert_vgroup); +void BKE_defvert_extract_vgroup_to_polyweights( + struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops, + struct MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup); + /* utility function, note that MAX_VGROUP_NAME chars is the maximum string length since its only * used with defgroups currently */ diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h index 168f700d132..3ee7dcd94b8 100644 --- a/source/blender/blenkernel/BKE_editmesh_bvh.h +++ b/source/blender/blenkernel/BKE_editmesh_bvh.h @@ -43,6 +43,8 @@ struct Scene; typedef struct BMBVHTree BMBVHTree; +typedef bool (*BMBVHTree_FaceFilter)(struct BMFace *f, void *userdata); + BMBVHTree *BKE_bmbvh_new_from_editmesh( struct BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free); @@ -55,8 +57,16 @@ BMBVHTree *BKE_bmbvh_new( const float (*cos_cage)[3], const bool cos_cage_free); void BKE_bmbvh_free(BMBVHTree *tree); struct BVHTree *BKE_bmbvh_tree_get(BMBVHTree *tree); -struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], const float radius, - float *r_dist, float r_hitout[3], float r_cagehit[3]); + +struct BMFace *BKE_bmbvh_ray_cast( + BMBVHTree *tree, const float co[3], const float dir[3], const float radius, + float *r_dist, float r_hitout[3], float r_cagehit[3]); + +struct BMFace *BKE_bmbvh_ray_cast_filter( + BMBVHTree *tree, const float co[3], const float dir[3], const float radius, + float *r_dist, float r_hitout[3], float r_cagehit[3], + BMBVHTree_FaceFilter filter, void *filter_cb); + /* find a face intersecting a segment (but not apart of the segment) */ struct BMFace *BKE_bmbvh_find_face_segment(BMBVHTree *tree, const float co_a[3], const float co_b[3], float *r_fac, float r_hitout[3], float r_cagehit[3]); diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 86c111653d1..084c5527f21 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -35,6 +35,7 @@ struct ListBase; struct bGPdata; struct bGPDlayer; struct bGPDframe; +struct bGPDstroke; /* ------------ Grease-Pencil API ------------------ */ @@ -43,17 +44,15 @@ void free_gpencil_frames(struct bGPDlayer *gpl); void free_gpencil_layers(struct ListBase *list); void BKE_gpencil_free(struct bGPdata *gpd); +void gpencil_stroke_sync_selection(struct bGPDstroke *gps); + struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe); struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, int setactive); struct bGPdata *gpencil_data_addnew(const char name[]); struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src); struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src); -struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd); - -//struct bGPdata *gpencil_data_getactive(struct ScrArea *sa); -//short gpencil_data_setactive(struct ScrArea *sa, struct bGPdata *gpd); -//struct ScrArea *gpencil_data_findowner(struct bGPdata *gpd); +struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd, bool internal_copy); void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 6d3d15e3565..5b10d7ebc06 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -40,18 +40,18 @@ typedef union IDPropertyTemplate { float f; double d; struct { - char *str; - short len; + const char *str; + int len; char subtype; } string; struct ID *id; struct { - short type; - short len; + int len; + char type; } array; struct { int matvec_size; - float *example; + const float *example; } matrix_or_vector; } IDPropertyTemplate; @@ -110,7 +110,7 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is bool IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) ATTR_WARN_UNUSED_RESULT; -struct IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void IDP_FreeProperty(struct IDProperty *prop); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index dc3d9f38b21..a225a27a00b 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -162,6 +162,7 @@ void BKE_image_alpha_mode_from_extension(struct Image *image); /* returns a new image or NULL if it can't load */ struct Image *BKE_image_load(struct Main *bmain, const char *filepath); /* returns existing Image when filename/type is same (frame optional) */ +struct Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists); struct Image *BKE_image_load_exists(const char *filepath); /* adds image, adds ibuf, generates color or pattern */ diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 31b2c7dc2b9..9535b921736 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -60,9 +60,11 @@ void key_curve_position_weights(float t, float data[4], int type); void key_curve_tangent_weights(float t, float data[4], int type); void key_curve_normal_weights(float t, float data[4], int type); -float *BKE_key_evaluate_object_ex(struct Scene *scene, struct Object *ob, int *r_totelem, - float *arr, size_t arr_size); -float *BKE_key_evaluate_object(struct Scene *scene, struct Object *ob, int *r_totelem); +float *BKE_key_evaluate_object_ex( + struct Object *ob, int *r_totelem, + float *arr, size_t arr_size); +float *BKE_key_evaluate_object( + struct Object *ob, int *r_totelem); struct Key *BKE_key_from_object(struct Object *ob); struct KeyBlock *BKE_keyblock_from_object(struct Object *ob); @@ -111,9 +113,6 @@ bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index); bool BKE_keyblock_is_basis(struct Key *key, const int index); -/* key.c */ -extern int slurph_opt; - #ifdef __cplusplus }; #endif diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index ed7e506941c..da44c989146 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -31,8 +31,9 @@ * \ingroup bke */ -struct MPoly; +struct MVert; struct MEdge; +struct MPoly; struct MLoop; struct MLoopUV; @@ -109,6 +110,10 @@ void BKE_mesh_vert_poly_map_create( MeshElemMap **r_map, int **r_mem, const struct MPoly *mface, const struct MLoop *mloop, int totvert, int totface, int totloop); +void BKE_mesh_vert_loop_map_create( + MeshElemMap **r_map, int **r_mem, + const struct MPoly *mface, const struct MLoop *mloop, + int totvert, int totface, int totloop); void BKE_mesh_vert_edge_map_create( MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge); @@ -122,7 +127,61 @@ void BKE_mesh_origindex_map_create( const int totorig, const int *final_origindex, const int totfinal); -/* smoothgroups */ + +/* islands */ + +/* Loop islands data helpers. */ +enum { + MISLAND_TYPE_NONE = 0, + MISLAND_TYPE_VERT = 1, + MISLAND_TYPE_EDGE = 2, + MISLAND_TYPE_POLY = 3, + MISLAND_TYPE_LOOP = 4, +}; + +typedef struct MeshIslandStore { + short item_type; /* MISLAND_TYPE_... */ + short island_type; /* MISLAND_TYPE_... */ + short innercut_type; /* MISLAND_TYPE_... */ + + int items_to_islands_num; + int *items_to_islands; /* map the item to the island index */ + + int islands_num; + size_t islands_num_alloc; + struct MeshElemMap **islands; /* Array of pointers, one item per island. */ + struct MeshElemMap **innercuts; /* Array of pointers, one item per island. */ + + struct MemArena *mem; /* Memory arena, internal use only. */ +} MeshIslandStore; + +void BKE_mesh_loop_islands_init( + MeshIslandStore *island_store, + const short item_type, const int item_num, const short island_type, const short innercut_type); +void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store); +void BKE_mesh_loop_islands_free(MeshIslandStore *island_store); +void BKE_mesh_loop_islands_add( + MeshIslandStore *islands, const int item_num, int *item_indices, + const int num_island_items, int *island_item_indices, + const int num_innercut_items, int *innercut_item_indices); + +typedef bool (*MeshRemapIslandsCalc)( + struct MVert *verts, const int totvert, + struct MEdge *edges, const int totedge, + struct MPoly *polys, const int totpoly, + struct MLoop *loops, const int totloop, + struct MeshIslandStore *r_island_store); + +/* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here. + * So better keep them separated for now, I think. + */ +bool BKE_mesh_calc_islands_loop_poly_uv( + struct MVert *verts, const int totvert, + struct MEdge *edges, const int totedge, + struct MPoly *polys, const int totpoly, + struct MLoop *loops, const int totloop, + MeshIslandStore *r_island_store); + int *BKE_mesh_calc_smoothgroups( const struct MEdge *medge, const int totedge, const struct MPoly *mpoly, const int totpoly, diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h new file mode 100644 index 00000000000..e1f37a63ff0 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_remap.h @@ -0,0 +1,171 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_MESH_REMAP_H__ +#define __BKE_MESH_REMAP_H__ + +/** \file BKE_mesh_remap.h + * \ingroup bke + */ + +struct CustomData; +struct DerivedMesh; +struct MVert; +struct MeshElemMap; +struct MemArena; + +/* Generic ways to map some geometry elements from a source mesh to a dest one. */ + +typedef struct MeshPairRemapItem { + int sources_num; + int *indices_src; /* NULL if no source found. */ + float *weights_src; /* NULL if no source found, else, always normalized! */ + /* UNUSED (at the moment)*/ + // float hit_dist; /* FLT_MAX if irrelevant or no source found. */ + int island; /* For loops only. */ +} MeshPairRemapItem; + +/* All mapping computing func return this. */ +typedef struct MeshPairRemap { + int items_num; + MeshPairRemapItem *items; /* array, one item per dest element. */ + + struct MemArena *mem; /* memory arena, internal use only. */ +} MeshPairRemap; + +/* Helpers! */ +void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num); +void BKE_mesh_remap_free(MeshPairRemap *map); + +void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index); + +/* TODO: + * Add other 'from/to' mapping sources, like e.g. using an UVMap, etc. + * http://blenderartists.org/forum/showthread.php?346458-Move-Vertices-to-the-location-of-the-Reference-Mesh-based-on-the-UV-Position + * We could also use similar topology mappings inside a same mesh + * (cf. Campbell's 'select face islands from similar topology' wip work). + * Also, users will have to check, whether we can get rid of some modes here, not sure all will be useful! + */ +enum { + MREMAP_USE_VERT = 1 << 4, + MREMAP_USE_EDGE = 1 << 5, + MREMAP_USE_LOOP = 1 << 6, + MREMAP_USE_POLY = 1 << 7, + + MREMAP_USE_NEAREST = 1 << 8, + MREMAP_USE_NORPROJ = 1 << 9, + MREMAP_USE_INTERP = 1 << 10, + MREMAP_USE_NORMAL = 1 << 11, + + /* ***** Target's vertices ***** */ + MREMAP_MODE_VERT = 1 << 24, + /* Nearest source vert. */ + MREMAP_MODE_VERT_NEAREST = MREMAP_MODE_VERT | MREMAP_USE_VERT | MREMAP_USE_NEAREST, + + /* Nearest vertex of nearest edge. */ + MREMAP_MODE_VERT_EDGE_NEAREST = MREMAP_MODE_VERT | MREMAP_USE_EDGE | MREMAP_USE_NEAREST, + /* This one uses two verts of selected edge (weighted interpolation). */ + /* Nearest point on nearest edge. */ + MREMAP_MODE_VERT_EDGEINTERP_NEAREST = MREMAP_MODE_VERT | MREMAP_USE_EDGE | MREMAP_USE_NEAREST | MREMAP_USE_INTERP, + + /* Nearest vertex of nearest poly. */ + MREMAP_MODE_VERT_POLY_NEAREST = MREMAP_MODE_VERT | MREMAP_USE_POLY | MREMAP_USE_NEAREST, + /* Those two use all verts of selected poly (weighted interpolation). */ + /* Nearest point on nearest poly. */ + MREMAP_MODE_VERT_POLYINTERP_NEAREST = MREMAP_MODE_VERT | MREMAP_USE_POLY | MREMAP_USE_NEAREST | MREMAP_USE_INTERP, + /* Point on nearest face hit by ray from target vertex's normal. */ + MREMAP_MODE_VERT_POLYINTERP_VNORPROJ = MREMAP_MODE_VERT | MREMAP_USE_POLY | MREMAP_USE_NORPROJ | MREMAP_USE_INTERP, + + /* ***** Target's edges ***** */ + MREMAP_MODE_EDGE = 1 << 25, + + /* Source edge which both vertices are nearest of dest ones. */ + MREMAP_MODE_EDGE_VERT_NEAREST = MREMAP_MODE_EDGE | MREMAP_USE_VERT | MREMAP_USE_NEAREST, + + /* Nearest source edge (using mid-point). */ + MREMAP_MODE_EDGE_NEAREST = MREMAP_MODE_EDGE | MREMAP_USE_EDGE | MREMAP_USE_NEAREST, + + /* Nearest edge of nearest poly (using mid-point). */ + MREMAP_MODE_EDGE_POLY_NEAREST = MREMAP_MODE_EDGE | MREMAP_USE_POLY | MREMAP_USE_NEAREST, + + /* Cast a set of rays from along dest edge, interpolating its vertices' normals, and use hit source edges. */ + MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ = MREMAP_MODE_EDGE | MREMAP_USE_VERT | MREMAP_USE_NORPROJ | MREMAP_USE_INTERP, + + /* ***** Target's loops ***** */ + /* Note: when islands are given to loop mapping func, all loops from the same destination face will always be mapped + * to loops of source faces within a same island, regardless of mapping mode. */ + MREMAP_MODE_LOOP = 1 << 26, + + /* Best normal-matching loop from nearest vert. */ + MREMAP_MODE_LOOP_NEAREST_LOOPNOR = MREMAP_MODE_LOOP | MREMAP_USE_LOOP | MREMAP_USE_VERT | MREMAP_USE_NEAREST | MREMAP_USE_NORMAL, + /* Loop from best normal-matching poly from nearest vert. */ + MREMAP_MODE_LOOP_NEAREST_POLYNOR = MREMAP_MODE_LOOP | MREMAP_USE_POLY | MREMAP_USE_VERT | MREMAP_USE_NEAREST | MREMAP_USE_NORMAL, + + /* Loop from nearest vertex of nearest poly. */ + MREMAP_MODE_LOOP_POLY_NEAREST = MREMAP_MODE_LOOP | MREMAP_USE_POLY | MREMAP_USE_NEAREST, + /* Those two use all verts of selected poly (weighted interpolation). */ + /* Nearest point on nearest poly. */ + MREMAP_MODE_LOOP_POLYINTERP_NEAREST = MREMAP_MODE_LOOP | MREMAP_USE_POLY | MREMAP_USE_NEAREST | MREMAP_USE_INTERP, + /* Point on nearest face hit by ray from target loop's normal. */ + MREMAP_MODE_LOOP_POLYINTERP_LNORPROJ = MREMAP_MODE_LOOP | MREMAP_USE_POLY | MREMAP_USE_NORPROJ | MREMAP_USE_INTERP, + + /* ***** Target's polygons ***** */ + MREMAP_MODE_POLY = 1 << 27, + + /* Nearest source poly. */ + MREMAP_MODE_POLY_NEAREST = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NEAREST, + /* Source poly from best normal-matching dest poly. */ + MREMAP_MODE_POLY_NOR = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NORMAL, + + /* Project dest poly onto source mesh using its normal, and use interpolation of all intersecting source polys. */ + MREMAP_MODE_POLY_POLYINTERP_PNORPROJ = MREMAP_MODE_POLY | MREMAP_USE_POLY | MREMAP_USE_NORPROJ | MREMAP_USE_INTERP, + + /* ***** Same topology, applies to all four elements types. ***** */ + MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY, +}; + +/* TODO add mesh2mesh versions (we'll need mesh versions of bvhtree funcs too, though!). */ + +void BKE_mesh_remap_calc_verts_from_dm( + const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, + const struct MVert *verts_dst, const int numverts_dst, const bool dirty_nors_dst, + struct DerivedMesh *dm_src, MeshPairRemap *r_map); + +void BKE_mesh_remap_calc_edges_from_dm( + const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, + const struct MVert *verts_dst, const int numverts_dst, const struct MEdge *edges_dst, const int numedges_dst, + const bool dirty_nors_dst, struct DerivedMesh *dm_src, MeshPairRemap *r_map); + +void BKE_mesh_remap_calc_loops_from_dm( + const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, + struct MVert *verts_dst, const int numverts_dst, struct MEdge *edges_dst, const int numedges_dst, + struct MLoop *loops_dst, const int numloops_dst, struct MPoly *polys_dst, const int numpolys_dst, + struct CustomData *ldata_dst, struct CustomData *pdata_dst, + const float split_angle_dst, const bool dirty_nors_dst, + struct DerivedMesh *dm_src, + MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, struct MeshPairRemap *r_map); + +void BKE_mesh_remap_calc_polys_from_dm( + const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, + struct MVert *verts_dst, const int numverts_dst, struct MLoop *loops_dst, const int numloops_dst, + struct MPoly *polys_dst, const int numpolys_dst, struct CustomData *pdata_dst, const bool dirty_nors_dst, + struct DerivedMesh *dm_src, struct MeshPairRemap *r_map); + +#endif /* __BKE_MESH_REMAP_H__ */ diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 341105cfdf7..a4aa58e22f1 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -46,6 +46,7 @@ void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip); struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); void BKE_movieclip_reload(struct MovieClip *clip); void BKE_movieclip_clear_cache(struct MovieClip *clip); +void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip); struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user); struct ImBuf *BKE_movieclip_get_postprocessed_ibuf(struct MovieClip *clip, struct MovieClipUser *user, int postprocess_flag); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index cb96538ad81..573fa60f703 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -485,6 +485,7 @@ void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *n void nodeSynchronizeID(struct bNode *node, bool copy_to_id); int nodeSocketIsHidden(struct bNodeSocket *sock); +void ntreeTagUsedSockets(struct bNodeTree *ntree); /* Node Clipboard */ void BKE_node_clipboard_init(struct bNodeTree *ntree); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 1bfd26d4f8c..1bdbc339f21 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -181,7 +181,7 @@ int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float * int BKE_object_insert_ptcache(struct Object *ob); void BKE_object_delete_ptcache(struct Object *ob, int index); -struct KeyBlock *BKE_object_insert_shape_key(struct Scene *scene, struct Object *ob, const char *name, const bool from_mix); +struct KeyBlock *BKE_object_insert_shape_key(struct Object *ob, const char *name, const bool from_mix); bool BKE_object_is_child_recursive(struct Object *ob_parent, struct Object *ob_child); bool BKE_object_is_animated(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h index 6de7ff9bc1c..e956815d6f7 100644 --- a/source/blender/blenkernel/BKE_object_deform.h +++ b/source/blender/blenkernel/BKE_object_deform.h @@ -29,10 +29,54 @@ * used by painting and tools. */ +#ifdef __cplusplus +extern "C" { +#endif + struct Object; +struct ID; +struct MDeformVert; +struct bDeformGroup; + +/* General vgroup operations */ +void BKE_object_defgroup_remap_update_users(struct Object *ob, int *map); + +bool BKE_object_defgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot); + +struct bDeformGroup *BKE_object_defgroup_add(struct Object *ob); +struct bDeformGroup *BKE_object_defgroup_add_name(struct Object *ob, const char *name); +struct MDeformVert *BKE_object_defgroup_data_create(struct ID *id); + +bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, const bool use_selection); +bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection); + +void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup); +void BKE_object_defgroup_remove_all(struct Object *ob); + + +/* Select helpers */ +enum eVGroupSelect; +bool *BKE_object_defgroup_subset_from_select_type( + struct Object *ob, enum eVGroupSelect subset_type, int *r_defgroup_tot, int *r_subset_count); +void BKE_object_defgroup_subset_to_index_array( + const bool *defgroup_validmap, const int defgroup_tot, int *r_defgroup_subset_map); + + +/* ********** */ + +bool *BKE_object_defgroup_lock_flags_get(struct Object *ob, const int defbase_tot); +bool *BKE_object_defgroup_validmap_get(struct Object *ob, const int defbase_tot); +bool *BKE_object_defgroup_selected_get(struct Object *ob, int defbase_tot, int *r_dg_flags_sel_tot); + +#ifdef __cplusplus +} +#endif + +/* Select helpers */ +bool *BKE_objdef_vgroup_subset_from_select_type( + struct Object *ob, enum eVGroupSelect subset_type, int *r_vgroup_tot, int *r_subset_count); +void BKE_objdef_vgroup_subset_to_index_array( + const bool *vgroup_validmap, const int vgroup_tot, int *r_vgroup_subset_map); -bool *BKE_objdef_lock_flags_get(struct Object *ob, const int defbase_tot); -bool *BKE_objdef_validmap_get(struct Object *ob, const int defbase_tot); -bool *BKE_objdef_selected_get(struct Object *ob, int defbase_tot, int *r_dg_flags_sel_tot); #endif /* __BKE_OBJECT_DEFORM_H__ */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index b080ca37e67..9ad99f726ff 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -109,7 +109,7 @@ void BKE_palette_cleanup(struct Palette *palette); struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); void BKE_paint_curve_free(struct PaintCurve *pc); -void BKE_paint_init(struct Paint *p, const char col[3]); +void BKE_paint_init(struct UnifiedPaintSettings *ups, struct Paint *p, const char col[3]); void BKE_paint_free(struct Paint *p); void BKE_paint_copy(struct Paint *src, struct Paint *tar); @@ -143,7 +143,9 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level, unsigned x, unsigned y); /* stroke related */ -void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, const float mouse_pos[2]); +void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]); + +void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); /* Session data (mode-specific) */ @@ -191,13 +193,6 @@ typedef struct SculptSession { struct SculptStroke *stroke; struct StrokeCache *cache; - - /* last paint/sculpt stroke location */ - bool last_stroke_valid; - float last_stroke[3]; - - float average_stroke_accum[3]; - int average_stroke_counter; } SculptSession; void BKE_free_sculptsession(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 49bc4e5f634..e56add721eb 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -364,7 +364,7 @@ void psys_get_pointcache_start_end(struct Scene *scene, ParticleSystem *psys, in void psys_check_boid_data(struct ParticleSystem *psys); -void psys_get_birth_coordinates(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra); +void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra); void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 188b8e22815..4c11ec9923d 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -280,6 +280,7 @@ void BKE_screen_area_free(struct ScrArea *sa); struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa); +struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min); unsigned int BKE_screen_view3d_layer_active_ex( diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index e460d0d8917..24e8d6362c1 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -102,8 +102,10 @@ typedef struct SeqRenderData { bool is_proxy_render; } SeqRenderData; -SeqRenderData BKE_sequencer_new_render_data(struct EvaluationContext *eval_ctx, struct Main *bmain, - struct Scene *scene, int rectx, int recty, int preview_render_size); +void BKE_sequencer_new_render_data( + struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *scene, + int rectx, int recty, int preview_render_size, + SeqRenderData *r_context); /* Wipe effect */ enum { @@ -377,12 +379,23 @@ struct Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine); void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq); void BKE_sequence_init_colorspace(struct Sequence *seq); +/* RNA enums, just to be more readable */ +enum { + SEQ_SIDE_NONE = 0, + SEQ_SIDE_LEFT, + SEQ_SIDE_RIGHT, + SEQ_SIDE_BOTH +}; +int BKE_sequencer_find_next_prev_edit( + struct Scene *scene, int cfra, const short side, + const bool do_skip_mute, const bool do_center, const bool do_unselected); + struct Sequence *BKE_sequencer_add_image_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load); struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load); struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load); /* view3d draw callback, run when not in background view */ -typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, int, char[256]); +typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, char[256]); extern SequencerDrawView sequencer_view3d_cb; /* copy/paste */ diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 50ca5fcdf7b..a4182b8405f 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -71,8 +71,6 @@ void sound_delete(struct Main *bmain, struct bSound *sound); void sound_cache(struct bSound *sound); -void sound_cache_notifying(struct Main *main, struct bSound *sound); - void sound_delete_cache(struct bSound *sound); void sound_load(struct Main *main, struct bSound *sound); @@ -132,7 +130,7 @@ int sound_scene_playing(struct Scene *scene); void sound_free_waveform(struct bSound *sound); -void sound_read_waveform(struct bSound *sound); +void sound_read_waveform(struct bSound *sound, short *stop); void sound_update_scene(struct Main *bmain, struct Scene *scene); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 1e79eaa8431..96e88f80464 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -51,7 +51,7 @@ int BKE_text_reload (struct Text *text); struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const char *relpath, const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); -struct Text *BKE_text_copy (struct Text *ta); +struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta); void BKE_text_unlink (struct Main *bmain, struct Text *text); void BKE_text_clear (struct Text *text); void BKE_text_write (struct Text *text, const char *str); diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index 5f5cb4c17cb..e5fb60cf1b5 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -145,6 +145,9 @@ void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_trac struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(struct MovieTrackingPlaneTrack *plane_track, int framenr); struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(struct MovieTrackingPlaneTrack *plane_track, int framenr); struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(struct MovieTrackingPlaneTrack *plane_track, int framenr); +void BKE_tracking_plane_marker_get_subframe_corners(struct MovieTrackingPlaneTrack *plane_track, + float framenr, + float corners[4][2]); /* **** Object **** */ struct MovieTrackingObject *BKE_tracking_object_add(struct MovieTracking *tracking, const char *name); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 353a3892f7d..328c465f07b 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -38,6 +38,7 @@ set(INC ../nodes ../pointcache ../render/extern/include + ../../../intern/ghost ../../../intern/guardedalloc ../../../intern/glew-mx ../../../intern/iksolver/extern @@ -64,6 +65,7 @@ set(SRC intern/addon.c intern/anim.c intern/anim_sys.c + intern/appdir.c intern/armature.c intern/autoexec.c intern/blender.c @@ -84,6 +86,7 @@ set(SRC intern/curve.c intern/customdata.c intern/customdata_file.c + intern/data_transfer.c intern/deform.c intern/depsgraph.c intern/displist.c @@ -120,6 +123,7 @@ set(SRC intern/mesh.c intern/mesh_evaluate.c intern/mesh_mapping.c + intern/mesh_remap.c intern/mesh_validate.c intern/modifier.c intern/modifiers_bmesh.c @@ -177,6 +181,7 @@ set(SRC BKE_addon.h BKE_anim.h BKE_animsys.h + BKE_appdir.h BKE_armature.h BKE_autoexec.h BKE_blender.h @@ -199,6 +204,7 @@ set(SRC BKE_curve.h BKE_customdata.h BKE_customdata_file.h + BKE_data_transfer.h BKE_deform.h BKE_depsgraph.h BKE_displist.h @@ -228,6 +234,7 @@ set(SRC BKE_mball.h BKE_mesh.h BKE_mesh_mapping.h + BKE_mesh_remap.h BKE_modifier.h BKE_movieclip.h BKE_multires.h @@ -273,10 +280,24 @@ set(SRC tracking_private.h intern/CCGSubSurf.h intern/pbvh_intern.h + intern/data_transfer_intern.h ) +if(WITH_BINRELOC) + list(APPEND INC_SYS + ${BINRELOC_INCLUDE_DIRS} + ) + add_definitions(-DWITH_BINRELOC) +endif() + add_definitions(${GL_DEFINITIONS}) +if(WIN32) + list(APPEND INC + ../../../intern/utfconv + ) +endif() + if(WITH_AUDASPACE) list(APPEND INC ../../../intern/audaspace/intern diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index e01d73c2718..6de55e276a1 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -46,6 +46,7 @@ incs = [ '#/intern/rigidbody', '#/extern/bullet2/src', env['BF_GLEW_INC'], + '#/intern/ghost', '#/intern/glew-mx', '#/intern/audaspace/intern', '#/intern/elbeem/extern', @@ -168,7 +169,11 @@ if env['WITH_BF_FREESTYLE']: if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] + incs += ' ../../../intern/utfconv' +if env['WITH_BF_BINRELOC']: + incs += ' #extern/binreloc/include' + defs.append('WITH_BINRELOC') if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [166,25]) #, cc_compileflags = env['CCFLAGS'].append('/WX') ) diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 623fb50b62c..9e5d4afffe2 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -172,29 +172,19 @@ static void *_ehash_lookup(EHash *eh, void *key) /**/ -typedef struct _EHashIterator { - EHash *eh; - int curBucket; - EHEntry *curEntry; -} EHashIterator; - -static EHashIterator *_ehashIterator_new(EHash *eh) +static void _ehashIterator_init(EHash *eh, EHashIterator *ehi) { - EHashIterator *ehi = EHASH_alloc(eh, sizeof(*ehi)); + /* fill all members */ ehi->eh = eh; - ehi->curEntry = NULL; ehi->curBucket = -1; + ehi->curEntry = NULL; + while (!ehi->curEntry) { ehi->curBucket++; if (ehi->curBucket == ehi->eh->curSize) break; ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; } - return ehi; -} -static void _ehashIterator_free(EHashIterator *ehi) -{ - EHASH_free(ehi->eh, ehi); } static void *_ehashIterator_getCurrent(EHashIterator *ehi) @@ -3051,17 +3041,17 @@ void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int /*** External API iterator functions ***/ -CCGVertIterator *ccgSubSurf_getVertIterator(CCGSubSurf *ss) +void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter) { - return (CCGVertIterator *) _ehashIterator_new(ss->vMap); + _ehashIterator_init(ss->vMap, viter); } -CCGEdgeIterator *ccgSubSurf_getEdgeIterator(CCGSubSurf *ss) +void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter) { - return (CCGEdgeIterator *) _ehashIterator_new(ss->eMap); + _ehashIterator_init(ss->eMap, eiter); } -CCGFaceIterator *ccgSubSurf_getFaceIterator(CCGSubSurf *ss) +void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter) { - return (CCGFaceIterator *) _ehashIterator_new(ss->fMap); + _ehashIterator_init(ss->fMap, fiter); } CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) @@ -3076,10 +3066,6 @@ void ccgVertIterator_next(CCGVertIterator *vi) { _ehashIterator_next((EHashIterator *) vi); } -void ccgVertIterator_free(CCGVertIterator *vi) -{ - _ehashIterator_free((EHashIterator *) vi); -} CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi) { @@ -3093,10 +3079,6 @@ void ccgEdgeIterator_next(CCGEdgeIterator *vi) { _ehashIterator_next((EHashIterator *) vi); } -void ccgEdgeIterator_free(CCGEdgeIterator *vi) -{ - _ehashIterator_free((EHashIterator *) vi); -} CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi) { @@ -3110,10 +3092,6 @@ void ccgFaceIterator_next(CCGFaceIterator *vi) { _ehashIterator_next((EHashIterator *) vi); } -void ccgFaceIterator_free(CCGFaceIterator *vi) -{ - _ehashIterator_free((EHashIterator *) vi); -} /*** Extern API final vert/edge/face interface ***/ diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index fdf6d2df99f..2b86a2a66b2 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -53,6 +53,13 @@ typedef struct CCGAllocatorIFC { void (*release) (CCGAllocatorHDL a); } CCGAllocatorIFC; +/* private, so we can allocate on the stack */ +typedef struct _EHashIterator { + struct _EHash *eh; + int curBucket; + struct _EHEntry *curEntry; +} EHashIterator; + /***/ typedef enum { @@ -163,27 +170,24 @@ int ccgSubSurf_getNumFinalFaces (const CCGSubSurf *ss); /***/ -typedef struct CCGVertIterator CCGVertIterator; -typedef struct CCGEdgeIterator CCGEdgeIterator; -typedef struct CCGFaceIterator CCGFaceIterator; +typedef struct _EHashIterator CCGVertIterator; +typedef struct _EHashIterator CCGEdgeIterator; +typedef struct _EHashIterator CCGFaceIterator; -CCGVertIterator* ccgSubSurf_getVertIterator (CCGSubSurf *ss); -CCGEdgeIterator* ccgSubSurf_getEdgeIterator (CCGSubSurf *ss); -CCGFaceIterator* ccgSubSurf_getFaceIterator (CCGSubSurf *ss); +void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter); +void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter); +void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter); CCGVert* ccgVertIterator_getCurrent (CCGVertIterator *vi); int ccgVertIterator_isStopped (CCGVertIterator *vi); void ccgVertIterator_next (CCGVertIterator *vi); -void ccgVertIterator_free (CCGVertIterator *vi); CCGEdge* ccgEdgeIterator_getCurrent (CCGEdgeIterator *ei); int ccgEdgeIterator_isStopped (CCGEdgeIterator *ei); void ccgEdgeIterator_next (CCGEdgeIterator *ei); -void ccgEdgeIterator_free (CCGEdgeIterator *ei); CCGFace* ccgFaceIterator_getCurrent (CCGFaceIterator *fi); int ccgFaceIterator_isStopped (CCGFaceIterator *fi); void ccgFaceIterator_next (CCGFaceIterator *fi); -void ccgFaceIterator_free (CCGFaceIterator *fi); #endif /* __CCGSUBSURF_H__ */ diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 2a52376aa2d..9cc99a07353 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -75,13 +75,11 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); #include "BLI_sys_types.h" /* for intptr_t support */ #include "GPU_buffers.h" -#include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_glew.h" -#include "GPU_material.h" /* very slow! enable for testing only! */ -// #define USE_MODIFIER_VALIDATE +//#define USE_MODIFIER_VALIDATE #ifdef USE_MODIFIER_VALIDATE # define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true))) @@ -1230,7 +1228,7 @@ static void calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, int const d bool *defbase_sel = NULL; if (draw_flag & CALC_WP_MULTIPAINT) { - defbase_sel = BKE_objdef_selected_get(ob, defbase_tot, &defbase_sel_tot); + defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_sel_tot); } for (i = numVerts; i != 0; i--, wc++, dv++) { @@ -1453,8 +1451,10 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob)) */ static void dm_ensure_display_normals(DerivedMesh *dm) { - /* this is for final output only, up until now this layer should be missing */ - BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); + /* Note: dm *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.). + * We do not use it here, though. And it should be tagged as temp! + */ + /* BLI_assert((CustomData_has_layer(&dm->polyData, CD_NORMAL) == false)); */ if ((dm->type == DM_TYPE_CDDM) && ((dm->dirty & DM_DIRTY_NORMALS) || CustomData_has_layer(&dm->faceData, CD_NORMAL) == false)) @@ -1539,8 +1539,8 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); const bool has_multires = (mmd && mmd->sculptlvl != 0); bool multires_applied = false; - const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt; - const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm); + const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !useRenderParams; + const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !useRenderParams; const int draw_flag = dm_drawflag_calc(scene->toolsettings); /* Generic preview only in object mode! */ @@ -2021,10 +2021,10 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh * if (!modifier_isEnabled(scene, md, required_mode)) return 0; if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { modifier_setError(md, "Modifier requires original data, bad stack position"); - return 0; + return false; } - return 1; + return true; } static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, DerivedMesh **cage_r, @@ -2555,7 +2555,9 @@ DerivedMesh *object_get_derived_final(Object *ob, const bool for_render) return ob->derivedFinal; } - if (em) { + /* only return the editmesh if its from this object because + * we don't a mesh from another object's modifier stack: T43122 */ + if (em && (em->ob == ob)) { DerivedMesh *dm = em->derivedFinal; return dm; } @@ -3369,7 +3371,7 @@ static void dm_debug_info_layers(DynStr *dynstr, DerivedMesh *dm, CustomData *cd CustomData_file_write_info(type, &structname, &structnum); BLI_dynstr_appendf(dynstr, " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", - name, structname, type, (void *)pt, size, pt_size); + name, structname, type, (const void *)pt, size, pt_size); } } } @@ -3433,7 +3435,7 @@ void DM_debug_print(DerivedMesh *dm) void DM_debug_print_cdlayers(CustomData *data) { int i; - CustomDataLayer *layer; + const CustomDataLayer *layer; printf("{\n"); @@ -3445,7 +3447,7 @@ void DM_debug_print_cdlayers(CustomData *data) int structnum; CustomData_file_write_info(layer->type, &structname, &structnum); printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", - name, structname, layer->type, (void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size)); + name, structname, layer->type, (const void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size)); } printf("}\n"); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index e753a7f7948..f94f1e72638 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -215,6 +215,10 @@ bAction *BKE_action_copy(bAction *src) } } + if (src->id.lib) { + BKE_id_lib_local_paths(G.main, src->id.lib, &dst->id); + } + return dst; } @@ -450,9 +454,9 @@ bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name) return NULL; if (pose->chanhash) - return BLI_ghash_lookup(pose->chanhash, (void *)name); + return BLI_ghash_lookup(pose->chanhash, (const void *)name); - return BLI_findstring(&((bPose *)pose)->chanbase, name, offsetof(bPoseChannel, name)); + return BLI_findstring(&((const bPose *)pose)->chanbase, name, offsetof(bPoseChannel, name)); } /** @@ -1028,12 +1032,12 @@ bool action_has_motion(const bAction *act) if (act) { for (fcu = act->curves.first; fcu; fcu = fcu->next) { if (fcu->totvert) - return 1; + return true; } } /* nothing found */ - return 0; + return false; } /* Calculate the extents of given action */ diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c index 119fa266908..28667d458b8 100644 --- a/source/blender/blenkernel/intern/addon.c +++ b/source/blender/blenkernel/intern/addon.c @@ -29,15 +29,9 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" -#include "BLI_string.h" #include "BKE_addon.h" /* own include */ -#include "RNA_access.h" -#include "RNA_define.h" - -#include "BLF_translation.h" - #include "MEM_guardedalloc.h" static GHash *global_addonpreftype_hash = NULL; diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 2fb832dc72d..8e36449f214 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -83,7 +83,7 @@ bool id_type_can_have_animdata(ID *id) { /* sanity check */ if (id == NULL) - return 0; + return false; /* Only some ID-blocks have this info for now */ /* TODO: finish adding this for the other blocktypes */ @@ -100,13 +100,14 @@ bool id_type_can_have_animdata(ID *id) case ID_SCE: case ID_MC: case ID_MSK: + case ID_GD: { - return 1; + return true; } /* no AnimData */ default: - return 0; + return false; } } @@ -193,20 +194,20 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act) /* can set */ adt->action = act; id_us_plus((ID *)adt->action); - ok = 1; + ok = true; } else { /* cannot set */ BKE_reportf(reports, RPT_ERROR, "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths " "for this purpose", act->id.name + 2, id->name); - /* ok = 0; */ + /* ok = false; */ } } else { /* just clearing the action... */ adt->action = NULL; - ok = 1; + ok = true; } return ok; @@ -289,7 +290,7 @@ bool BKE_copy_animdata_id(ID *id_to, ID *id_from, const bool do_action) AnimData *adt; if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) - return 0; + return false; BKE_free_animdata(id_to); @@ -299,7 +300,7 @@ bool BKE_copy_animdata_id(ID *id_to, ID *id_from, const bool do_action) iat->adt = BKE_copy_animdata(adt, do_action); } - return 1; + return true; } void BKE_copy_animdata_id_action(ID *id) @@ -1031,6 +1032,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u /* line styles */ ANIMDATA_IDS_CB(mainptr->linestyle.first); + + /* grease pencil */ + ANIMDATA_IDS_CB(mainptr->gpencil.first); } /* Fix all RNA-Paths throughout the database (directly access the Global.main version) @@ -1119,6 +1123,9 @@ void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const cha /* linestyles */ RENAMEFIX_ANIM_IDS(mainptr->linestyle.first); + /* grease pencil */ + RENAMEFIX_ANIM_IDS(mainptr->gpencil.first); + /* scenes */ RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene); } @@ -1346,11 +1353,11 @@ static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst /* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */ *dst = path; - return 0; + return false; } -/* less then 1.0 evaluates to false, use epsilon to avoid float error */ +/* less than 1.0 evaluates to false, use epsilon to avoid float error */ #define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON))) /* Write the given value to a setting using RNA, and return success */ @@ -1375,7 +1382,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind path, array_index, array_len - 1); } - return 0; + return false; } switch (RNA_property_type(prop)) { @@ -1429,7 +1436,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind break; default: /* nothing can be done here... so it is unsuccessful? */ - return 0; + return false; } /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */ @@ -1468,7 +1475,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind } /* successful */ - return 1; + return true; } else { /* failed to get path */ @@ -1479,7 +1486,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", path, array_index); } - return 0; + return false; } } @@ -2680,6 +2687,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) /* linestyles */ EVAL_ANIM_IDS(main->linestyle.first, ADT_RECALC_ANIM); + /* grease pencil */ + EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM); + /* objects */ /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets * this tagged by Depsgraph on framechange. This optimization means that objects diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c new file mode 100644 index 00000000000..50f9a9be05d --- /dev/null +++ b/source/blender/blenkernel/intern/appdir.c @@ -0,0 +1,808 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 blender/blenlib/intern/appdir.c + * \ingroup bke + * + * Access to application level directories. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "BLI_utildefines.h" +#include "BLI_string.h" +#include "BLI_fileops.h" +#include "BLI_path_util.h" + +#include "BKE_appdir.h" /* own include */ + +#include "GHOST_Path-api.h" + +#include "../blenkernel/BKE_blender.h" /* BLENDER_VERSION, bad level include (no function call) */ + +#include "MEM_guardedalloc.h" + +#ifdef WIN32 +# include "utf_winfunc.h" +# include "utfconv.h" +# include <io.h> +# ifdef _WIN32_IE +# undef _WIN32_IE +# endif +# define _WIN32_IE 0x0501 +# include <windows.h> +# include <shlobj.h> +# include "BLI_winstuff.h" +#else /* non windows */ +# ifdef WITH_BINRELOC +# include "binreloc.h" +# endif +# include <unistd.h> /* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */ +#endif /* WIN32 */ + +/* local */ +static char bprogname[FILE_MAX]; /* full path to program executable */ +static char bprogdir[FILE_MAX]; /* full path to directory in which executable is located */ +static char btempdir_base[FILE_MAX]; /* persistent temporary directory */ +static char btempdir_session[FILE_MAX] = ""; /* volatile temporary directory */ + +/* This is now only used to really get the user's default document folder */ +/* On Windows I chose the 'Users/<MyUserName>/Documents' since it's used + * as default location to save documents */ +const char *BKE_appdir_folder_default(void) +{ +#ifndef WIN32 + const char * const xdg_documents_dir = getenv("XDG_DOCUMENTS_DIR"); + + if (xdg_documents_dir) + return xdg_documents_dir; + + return getenv("HOME"); +#else /* Windows */ + static char documentfolder[MAXPATHLEN]; + HRESULT hResult; + + /* Check for %HOME% env var */ + if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) { + if (BLI_is_dir(documentfolder)) return documentfolder; + } + + /* add user profile support for WIN 2K / NT. + * This is %APPDATA%, which translates to either + * %USERPROFILE%\Application Data or since Vista + * to %USERPROFILE%\AppData\Roaming + */ + hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder); + + if (hResult == S_OK) { + if (BLI_is_dir(documentfolder)) return documentfolder; + } + + return NULL; +#endif /* WIN32 */ +} + + +// #define PATH_DEBUG + +/* returns a formatted representation of the specified version number. Non-reentrant! */ +static char *blender_version_decimal(const int ver) +{ + static char version_str[5]; + sprintf(version_str, "%d.%02d", ver / 100, ver % 100); + return version_str; +} + +/** + * Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath, + * returning true if result points to a directory. + */ +static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name) +{ + char tmppath[FILE_MAX]; + + if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep); + else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); + + /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */ + if (folder_name) + BLI_make_file_string("/", targetpath, tmppath, folder_name); + else + BLI_strncpy(targetpath, tmppath, sizeof(tmppath)); + /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile) + * if folder_name is specified but not otherwise? */ + + if (BLI_is_dir(targetpath)) { +#ifdef PATH_DEBUG + printf("\t%s found: %s\n", __func__, targetpath); +#endif + return true; + } + else { +#ifdef PATH_DEBUG + printf("\t%s missing: %s\n", __func__, targetpath); +#endif + //targetpath[0] = '\0'; + return false; + } +} + +/** + * Puts the value of the specified environment variable into *path if it exists + * and points at a directory. Returns true if this was done. + */ +static bool test_env_path(char *path, const char *envvar) +{ + const char *env = envvar ? getenv(envvar) : NULL; + if (!env) return false; + + if (BLI_is_dir(env)) { + BLI_strncpy(path, env, FILE_MAX); +#ifdef PATH_DEBUG + printf("\t%s env %s found: %s\n", __func__, envvar, env); +#endif + return true; + } + else { + path[0] = '\0'; +#ifdef PATH_DEBUG + printf("\t%s env %s missing: %s\n", __func__, envvar, env); +#endif + return false; + } +} + +/** + * Constructs in \a targetpath the name of a directory relative to a version-specific + * subdirectory in the parent directory of the Blender executable. + * + * \param targetpath String to return path + * \param folder_name Optional folder name within version-specific directory + * \param subfolder_name Optional subfolder name within folder_name + * \param ver To construct name of version-specific directory within bprogdir + * \return true if such a directory exists. + */ +static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver) +{ + char relfolder[FILE_MAX]; + +#ifdef PATH_DEBUG + printf("%s...\n", __func__); +#endif + + if (folder_name) { + if (subfolder_name) { + BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name); + } + else { + BLI_strncpy(relfolder, folder_name, sizeof(relfolder)); + } + } + else { + relfolder[0] = '\0'; + } + + /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ +#ifdef __APPLE__ + static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */ + sprintf(osx_resourses, "%s../Resources", bprogdir); + return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder); +#else + return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder); +#endif +} + +/** + * Is this an install with user files kept together with the Blender executable and its + * installation files. + */ +static bool is_portable_install(void) +{ + /* detect portable install by the existence of config folder */ + const int ver = BLENDER_VERSION; + char path[FILE_MAX]; + + return get_path_local(path, "config", NULL, ver); +} + +/** + * Returns the path of a folder within the user-files area. + * + * + * \param targetpath String to return path + * \param folder_name default name of folder within user area + * \param subfolder_name optional name of subfolder within folder + * \param envvar name of environment variable which, if defined, overrides folder_name + * \param ver Blender version, used to construct a subdirectory name + * \return true if it was able to construct such a path. + */ +static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) +{ + char user_path[FILE_MAX]; + const char *user_base_path; + + /* for portable install, user path is always local */ + if (is_portable_install()) + return get_path_local(targetpath, folder_name, subfolder_name, ver); + + user_path[0] = '\0'; + + if (test_env_path(user_path, envvar)) { + if (subfolder_name) { + return test_path(targetpath, user_path, NULL, subfolder_name); + } + else { + BLI_strncpy(targetpath, user_path, FILE_MAX); + return true; + } + } + + user_base_path = (const char *)GHOST_getUserDir(ver, blender_version_decimal(ver)); + if (user_base_path) + BLI_strncpy(user_path, user_base_path, FILE_MAX); + + if (!user_path[0]) + return false; + +#ifdef PATH_DEBUG + printf("%s: %s\n", __func__, user_path); +#endif + + if (subfolder_name) { + return test_path(targetpath, user_path, folder_name, subfolder_name); + } + else { + return test_path(targetpath, user_path, NULL, folder_name); + } +} + +/** + * Returns the path of a folder within the Blender installation directory. + * + * \param targetpath String to return path + * \param folder_name default name of folder within installation area + * \param subfolder_name optional name of subfolder within folder + * \param envvar name of environment variable which, if defined, overrides folder_name + * \param ver Blender version, used to construct a subdirectory name + * \return true if it was able to construct such a path. + */ +static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) +{ + char system_path[FILE_MAX]; + const char *system_base_path; + char cwd[FILE_MAX]; + char relfolder[FILE_MAX]; + + if (folder_name) { + if (subfolder_name) { + BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name); + } + else { + BLI_strncpy(relfolder, folder_name, sizeof(relfolder)); + } + } + else { + relfolder[0] = '\0'; + } + + /* first allow developer only overrides to the system path + * these are only used when running blender from source */ + + /* try CWD/release/folder_name */ + if (BLI_current_working_dir(cwd, sizeof(cwd))) { + if (test_path(targetpath, cwd, "release", relfolder)) { + return true; + } + } + + /* try EXECUTABLE_DIR/release/folder_name */ + if (test_path(targetpath, bprogdir, "release", relfolder)) + return true; + + /* end developer overrides */ + + + + system_path[0] = '\0'; + + if (test_env_path(system_path, envvar)) { + if (subfolder_name) { + return test_path(targetpath, system_path, NULL, subfolder_name); + } + else { + BLI_strncpy(targetpath, system_path, FILE_MAX); + return true; + } + } + + system_base_path = (const char *)GHOST_getSystemDir(ver, blender_version_decimal(ver)); + if (system_base_path) + BLI_strncpy(system_path, system_base_path, FILE_MAX); + + if (!system_path[0]) + return false; + +#ifdef PATH_DEBUG + printf("%s: %s\n", __func__, system_path); +#endif + + if (subfolder_name) { + /* try $BLENDERPATH/folder_name/subfolder_name */ + return test_path(targetpath, system_path, folder_name, subfolder_name); + } + else { + /* try $BLENDERPATH/folder_name */ + return test_path(targetpath, system_path, NULL, folder_name); + } +} + +/* get a folder out of the 'folder_id' presets for paths */ +/* returns the path if found, NULL string if not */ +const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder) +{ + const int ver = BLENDER_VERSION; + static char path[FILE_MAX] = ""; + + switch (folder_id) { + case BLENDER_DATAFILES: /* general case */ + if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; + if (get_path_local(path, "datafiles", subfolder, ver)) break; + if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; + return NULL; + + case BLENDER_USER_DATAFILES: + if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; + return NULL; + + case BLENDER_SYSTEM_DATAFILES: + if (get_path_local(path, "datafiles", subfolder, ver)) break; + if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; + return NULL; + + case BLENDER_USER_AUTOSAVE: + if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break; + return NULL; + + case BLENDER_USER_CONFIG: + if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break; + return NULL; + + case BLENDER_USER_SCRIPTS: + if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break; + return NULL; + + case BLENDER_SYSTEM_SCRIPTS: + if (get_path_local(path, "scripts", subfolder, ver)) break; + if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break; + return NULL; + + case BLENDER_SYSTEM_PYTHON: + if (get_path_local(path, "python", subfolder, ver)) break; + if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break; + return NULL; + + default: + BLI_assert(0); + break; + } + + return path; +} + +/** + * Returns the path to a folder in the user area without checking that it actually exists first. + */ +const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder) +{ + const int ver = BLENDER_VERSION; + static char path[FILE_MAX] = ""; + + switch (folder_id) { + case BLENDER_USER_DATAFILES: + get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver); + break; + case BLENDER_USER_CONFIG: + get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver); + break; + case BLENDER_USER_AUTOSAVE: + get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver); + break; + case BLENDER_USER_SCRIPTS: + get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver); + break; + default: + BLI_assert(0); + break; + } + + if ('\0' == path[0]) { + return NULL; + } + return path; +} + +/** + * Returns the path to a folder in the user area, creating it if it doesn't exist. + */ +const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder) +{ + const char *path; + + /* only for user folders */ + if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) + return NULL; + + path = BKE_appdir_folder_id(folder_id, subfolder); + + if (!path) { + path = BKE_appdir_folder_id_user_notest(folder_id, subfolder); + if (path) BLI_dir_create_recursive(path); + } + + return path; +} + +/** + * Returns the path of the top-level version-specific local, user or system directory. + * If do_check, then the result will be NULL if the directory doesn't exist. + */ +const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check) +{ + static char path[FILE_MAX] = ""; + bool ok; + switch (folder_id) { + case BLENDER_RESOURCE_PATH_USER: + ok = get_path_user(path, NULL, NULL, NULL, ver); + break; + case BLENDER_RESOURCE_PATH_LOCAL: + ok = get_path_local(path, NULL, NULL, ver); + break; + case BLENDER_RESOURCE_PATH_SYSTEM: + ok = get_path_system(path, NULL, NULL, NULL, ver); + break; + default: + path[0] = '\0'; /* in case do_check is false */ + ok = false; + BLI_assert(!"incorrect ID"); + break; + } + + if (!ok && do_check) { + return NULL; + } + + return path; +} + +#ifdef PATH_DEBUG +# undef PATH_DEBUG +#endif + + +/* -------------------------------------------------------------------- */ +/* Preset paths */ + +/** + * Tries appending each of the semicolon-separated extensions in the PATHEXT + * environment variable (Windows-only) onto *name in turn until such a file is found. + * Returns success/failure. + */ +static int add_win32_extension(char *name) +{ + int retval = 0; + int type; + + type = BLI_exists(name); + if ((type == 0) || S_ISDIR(type)) { +#ifdef _WIN32 + char filename[FILE_MAX]; + char ext[FILE_MAX]; + const char *extensions = getenv("PATHEXT"); + if (extensions) { + char *temp; + do { + strcpy(filename, name); + temp = strstr(extensions, ";"); + if (temp) { + strncpy(ext, extensions, temp - extensions); + ext[temp - extensions] = 0; + extensions = temp + 1; + strcat(filename, ext); + } + else { + strcat(filename, extensions); + } + + type = BLI_exists(filename); + if (type && (!S_ISDIR(type))) { + retval = 1; + strcpy(name, filename); + break; + } + } while (temp); + } +#endif + } + else { + retval = 1; + } + + return (retval); +} + +/** + * Checks if name is a fully qualified filename to an executable. + * If not it searches $PATH for the file. On Windows it also + * adds the correct extension (.com .exe etc) from + * $PATHEXT if necessary. Also on Windows it translates + * the name to its 8.3 version to prevent problems with + * spaces and stuff. Final result is returned in fullname. + * + * \param fullname The full path and full name of the executable + * (must be FILE_MAX minimum) + * \param name The name of the executable (usually argv[0]) to be checked + */ +static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name) +{ + char filename[FILE_MAX]; + const char *path = NULL, *temp; + +#ifdef _WIN32 + const char *separator = ";"; +#else + const char *separator = ":"; +#endif + + +#ifdef WITH_BINRELOC + /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */ + path = br_find_exe(NULL); + if (path) { + BLI_strncpy(fullname, path, maxlen); + free((void *)path); + return; + } +#endif + +#ifdef _WIN32 + wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath"); + if (GetModuleFileNameW(0, fullname_16, maxlen)) { + conv_utf_16_to_8(fullname_16, fullname, maxlen); + if (!BLI_exists(fullname)) { + printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname); + MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); + } + MEM_freeN(fullname_16); + return; + } + + MEM_freeN(fullname_16); +#endif + + /* unix and non linux */ + if (name && name[0]) { + + BLI_strncpy(fullname, name, maxlen); + if (name[0] == '.') { + char wdir[FILE_MAX] = ""; + BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */ + + // not needed but avoids annoying /./ in name + if (name[1] == SEP) + BLI_join_dirfile(fullname, maxlen, wdir, name + 2); + else + BLI_join_dirfile(fullname, maxlen, wdir, name); + + add_win32_extension(fullname); /* XXX, doesnt respect length */ + } + else if (BLI_last_slash(name)) { + // full path + BLI_strncpy(fullname, name, maxlen); + add_win32_extension(fullname); + } + else { + // search for binary in $PATH + path = getenv("PATH"); + if (path) { + do { + temp = strstr(path, separator); + if (temp) { + strncpy(filename, path, temp - path); + filename[temp - path] = 0; + path = temp + 1; + } + else { + strncpy(filename, path, sizeof(filename)); + } + BLI_path_append(fullname, maxlen, name); + if (add_win32_extension(filename)) { + BLI_strncpy(fullname, filename, maxlen); + break; + } + } while (temp); + } + } +#if defined(DEBUG) + if (strcmp(name, fullname)) { + printf("guessing '%s' == '%s'\n", name, fullname); + } +#endif + } +} + +void BKE_appdir_program_path_init(const char *argv0) +{ + bli_where_am_i(bprogname, sizeof(bprogname), argv0); + BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir)); +} + +/** + * Path to executable + */ +const char *BKE_appdir_program_path(void) +{ + return bprogname; +} + +/** + * Path to directory of executable + */ +const char *BKE_appdir_program_dir(void) +{ + return bprogdir; +} + +/** + * Gets the temp directory when blender first runs. + * If the default path is not found, use try $TEMP + * + * Also make sure the temp dir has a trailing slash + * + * \param fullname The full path to the temporary temp directory + * \param basename The full path to the persistent temp directory (may be NULL) + * \param maxlen The size of the fullname buffer + * \param userdir Directory specified in user preferences + */ +static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir) +{ + /* Clear existing temp dir, if needed. */ + BKE_tempdir_session_purge(); + + fullname[0] = '\0'; + if (basename) { + basename[0] = '\0'; + } + + if (userdir && BLI_is_dir(userdir)) { + BLI_strncpy(fullname, userdir, maxlen); + } + + +#ifdef WIN32 + if (fullname[0] == '\0') { + const char *tmp = getenv("TEMP"); /* Windows */ + if (tmp && BLI_is_dir(tmp)) { + BLI_strncpy(fullname, tmp, maxlen); + } + } +#else + /* Other OS's - Try TMP and TMPDIR */ + if (fullname[0] == '\0') { + const char *tmp = getenv("TMP"); + if (tmp && BLI_is_dir(tmp)) { + BLI_strncpy(fullname, tmp, maxlen); + } + } + + if (fullname[0] == '\0') { + const char *tmp = getenv("TMPDIR"); + if (tmp && BLI_is_dir(tmp)) { + BLI_strncpy(fullname, tmp, maxlen); + } + } +#endif + + if (fullname[0] == '\0') { + BLI_strncpy(fullname, "/tmp/", maxlen); + } + else { + /* add a trailing slash if needed */ + BLI_add_slash(fullname); +#ifdef WIN32 + if (userdir && userdir != fullname) { + BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */ + } +#endif + } + + /* Now that we have a valid temp dir, add system-generated unique sub-dir. */ + if (basename) { + /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */ + char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX"); + const size_t ln = strlen(tmp_name) + 1; + if (ln <= maxlen) { +#ifdef WIN32 + if (_mktemp_s(tmp_name, ln) == 0) { + BLI_dir_create_recursive(tmp_name); + } +#else + mkdtemp(tmp_name); +#endif + } + if (BLI_is_dir(tmp_name)) { + BLI_strncpy(basename, fullname, maxlen); + BLI_strncpy(fullname, tmp_name, maxlen); + BLI_add_slash(fullname); + } + else { + printf("Warning! Could not generate a temp file name for '%s', falling back to '%s'\n", tmp_name, fullname); + } + + MEM_freeN(tmp_name); + } +} + +/** + * Sets btempdir_base to userdir if specified and is a valid directory, otherwise + * chooses a suitable OS-specific temporary directory. + * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base. + * + * \note On Window userdir will be set to the temporary directory! + */ +void BKE_tempdir_init(char *userdir) +{ + BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir); +; +} + +/** + * Path to temporary directory (with trailing slash) + */ +const char *BKE_tempdir_session(void) +{ + return btempdir_session[0] ? btempdir_session : BKE_tempdir_base(); +} + +/** + * Path to persistent temporary directory (with trailing slash) + */ +const char *BKE_tempdir_base(void) +{ + return btempdir_base; +} + +/** + * Path to the system temporary directory (with trailing slash) + */ +void BKE_tempdir_system_init(char *dir) +{ + BLI_where_is_temp(dir, NULL, FILE_MAX, NULL); +} + +/** + * Delete content of this instance's temp dir. + */ +void BKE_tempdir_session_purge(void) +{ + if (btempdir_session[0] && BLI_is_dir(btempdir_session)) { + BLI_delete(btempdir_session, true, true); + } +} diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index d3dcb2b72a0..431c24d3ed0 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -222,6 +222,10 @@ bArmature *BKE_armature_copy(bArmature *arm) newArm->act_edbone = NULL; newArm->sketch = NULL; + if (arm->id.lib) { + BKE_id_lib_local_paths(G.main, arm->id.lib, &newArm->id); + } + return newArm; } @@ -1654,6 +1658,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected pchanw.next = pchan->next; pchanw.parent = pchan->parent; pchanw.child = pchan->child; + pchanw.custom_tx = pchan->custom_tx; pchanw.mpath = pchan->mpath; pchan->mpath = NULL; @@ -2161,9 +2166,9 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o mul_v3_fl(poseMat[2], scale); break; } - case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: + case CONSTRAINT_SPLINEIK_XZS_INVERSE: { - /* 'volume preservation' */ + /* old 'volume preservation' method using the inverse scale */ float scale; /* calculate volume preservation factor which is @@ -2184,6 +2189,54 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o mul_v3_fl(poseMat[2], scale); break; } + case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: + { + /* improved volume preservation based on the Stretch To constraint */ + float final_scale; + + /* as the basis for volume preservation, we use the inverse scale factor... */ + if (fabsf(scaleFac) != 0.0f) { + /* NOTE: The method here is taken wholesale from the Stretch To constraint */ + float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); + + if (bulge > 1.0f) { + if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { + float bulge_max = max_ff(ikData->bulge_max, 1.0f); + float hard = min_ff(bulge, bulge_max); + + float range = bulge_max - 1.0f; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (0.5f * M_PI); + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + if (bulge < 1.0f) { + if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { + float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); + float hard = max_ff(bulge, bulge_min); + + float range = 1.0f - bulge_min; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (0.5f * M_PI); + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + + /* compute scale factor for xz axes from this value */ + final_scale = sqrt(bulge); + } + else { + /* no scaling, so scale factor is simple */ + final_scale = 1.0f; + } + + /* apply the scaling (assuming normalised scale) */ + mul_v3_fl(poseMat[0], final_scale); + mul_v3_fl(poseMat[2], final_scale); + break; + } } /* finally, multiply the x and z scaling by the radius of the curve too, diff --git a/source/blender/blenkernel/intern/autoexec.c b/source/blender/blenkernel/intern/autoexec.c index 872780bd50a..d9462cd0262 100644 --- a/source/blender/blenkernel/intern/autoexec.c +++ b/source/blender/blenkernel/intern/autoexec.c @@ -34,9 +34,12 @@ #include "BLI_utildefines.h" #include "BLI_fnmatch.h" -#include "BLI_string.h" #include "BLI_path_util.h" +#ifdef WIN32 +# include "BLI_string.h" +#endif + #include "BKE_autoexec.h" /* own include */ /** diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index adfe43cb2a3..96f769587d9 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -61,6 +61,7 @@ #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_bpath.h" #include "BKE_brush.h" @@ -493,10 +494,11 @@ bool BKE_read_file_from_memory( BLO_update_defaults_startup_blend(bfd->main); setup_app_data(C, bfd, "<memory2>"); } - else + else { BKE_reports_prepend(reports, "Loading failed: "); + } - return (bfd ? 1 : 0); + return (bfd != NULL); } /* memfile is the undo buffer */ @@ -516,10 +518,11 @@ bool BKE_read_file_from_memfile( setup_app_data(C, bfd, "<memory1>"); } - else + else { BKE_reports_prepend(reports, "Loading failed: "); + } - return (bfd ? 1 : 0); + return (bfd != NULL); } /* only read the userdef from a .blend */ @@ -687,7 +690,7 @@ void BKE_write_undo(bContext *C, const char *name) counter = counter % U.undosteps; BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); - BLI_make_file_string("/", filepath, BLI_temp_dir_session(), numstr); + BLI_make_file_string("/", filepath, BKE_tempdir_session(), numstr); /* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); @@ -834,13 +837,13 @@ bool BKE_undo_save_file(const char *filename) int file, oflags; if ((U.uiflag & USER_GLOBALUNDO) == 0) { - return 0; + return false; } uel = curundo; if (uel == NULL) { fprintf(stderr, "No undo buffer to save recovery file\n"); - return 0; + return false; } /* note: This is currently used for autosave and 'quit.blend', where _not_ following symlinks is OK, @@ -862,7 +865,7 @@ bool BKE_undo_save_file(const char *filename) if (file == -1) { fprintf(stderr, "Unable to save '%s': %s\n", filename, errno ? strerror(errno) : "Unknown error opening file"); - return 0; + return false; } for (chunk = uel->memfile.chunks.first; chunk; chunk = chunk->next) { @@ -876,9 +879,9 @@ bool BKE_undo_save_file(const char *filename) if (chunk) { fprintf(stderr, "Unable to save '%s': %s\n", filename, errno ? strerror(errno) : "Unknown error writing file"); - return 0; + return false; } - return 1; + return true; } /* sets curscene */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 0fdd838f5fc..55d347a4fb2 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -33,7 +33,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_rand.h" -#include "BLI_rect.h" #include "BKE_brush.h" #include "BKE_colortools.h" @@ -49,7 +48,6 @@ #include "IMB_imbuf_types.h" #include "RE_render_ext.h" /* externtex */ -#include "RE_shader_ext.h" static RNG *brush_rng; @@ -180,6 +178,10 @@ Brush *BKE_brush_copy(Brush *brush) brushn->id.us++; } + if (brush->id.lib) { + BKE_id_lib_local_paths(G.main, brush->id.lib, &brushn->id); + } + return brushn; } @@ -300,7 +302,6 @@ void BKE_brush_debug_print_state(Brush *br) BR_TEST_FLAG(BRUSH_SIZE_PRESSURE); BR_TEST_FLAG(BRUSH_JITTER_PRESSURE); BR_TEST_FLAG(BRUSH_SPACING_PRESSURE); - BR_TEST_FLAG(BRUSH_RAKE); BR_TEST_FLAG(BRUSH_ANCHORED); BR_TEST_FLAG(BRUSH_DIR_IN); BR_TEST_FLAG(BRUSH_SPACE); @@ -316,7 +317,6 @@ void BKE_brush_debug_print_state(Brush *br) BR_TEST_FLAG(BRUSH_EDGE_TO_EDGE); BR_TEST_FLAG(BRUSH_DRAG_DOT); BR_TEST_FLAG(BRUSH_INVERSE_SMOOTH_PRESSURE); - BR_TEST_FLAG(BRUSH_RANDOM_ROTATION); BR_TEST_FLAG(BRUSH_PLANE_TRIM); BR_TEST_FLAG(BRUSH_FRONTFACE); BR_TEST_FLAG(BRUSH_CUSTOM_ICON); @@ -702,7 +702,7 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br, if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { /* keep coordinates relative to mouse */ - rotation += ups->brush_rotation; + rotation += ups->brush_rotation_sec; x = point_2d[0] - ups->mask_tex_mouse[0]; y = point_2d[1] - ups->mask_tex_mouse[1]; @@ -720,7 +720,7 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br, y = point_2d[1]; } else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) { - rotation += ups->brush_rotation; + rotation += ups->brush_rotation_sec; /* these contain a random coordinate */ x = point_2d[0] - ups->mask_tex_mouse[0]; y = point_2d[1] - ups->mask_tex_mouse[1]; @@ -953,7 +953,7 @@ void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread; } -void BKE_brush_randomize_texture_coordinates(UnifiedPaintSettings *ups, bool mask) +void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask) { /* we multiply with brush radius as an optimization for the brush * texture sampling functions */ @@ -968,7 +968,7 @@ void BKE_brush_randomize_texture_coordinates(UnifiedPaintSettings *ups, bool mas } /* Uses the brush curve control to find a strength value between 0 and 1 */ -float BKE_brush_curve_strength_clamp(Brush *br, float p, const float len) +float BKE_brush_curve_strength(Brush *br, float p, const float len) { float strength; @@ -981,17 +981,6 @@ float BKE_brush_curve_strength_clamp(Brush *br, float p, const float len) return strength; } -/* same as above but can return negative values if the curve enables - * used for sculpt only */ -float BKE_brush_curve_strength(Brush *br, float p, const float len) -{ - if (p >= len) - p = 1.0f; - else - p = p / len; - - return curvemapping_evaluateF(br->curve, 0, p); -} /* TODO: should probably be unified with BrushPainter stuff? */ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_secondary) @@ -1049,7 +1038,7 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary) for (i = 0; i < side; ++i) { for (j = 0; j < side; ++j) { float magn = sqrtf(pow2f(i - half) + pow2f(j - half)); - im->rect_float[i * side + j] = BKE_brush_curve_strength_clamp(br, magn, half); + im->rect_float[i * side + j] = BKE_brush_curve_strength(br, magn, half); } } diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 4ad577a7bda..1a4a4bd6bce 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -65,9 +65,7 @@ static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, con float idist; float p1[3]; - float plane_normal[3], hit_point[3]; - - normal_tri_v3(plane_normal, v0, v1, v2); + float hit_point[3]; madd_v3_v3v3fl(p1, ray->origin, ray->direction, m_dist); if (isect_sweeping_sphere_tri_v3(ray->origin, p1, radius, v0, v1, v2, &idist, hit_point)) { @@ -81,7 +79,7 @@ static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, con * BVH from meshes callbacks */ -/* Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces. +/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_faces. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) { @@ -145,7 +143,7 @@ static void editmesh_faces_nearest_point(void *userdata, int index, const float } } -/* Callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces. +/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_faces. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { @@ -214,7 +212,7 @@ static void editmesh_faces_spherecast(void *userdata, int index, const BVHTreeRa } } -/* Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_edges. +/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_edges. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_edges_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) { @@ -239,68 +237,140 @@ static void mesh_edges_nearest_point(void *userdata, int index, const float co[3 } } -/* - * BVH builders - */ -/* Builds a bvh tree.. where nodes are the vertexs of the given mesh */ -BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) +/* Helper, does all the point-spherecast work actually. */ +static void mesh_verts_spherecast_do( + const BVHTreeFromMesh *UNUSED(data), int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit) { - BVHTree *tree; - MVert *vert; - bool vert_allocated; + float dist; + const float *r1; + float r2[3], i1[3]; + r1 = ray->origin; + add_v3_v3v3(r2, r1, ray->direction); + + closest_to_line_segment_v3(i1, v, r1, r2); + + /* No hit if closest point is 'behind' the origin of the ray, or too far away from it. */ + if ((dot_v3v3v3(r1, i1, r2) >= 0.0f) && ((dist = len_v3v3(r1, i1)) < hit->dist)) { + hit->index = index; + hit->dist = dist; + copy_v3_v3(hit->co, i1); + } +} - BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); - tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTICES); - BLI_rw_mutex_unlock(&cache_rwlock); +/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_verts. + * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ +static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata; + float *v = data->vert[index].co; - vert = DM_get_vert_array(dm, &vert_allocated); + mesh_verts_spherecast_do(data, index, v, ray, hit); +} - /* Not in cache */ - if (tree == NULL) { - BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTICES); - if (tree == NULL) { - int i; - int numVerts = dm->getNumVerts(dm); +/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges. + * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ +static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata; + MVert *vert = data->vert; + MEdge *edge = &data->edge[index]; - if (vert != NULL) { - tree = BLI_bvhtree_new(numVerts, epsilon, tree_type, axis); + const float radius_sq = SQUARE(data->sphere_radius); + float dist; + const float *v1, *v2, *r1; + float r2[3], i1[3], i2[3]; + v1 = vert[edge->v1].co; + v2 = vert[edge->v2].co; + + /* In case we get a zero-length edge, handle it as a point! */ + if (equals_v3v3(v1, v2)) { + mesh_verts_spherecast_do(data, index, v1, ray, hit); + return; + } - if (tree != NULL) { - for (i = 0; i < numVerts; i++) { - BLI_bvhtree_insert(tree, i, vert[i].co, 1); - } + r1 = ray->origin; + add_v3_v3v3(r2, r1, ray->direction); - BLI_bvhtree_balance(tree); + if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) { + /* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */ + if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) { + const float e_fac = line_point_factor_v3(i1, v1, v2); + if (e_fac < 0.0f) { + copy_v3_v3(i1, v1); + } + else if (e_fac > 1.0f) { + copy_v3_v3(i1, v2); + } + /* Ensure ray is really close enough from edge! */ + if (len_squared_v3v3(i1, i2) <= radius_sq) { + hit->index = index; + hit->dist = dist; + copy_v3_v3(hit->co, i2); + } + } + } +} - /* Save on cache for later use */ -// printf("BVHTree built and saved on cache\n"); - bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTICES); +/* + * BVH builders + */ + +/* ***** Vertex ***** */ + +static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon, int tree_type, int axis, + MVert *vert, const int numVerts, + BLI_bitmap *mask, int numVerts_active) +{ + BVHTree *tree = NULL; + int i; + + if (vert) { + if (mask && numVerts_active < 0) { + numVerts_active = 0; + for (i = 0; i < numVerts; i++) { + if (BLI_BITMAP_TEST_BOOL(mask, i)) { + numVerts_active++; } } } - BLI_rw_mutex_unlock(&cache_rwlock); - } - else { -// printf("BVHTree is already build, using cached tree\n"); + else if (!mask) { + numVerts_active = numVerts; + } + + tree = BLI_bvhtree_new(numVerts_active, epsilon, tree_type, axis); + + if (tree) { + for (i = 0; i < numVerts; i++) { + if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) { + continue; + } + BLI_bvhtree_insert(tree, i, vert[i].co, 1); + } + + BLI_bvhtree_balance(tree); + } } + return tree; +} - /* Setup BVHTreeFromMesh */ +static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon, + MVert *vert, const bool vert_allocated) +{ memset(data, 0, sizeof(*data)); - data->tree = tree; - if (data->tree) { - data->cached = true; + if (tree) { + data->tree = tree; + data->cached = is_cached; /* a NULL nearest callback works fine * remember the min distance to point is the same as the min distance to BV of point */ data->nearest_callback = NULL; - data->raycast_callback = NULL; + data->raycast_callback = mesh_verts_spherecast; data->vert = vert; data->vert_allocated = vert_allocated; - data->face = DM_get_tessface_array(dm, &data->face_allocated); + //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */ data->sphere_radius = epsilon; } @@ -309,184 +379,66 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e MEM_freeN(vert); } } - - return data->tree; } -/* Builds a bvh tree.. where nodes are the faces of the given dm. */ -BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) +/* Builds a bvh tree where nodes are the vertices of the given dm */ +BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) { - BMEditMesh *em = data->em_evil; - const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_FACES; BVHTree *tree; MVert *vert; - MFace *face; - bool vert_allocated = false, face_allocated = false; + bool vert_allocated; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS); BLI_rw_mutex_unlock(&cache_rwlock); - if (em == NULL) { - vert = DM_get_vert_array(dm, &vert_allocated); - face = DM_get_tessface_array(dm, &face_allocated); - } + vert = DM_get_vert_array(dm, &vert_allocated); /* Not in cache */ if (tree == NULL) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS); if (tree == NULL) { - int i; - int numFaces; - - /* BMESH specific check that we have tessfaces, - * we _could_ tessellate here but rather not - campbell - * - * this assert checks we have tessfaces, - * if not caller should use DM_ensure_tessface() */ - if (em) { - numFaces = em->tottri; - } - else { - numFaces = dm->getNumTessFaces(dm); - BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0)); - } - - if (numFaces != 0) { - /* Create a bvh-tree of the given target */ - // printf("%s: building BVH, total=%d\n", __func__, numFaces); - tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis); - if (tree != NULL) { - if (em) { - const struct BMLoop *(*looptris)[3] = (void *)em->looptris; - - /* avoid double-up on face searches for quads-ngons */ - bool insert_prev = false; - BMFace *f_prev = NULL; - - /* data->em_evil is only set for snapping, and only for the mesh of the object - * which is currently open in edit mode. When set, the bvhtree should not contain - * faces that will interfere with snapping (e.g. faces that are hidden/selected - * or faces that have selected verts).*/ - - /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden - * and/or selected. Even if the faces themselves are not selected for the snapped - * transform, having a vertex selected means the face (and thus it's tessellated - * triangles) will be moving and will not be a good snap targets.*/ - for (i = 0; i < em->tottri; i++) { - const BMLoop **ltri = looptris[i]; - BMFace *f = ltri[0]->f; - bool insert; - - /* Start with the assumption the triangle should be included for snapping. */ - if (f == f_prev) { - insert = insert_prev; - } - else { - if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - /* Don't insert triangles tessellated from faces that are hidden - * or selected*/ - insert = false; - } - else { - BMLoop *l_iter, *l_first; - insert = true; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { - /* Don't insert triangles tessellated from faces that have - * any selected verts.*/ - insert = false; - break; - } - } while ((l_iter = l_iter->next) != l_first); - } - - /* skip if face doesn't change */ - f_prev = f; - insert_prev = insert; - } - - if (insert) { - /* No reason found to block hit-testing the triangle for snap, - * so insert it now.*/ - float co[3][3]; - copy_v3_v3(co[0], ltri[0]->v->co); - copy_v3_v3(co[1], ltri[1]->v->co); - copy_v3_v3(co[2], ltri[2]->v->co); - - BLI_bvhtree_insert(tree, i, co[0], 3); - } - } - } - else { - if (vert != NULL && face != NULL) { - for (i = 0; i < numFaces; i++) { - float co[4][3]; - copy_v3_v3(co[0], vert[face[i].v1].co); - copy_v3_v3(co[1], vert[face[i].v2].co); - copy_v3_v3(co[2], vert[face[i].v3].co); - if (face[i].v4) - copy_v3_v3(co[3], vert[face[i].v4].co); - - BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); - } - } - } - BLI_bvhtree_balance(tree); - - /* Save on cache for later use */ -// printf("BVHTree built and saved on cache\n"); - bvhcache_insert(&dm->bvhCache, tree, bvhcache_type); - } + tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, vert, dm->getNumVerts(dm), NULL, -1); + if (tree) { + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS); } } BLI_rw_mutex_unlock(&cache_rwlock); } else { -// printf("BVHTree is already build, using cached tree\n"); + /* printf("BVHTree is already build, using cached tree\n"); */ } - /* Setup BVHTreeFromMesh */ - memset(data, 0, sizeof(*data)); - data->tree = tree; - data->em_evil = em; + bvhtree_from_mesh_verts_setup_data(data, tree, true, epsilon, vert, vert_allocated); - if (data->tree) { - data->cached = true; - - if (em) { - data->nearest_callback = editmesh_faces_nearest_point; - data->raycast_callback = editmesh_faces_spherecast; - } - else { - data->nearest_callback = mesh_faces_nearest_point; - data->raycast_callback = mesh_faces_spherecast; + return data->tree; +} - data->vert = vert; - data->vert_allocated = vert_allocated; - data->face = face; - data->face_allocated = face_allocated; - } +/** + * Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!). + * \param vert_allocated if true, vert freeing will be done when freeing data. + * \param mask if not null, true elements give which vert to add to BVH tree. + * \param numVerts_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). + */ +BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data, MVert *vert, const int numVerts, const bool vert_allocated, + BLI_bitmap *mask, int numVerts_active, + float epsilon, int tree_type, int axis) +{ + BVHTree *tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, vert, numVerts, mask, numVerts_active); - data->sphere_radius = epsilon; - } - else { - if (vert_allocated) { - MEM_freeN(vert); - } - if (face_allocated) { - MEM_freeN(face); - } - } + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated); return data->tree; - } -/* Builds a bvh tree.. where nodes are the faces of the given dm. */ +/* ***** Edge ***** */ + +/* Builds a bvh tree where nodes are the edges of the given dm */ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) { BVHTree *tree; @@ -523,7 +475,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e BLI_bvhtree_balance(tree); /* Save on cache for later use */ -// printf("BVHTree built and saved on cache\n"); + /* printf("BVHTree built and saved on cache\n"); */ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES); } } @@ -531,7 +483,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e BLI_rw_mutex_unlock(&cache_rwlock); } else { -// printf("BVHTree is already build, using cached tree\n"); + /* printf("BVHTree is already build, using cached tree\n"); */ } @@ -543,7 +495,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e data->cached = true; data->nearest_callback = mesh_edges_nearest_point; - data->raycast_callback = NULL; + data->raycast_callback = mesh_edges_spherecast; data->vert = vert; data->vert_allocated = vert_allocated; @@ -561,15 +513,240 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e } } return data->tree; +} + +/* ***** Tessellated face ***** */ + +static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon, int tree_type, int axis, + BMEditMesh *em, MVert *vert, MFace *face, const int numFaces, + BLI_bitmap *mask, int numFaces_active) +{ + BVHTree *tree = NULL; + int i; + + if (numFaces) { + if (mask && numFaces_active < 0) { + numFaces_active = 0; + for (i = 0; i < numFaces; i++) { + if (BLI_BITMAP_TEST_BOOL(mask, i)) { + numFaces_active++; + } + } + } + else if (!mask) { + numFaces_active = numFaces; + } + + /* Create a bvh-tree of the given target */ + /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */ + tree = BLI_bvhtree_new(numFaces_active, epsilon, tree_type, axis); + if (tree) { + if (em) { + const struct BMLoop *(*looptris)[3] = (void *)em->looptris; + + /* avoid double-up on face searches for quads-ngons */ + bool insert_prev = false; + BMFace *f_prev = NULL; + + /* data->em_evil is only set for snapping, and only for the mesh of the object + * which is currently open in edit mode. When set, the bvhtree should not contain + * faces that will interfere with snapping (e.g. faces that are hidden/selected + * or faces that have selected verts). */ + + /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden + * and/or selected. Even if the faces themselves are not selected for the snapped + * transform, having a vertex selected means the face (and thus it's tessellated + * triangles) will be moving and will not be a good snap targets. */ + for (i = 0; i < numFaces; i++) { + const BMLoop **ltri = looptris[i]; + BMFace *f = ltri[0]->f; + bool insert = mask ? BLI_BITMAP_TEST_BOOL(mask, i) : true; + + /* Start with the assumption the triangle should be included for snapping. */ + if (f == f_prev) { + insert = insert_prev; + } + else if (insert) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + /* Don't insert triangles tessellated from faces that are hidden or selected */ + insert = false; + } + else { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { + /* Don't insert triangles tessellated from faces that have any selected verts */ + insert = false; + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + + /* skip if face doesn't change */ + f_prev = f; + insert_prev = insert; + } + + if (insert) { + /* No reason found to block hit-testing the triangle for snap, so insert it now.*/ + float co[3][3]; + copy_v3_v3(co[0], ltri[0]->v->co); + copy_v3_v3(co[1], ltri[1]->v->co); + copy_v3_v3(co[2], ltri[2]->v->co); + + BLI_bvhtree_insert(tree, i, co[0], 3); + } + } + } + else { + if (vert && face) { + for (i = 0; i < numFaces; i++) { + float co[4][3]; + if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) { + continue; + } + copy_v3_v3(co[0], vert[face[i].v1].co); + copy_v3_v3(co[1], vert[face[i].v2].co); + copy_v3_v3(co[2], vert[face[i].v3].co); + if (face[i].v4) + copy_v3_v3(co[3], vert[face[i].v4].co); + + BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); + } + } + } + BLI_bvhtree_balance(tree); + } + } + + return tree; +} + +static void bvhtree_from_mesh_faces_setup_data(BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, + float epsilon, BMEditMesh *em, + MVert *vert, const bool vert_allocated, + MFace *face, const bool face_allocated) +{ + memset(data, 0, sizeof(*data)); + data->em_evil = em; + + if (tree) { + data->tree = tree; + data->cached = is_cached; + + if (em) { + data->nearest_callback = editmesh_faces_nearest_point; + data->raycast_callback = editmesh_faces_spherecast; + } + else { + data->nearest_callback = mesh_faces_nearest_point; + data->raycast_callback = mesh_faces_spherecast; + + data->vert = vert; + data->vert_allocated = vert_allocated; + data->face = face; + data->face_allocated = face_allocated; + } + + data->sphere_radius = epsilon; + } + else { + if (vert_allocated) { + MEM_freeN(vert); + } + if (face_allocated) { + MEM_freeN(face); + } + } +} + +/* Builds a bvh tree where nodes are the tesselated faces of the given dm */ +BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) +{ + BMEditMesh *em = data->em_evil; + const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_FACES; + BVHTree *tree; + MVert *vert = NULL; + MFace *face = NULL; + bool vert_allocated = false, face_allocated = false; + + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); + tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + BLI_rw_mutex_unlock(&cache_rwlock); + + if (em == NULL) { + vert = DM_get_vert_array(dm, &vert_allocated); + face = DM_get_tessface_array(dm, &face_allocated); + } + + /* Not in cache */ + if (tree == NULL) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + tree = bvhcache_find(&dm->bvhCache, bvhcache_type); + if (tree == NULL) { + int numFaces; + + /* BMESH specific check that we have tessfaces, + * we _could_ tessellate here but rather not - campbell + * + * this assert checks we have tessfaces, + * if not caller should use DM_ensure_tessface() */ + if (em) { + numFaces = em->tottri; + } + else { + numFaces = dm->getNumTessFaces(dm); + BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0)); + } + + tree = bvhtree_from_mesh_faces_create_tree(epsilon, tree_type, axis, em, vert, face, numFaces, NULL, -1); + if (tree) { + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(&dm->bvhCache, tree, bvhcache_type); + } + } + BLI_rw_mutex_unlock(&cache_rwlock); + } + else { + /* printf("BVHTree is already build, using cached tree\n"); */ + } + + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, em, vert, vert_allocated, face, face_allocated); + + return data->tree; +} + +/** + * Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!). + * \param vert_allocated if true, vert freeing will be done when freeing data. + * \param face_allocated if true, face freeing will be done when freeing data. + * \param mask if not null, true elements give which faces to add to BVH tree. + * \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask). + */ +BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated, + MFace *face, const int numFaces, const bool face_allocated, + BLI_bitmap *mask, int numFaces_active, float epsilon, int tree_type, int axis) +{ + BVHTree *tree = bvhtree_from_mesh_faces_create_tree(epsilon, tree_type, axis, NULL, vert, face, numFaces, + mask, numFaces_active); + + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, NULL, vert, vert_allocated, face, face_allocated); + + return data->tree; } /* Frees data allocated by a call to bvhtree_from_mesh_*. */ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) { if (data->tree) { - if (!data->cached) + if (!data->cached) { BLI_bvhtree_free(data->tree); + } if (data->vert_allocated) { MEM_freeN(data->vert); @@ -586,7 +763,10 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) } -/* BVHCache */ +/* + * BVHCache + */ + typedef struct BVHCacheItem { int type; BVHTree *tree; diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 1402f62291f..e424823d8dc 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -39,6 +39,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_rect.h" #include "BKE_animsys.h" #include "BKE_camera.h" @@ -77,6 +78,10 @@ Camera *BKE_camera_copy(Camera *cam) id_lib_extern((ID *)camn->dof_ob); + if (cam->id.lib) { + BKE_id_lib_local_paths(G.main, cam->id.lib, &camn->id); + } + return camn; } @@ -454,17 +459,25 @@ void BKE_camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3]) float dummy_drawsize; const float dummy_scale[3] = {1.0f, 1.0f, 1.0f}; - BKE_camera_view_frame_ex(scene, camera, false, 1.0, dummy_scale, + BKE_camera_view_frame_ex(scene, camera, 0.0, true, dummy_scale, dummy_asp, dummy_shift, &dummy_drawsize, r_vec); } +#define CAMERA_VIEWFRAME_NUM_PLANES 4 typedef struct CameraViewFrameData { - float plane_tx[4][4]; /* 4 planes (not 4x4 matrix)*/ - float frame_tx[4][3]; - float normal_tx[4][3]; - float dist_vals_sq[4]; /* distance squared (signed) */ + float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; /* 4 planes */ + float normal_tx[CAMERA_VIEWFRAME_NUM_PLANES][3]; + float dist_vals_sq[CAMERA_VIEWFRAME_NUM_PLANES]; /* distance squared (signed) */ unsigned int tot; + + /* Ortho camera only. */ + bool is_ortho; + float camera_no[3]; + float dist_to_cam; + + /* Not used by callbacks... */ + float camera_rotmat[3][3]; } CameraViewFrameData; static void camera_to_frame_view_cb(const float co[3], void *user_data) @@ -472,67 +485,106 @@ static void camera_to_frame_view_cb(const float co[3], void *user_data) CameraViewFrameData *data = (CameraViewFrameData *)user_data; unsigned int i; - for (i = 0; i < 4; i++) { - float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]); - if (nd < data->dist_vals_sq[i]) { - data->dist_vals_sq[i] = nd; - } + for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { + const float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]); + CLAMP_MAX(data->dist_vals_sq[i], nd); + } + + if (data->is_ortho) { + const float d = dot_v3v3(data->camera_no, co); + CLAMP_MAX(data->dist_to_cam, d); } data->tot++; } -/* don't move the camera, just yield the fit location */ -/* only valid for perspective cameras */ -bool BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3]) +static void camera_frame_fit_data_init(Scene *scene, Object *ob, CameraParams *params, CameraViewFrameData *data) { - float shift[2]; - float plane_tx[4][3]; - float rot_obmat[3][3]; - const float zero[3] = {0, 0, 0}; - CameraViewFrameData data_cb; - + float camera_rotmat_transposed_inversed[4][4]; unsigned int i; - BKE_camera_view_frame(scene, camera_ob->data, data_cb.frame_tx); + /* setup parameters */ + BKE_camera_params_init(params); + BKE_camera_params_from_object(params, ob); - copy_m3_m4(rot_obmat, camera_ob->obmat); - normalize_m3(rot_obmat); - - for (i = 0; i < 4; i++) { - /* normalize so Z is always 1.0f*/ - mul_v3_fl(data_cb.frame_tx[i], 1.0f / data_cb.frame_tx[i][2]); + /* compute matrix, viewplane, .. */ + if (scene) { + BKE_camera_params_compute_viewplane(params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); } + else { + BKE_camera_params_compute_viewplane(params, 1, 1, 1.0f, 1.0f); + } + BKE_camera_params_compute_matrix(params); - /* get the shift back out of the frame */ - shift[0] = (data_cb.frame_tx[0][0] + - data_cb.frame_tx[1][0] + - data_cb.frame_tx[2][0] + - data_cb.frame_tx[3][0]) / 4.0f; - shift[1] = (data_cb.frame_tx[0][1] + - data_cb.frame_tx[1][1] + - data_cb.frame_tx[2][1] + - data_cb.frame_tx[3][1]) / 4.0f; - - for (i = 0; i < 4; i++) { - mul_m3_v3(rot_obmat, data_cb.frame_tx[i]); + /* initialize callback data */ + copy_m3_m4(data->camera_rotmat, ob->obmat); + normalize_m3(data->camera_rotmat); + /* To transform a plane which is in its homogeneous representation (4d vector), + * we need the inverse of the transpose of the transform matrix... */ + copy_m4_m3(camera_rotmat_transposed_inversed, data->camera_rotmat); + transpose_m4(camera_rotmat_transposed_inversed); + invert_m4(camera_rotmat_transposed_inversed); + + /* Extract frustum planes from projection matrix. */ + planes_from_projmat(params->winmat, + /* left right top bottom near far */ + data->plane_tx[2], data->plane_tx[0], data->plane_tx[3], data->plane_tx[1], NULL, NULL); + + /* Rotate planes and get normals from them */ + for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { + mul_m4_v4(camera_rotmat_transposed_inversed, data->plane_tx[i]); + normalize_v3_v3(data->normal_tx[i], data->plane_tx[i]); } - for (i = 0; i < 4; i++) { - normal_tri_v3(data_cb.normal_tx[i], zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]); - plane_from_point_normal_v3(data_cb.plane_tx[i], data_cb.frame_tx[i], data_cb.normal_tx[i]); + copy_v4_fl(data->dist_vals_sq, FLT_MAX); + data->tot = 0; + data->is_ortho = params->is_ortho; + if (params->is_ortho) { + /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */ + negate_v3_v3(data->camera_no, data->camera_rotmat[2]); + data->dist_to_cam = FLT_MAX; } +} - /* initialize callback data */ - copy_v4_fl(data_cb.dist_vals_sq, FLT_MAX); - data_cb.tot = 0; - /* run callback on all visible points */ - BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, - camera_to_frame_view_cb, &data_cb); +static bool camera_frame_fit_calc_from_data( + CameraParams *params, CameraViewFrameData *data, float r_co[3], float *r_scale) +{ + float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][3]; + unsigned int i; - if (data_cb.tot <= 1) { + if (data->tot <= 1) { return false; } + + if (params->is_ortho) { + const float *cam_axis_x = data->camera_rotmat[0]; + const float *cam_axis_y = data->camera_rotmat[1]; + const float *cam_axis_z = data->camera_rotmat[2]; + float dists[CAMERA_VIEWFRAME_NUM_PLANES]; + float scale_diff; + + /* apply the dist-from-plane's to the transformed plane points */ + for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { + dists[i] = sqrtf_signed(data->dist_vals_sq[i]); + } + + if ((dists[0] + dists[2]) > (dists[1] + dists[3])) { + scale_diff = (dists[1] + dists[3]) * + (BLI_rctf_size_x(¶ms->viewplane) / BLI_rctf_size_y(¶ms->viewplane)); + } + else { + scale_diff = (dists[0] + dists[2]) * + (BLI_rctf_size_y(¶ms->viewplane) / BLI_rctf_size_x(¶ms->viewplane)); + } + *r_scale = params->ortho_scale - scale_diff; + + zero_v3(r_co); + madd_v3_v3fl(r_co, cam_axis_x, (dists[2] - dists[0]) * 0.5f + params->shiftx * scale_diff); + madd_v3_v3fl(r_co, cam_axis_y, (dists[1] - dists[3]) * 0.5f + params->shifty * scale_diff); + madd_v3_v3fl(r_co, cam_axis_z, -(data->dist_to_cam - 1.0f - params->clipsta)); + + return true; + } else { float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3]; float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3]; @@ -540,16 +592,16 @@ bool BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object float plane_isect_pt_1[3], plane_isect_pt_2[3]; /* apply the dist-from-plane's to the transformed plane points */ - for (i = 0; i < 4; i++) { - mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], sqrtf_signed(data_cb.dist_vals_sq[i])); + for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { + mul_v3_v3fl(plane_tx[i], data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i])); } if ((!isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, - plane_tx[0], data_cb.normal_tx[0], - plane_tx[2], data_cb.normal_tx[2])) || + plane_tx[0], data->normal_tx[0], + plane_tx[2], data->normal_tx[2])) || (!isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, - plane_tx[1], data_cb.normal_tx[1], - plane_tx[3], data_cb.normal_tx[3]))) + plane_tx[1], data->normal_tx[1], + plane_tx[3], data->normal_tx[3]))) { return false; } @@ -559,16 +611,17 @@ bool BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object if (isect_line_line_v3(plane_isect_1, plane_isect_1_other, plane_isect_2, plane_isect_2_other, - plane_isect_pt_1, plane_isect_pt_2) == 0) + plane_isect_pt_1, plane_isect_pt_2) != 0) { - return false; - } - else { - float cam_plane_no[3] = {0.0f, 0.0f, -1.0f}; + float cam_plane_no[3]; float plane_isect_delta[3]; float plane_isect_delta_len; - mul_m3_v3(rot_obmat, cam_plane_no); + float shift_fac = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y) / + params->lens; + + /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */ + negate_v3_v3(cam_plane_no, data->camera_rotmat[2]); sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1); plane_isect_delta_len = len_v3(plane_isect_delta); @@ -578,18 +631,58 @@ bool BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object /* offset shift */ normalize_v3(plane_isect_1_no); - madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len); + madd_v3_v3fl(r_co, plane_isect_1_no, params->shifty * plane_isect_delta_len * shift_fac); } else { copy_v3_v3(r_co, plane_isect_pt_2); /* offset shift */ normalize_v3(plane_isect_2_no); - madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len); + madd_v3_v3fl(r_co, plane_isect_2_no, params->shiftx * plane_isect_delta_len * shift_fac); } - return true; } } + + return false; } + +/* don't move the camera, just yield the fit location */ +/* r_scale only valid/useful for ortho cameras */ +bool BKE_camera_view_frame_fit_to_scene( + Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale) +{ + CameraParams params; + CameraViewFrameData data_cb; + + /* just in case */ + *r_scale = 1.0f; + + camera_frame_fit_data_init(scene, camera_ob, ¶ms, &data_cb); + + /* run callback on all visible points */ + BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb); + + return camera_frame_fit_calc_from_data(¶ms, &data_cb, r_co, r_scale); +} + +bool BKE_camera_view_frame_fit_to_coords( + Scene *scene, float (*cos)[3], int num_cos, Object *camera_ob, float r_co[3], float *r_scale) +{ + CameraParams params; + CameraViewFrameData data_cb; + + /* just in case */ + *r_scale = 1.0f; + + camera_frame_fit_data_init(scene, camera_ob, ¶ms, &data_cb); + + /* run callback on all given coordinates */ + while (num_cos--) { + camera_to_frame_view_cb(cos[num_cos], &data_cb); + } + + return camera_frame_fit_calc_from_data(¶ms, &data_cb, r_co, r_scale); +} + diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index bfc70c91181..a1bf255c239 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -35,7 +35,6 @@ */ #include "BLI_math.h" -#include "BLI_blenlib.h" #include "BLI_edgehash.h" #include "BLI_utildefines.h" #include "BLI_stackdefines.h" @@ -49,7 +48,6 @@ #include "BKE_editmesh.h" #include "BKE_curve.h" -#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -61,7 +59,6 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_glew.h" -#include "GPU_material.h" #include <string.h> #include <limits.h> @@ -343,106 +340,64 @@ static void cdDM_update_normals_from_pbvh(DerivedMesh *dm) static void cdDM_drawVerts(DerivedMesh *dm) { - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - MVert *mv = cddm->mvert; - int i; - - if (GPU_buffer_legacy(dm)) { - glBegin(GL_POINTS); - for (i = 0; i < dm->numVertData; i++, mv++) - glVertex3fv(mv->co); - glEnd(); - } - else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ - GPU_vertex_setup(dm); - if (!GPU_buffer_legacy(dm)) { - if (dm->drawObject->tot_triangle_point) - glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_triangle_point); - else - glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loose_point); - } - GPU_buffer_unbind(); - } + GPU_vertex_setup(dm); + if (dm->drawObject->tot_triangle_point) + glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_triangle_point); + else + glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loose_point); + GPU_buffer_unbind(); } static void cdDM_drawUVEdges(DerivedMesh *dm) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; MFace *mf = cddm->mface; - MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE); int i; if (mf) { - if (GPU_buffer_legacy(dm)) { - glBegin(GL_LINES); - for (i = 0; i < dm->numTessFaceData; i++, mf++, tf++) { - if (!(mf->flag & ME_HIDE)) { - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - - if (!mf->v4) { - glVertex2fv(tf->uv[2]); - glVertex2fv(tf->uv[0]); - } - else { - glVertex2fv(tf->uv[2]); - glVertex2fv(tf->uv[3]); - - glVertex2fv(tf->uv[3]); - glVertex2fv(tf->uv[0]); - } - } + int prevstart = 0; + int prevdraw = 1; + int draw = 1; + int curpos = 0; + + GPU_uvedge_setup(dm); + for (i = 0; i < dm->numTessFaceData; i++, mf++) { + if (!(mf->flag & ME_HIDE)) { + draw = 1; } - glEnd(); - } - else { - int prevstart = 0; - int prevdraw = 1; - int draw = 1; - int curpos = 0; - - GPU_uvedge_setup(dm); - if (!GPU_buffer_legacy(dm)) { - for (i = 0; i < dm->numTessFaceData; i++, mf++) { - if (!(mf->flag & ME_HIDE)) { - draw = 1; - } - else { - draw = 0; - } - if (prevdraw != draw) { - if (prevdraw > 0 && (curpos - prevstart) > 0) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - prevstart = curpos; - } - if (mf->v4) { - curpos += 8; - } - else { - curpos += 6; - } - prevdraw = draw; - } + else { + draw = 0; + } + if (prevdraw != draw) { if (prevdraw > 0 && (curpos - prevstart) > 0) { glDrawArrays(GL_LINES, prevstart, curpos - prevstart); } + prevstart = curpos; + } + if (mf->v4) { + curpos += 8; } - GPU_buffer_unbind(); + else { + curpos += 6; + } + prevdraw = draw; + } + if (prevdraw > 0 && (curpos - prevstart) > 0) { + glDrawArrays(GL_LINES, prevstart, curpos - prevstart); } + GPU_buffer_unbind(); } } static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - MVert *mvert = cddm->mvert; MEdge *medge = cddm->medge; int i; - + int prevstart = 0; + int prevdraw = 1; + bool draw = true; + if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { @@ -451,97 +406,60 @@ static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdg return; } - if (GPU_buffer_legacy(dm)) { - DEBUG_VBO("Using legacy code. cdDM_drawEdges\n"); - glBegin(GL_LINES); - for (i = 0; i < dm->numEdgeData; i++, medge++) { - if ((drawAllEdges || (medge->flag & ME_EDGEDRAW)) && - (drawLooseEdges || !(medge->flag & ME_LOOSEEDGE))) - { - glVertex3fv(mvert[medge->v1].co); - glVertex3fv(mvert[medge->v2].co); - } + GPU_edge_setup(dm); + for (i = 0; i < dm->numEdgeData; i++, medge++) { + if ((drawAllEdges || (medge->flag & ME_EDGEDRAW)) && + (drawLooseEdges || !(medge->flag & ME_LOOSEEDGE))) + { + draw = true; } - glEnd(); - } - else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ - int prevstart = 0; - int prevdraw = 1; - bool draw = true; - - GPU_edge_setup(dm); - if (!GPU_buffer_legacy(dm)) { - for (i = 0; i < dm->numEdgeData; i++, medge++) { - if ((drawAllEdges || (medge->flag & ME_EDGEDRAW)) && - (drawLooseEdges || !(medge->flag & ME_LOOSEEDGE))) - { - draw = true; - } - else { - draw = false; - } - if (prevdraw != draw) { - if (prevdraw > 0 && (i - prevstart) > 0) { - GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2); - } - prevstart = i; - } - prevdraw = draw; - } + else { + draw = false; + } + if (prevdraw != draw) { if (prevdraw > 0 && (i - prevstart) > 0) { GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2); } + prevstart = i; } - GPU_buffer_unbind(); + prevdraw = draw; } + if (prevdraw > 0 && (i - prevstart) > 0) { + GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2); + } + GPU_buffer_unbind(); } static void cdDM_drawLooseEdges(DerivedMesh *dm) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - MVert *mvert = cddm->mvert; MEdge *medge = cddm->medge; int i; - - if (GPU_buffer_legacy(dm)) { - DEBUG_VBO("Using legacy code. cdDM_drawLooseEdges\n"); - glBegin(GL_LINES); - for (i = 0; i < dm->numEdgeData; i++, medge++) { - if (medge->flag & ME_LOOSEEDGE) { - glVertex3fv(mvert[medge->v1].co); - glVertex3fv(mvert[medge->v2].co); - } + + int prevstart = 0; + int prevdraw = 1; + int draw = 1; + + GPU_edge_setup(dm); + for (i = 0; i < dm->numEdgeData; i++, medge++) { + if (medge->flag & ME_LOOSEEDGE) { + draw = 1; } - glEnd(); - } - else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ - int prevstart = 0; - int prevdraw = 1; - int draw = 1; - - GPU_edge_setup(dm); - if (!GPU_buffer_legacy(dm)) { - for (i = 0; i < dm->numEdgeData; i++, medge++) { - if (medge->flag & ME_LOOSEEDGE) { - draw = 1; - } - else { - draw = 0; - } - if (prevdraw != draw) { - if (prevdraw > 0 && (i - prevstart) > 0) { - GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2); - } - prevstart = i; - } - prevdraw = draw; - } + else { + draw = 0; + } + if (prevdraw != draw) { if (prevdraw > 0 && (i - prevstart) > 0) { GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2); } + prevstart = i; } - GPU_buffer_unbind(); + prevdraw = draw; + } + if (prevdraw > 0 && (i - prevstart) > 0) { + GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2); } + GPU_buffer_unbind(); } static void cdDM_drawFacesSolid(DerivedMesh *dm, @@ -549,11 +467,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, bool UNUSED(fast), DMSetMaterial setMaterial) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - MVert *mvert = cddm->mvert; - MFace *mface = cddm->mface; - const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL); - const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); - int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1; + int a; if (cddm->pbvh && cddm->pbvh_draw) { if (dm->numTessFaceData) { @@ -566,121 +480,37 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, return; } - - if (GPU_buffer_legacy(dm)) { - DEBUG_VBO("Using legacy code. cdDM_drawFacesSolid\n"); - glBegin(glmode = GL_QUADS); - for (a = 0; a < dm->numTessFaceData; a++, mface++) { - int new_glmode, new_matnr, new_shademodel; - - new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES; - new_matnr = mface->mat_nr + 1; - new_shademodel = (lnors || (mface->flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT; - - - if ((new_glmode != glmode) || (new_shademodel != shademodel) || - (setMaterial && (new_matnr != matnr))) - { - glEnd(); - - if (setMaterial) { - drawCurrentMat = setMaterial(matnr = new_matnr, NULL); - } - - glShadeModel(shademodel = new_shademodel); - glBegin(glmode = new_glmode); - } - - if (drawCurrentMat) { - if (lnors) { - glNormal3sv((const GLshort *)lnors[0][0]); - glVertex3fv(mvert[mface->v1].co); - glNormal3sv((const GLshort *)lnors[0][1]); - glVertex3fv(mvert[mface->v2].co); - glNormal3sv((const GLshort *)lnors[0][2]); - glVertex3fv(mvert[mface->v3].co); - if (mface->v4) { - glNormal3sv((const GLshort *)lnors[0][3]); - glVertex3fv(mvert[mface->v4].co); - } - } - else if (shademodel == GL_FLAT) { - if (nors) { - glNormal3fv(nors); - } - else { - /* TODO make this better (cache facenormals as layer?) */ - float nor[3]; - if (mface->v4) { - normal_quad_v3(nor, mvert[mface->v1].co, mvert[mface->v2].co, mvert[mface->v3].co, mvert[mface->v4].co); - } - else { - normal_tri_v3(nor, mvert[mface->v1].co, mvert[mface->v2].co, mvert[mface->v3].co); - } - glNormal3fv(nor); - } - glVertex3fv(mvert[mface->v1].co); - glVertex3fv(mvert[mface->v2].co); - glVertex3fv(mvert[mface->v3].co); - if (mface->v4) { - glVertex3fv(mvert[mface->v4].co); - } - } - else { /* shademodel == GL_SMOOTH */ - glNormal3sv(mvert[mface->v1].no); - glVertex3fv(mvert[mface->v1].co); - glNormal3sv(mvert[mface->v2].no); - glVertex3fv(mvert[mface->v2].co); - glNormal3sv(mvert[mface->v3].no); - glVertex3fv(mvert[mface->v3].co); - if (mface->v4) { - glNormal3sv(mvert[mface->v4].no); - glVertex3fv(mvert[mface->v4].co); - } - } - } - - if (nors) - nors += 3; - if (lnors) - lnors++; - } - glEnd(); - } - else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - if (!GPU_buffer_legacy(dm)) { - glShadeModel(GL_SMOOTH); - for (a = 0; a < dm->drawObject->totmaterial; a++) { - if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) { - glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start, - dm->drawObject->materials[a].totpoint); - } - } + + GPU_vertex_setup(dm); + GPU_normal_setup(dm); + glShadeModel(GL_SMOOTH); + for (a = 0; a < dm->drawObject->totmaterial; a++) { + if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) { + glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start, + dm->drawObject->materials[a].totpoint); } - GPU_buffer_unbind(); } + GPU_buffer_unbind(); glShadeModel(GL_FLAT); } static void cdDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, - DMSetDrawOptions drawParamsMapped, + DMSetDrawOptionsMappedTex drawParamsMapped, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag uvflag) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - MVert *mv = cddm->mvert; const MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE); - const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL); - const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE); MCol *mcol; int i, orig; int colType, startFace = 0; bool use_tface = (uvflag & DM_DRAW_USE_ACTIVE_UV) != 0; + int tottri; + int next_actualFace; + /* double lookup */ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); @@ -717,208 +547,81 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, } cdDM_update_normals_from_pbvh(dm); - - if (GPU_buffer_legacy(dm)) { - int mat_nr_cache = -1; - MTFace *tf_base = DM_get_tessface_data_layer(dm, CD_MTFACE); - MTFace *tf_stencil_base = NULL; - MTFace *tf_stencil = NULL; - - if (uvflag & DM_DRAW_USE_TEXPAINT_UV) { - int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); - tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + + GPU_vertex_setup(dm); + GPU_normal_setup(dm); + if (uvflag & DM_DRAW_USE_TEXPAINT_UV) + GPU_texpaint_uv_setup(dm); + else + GPU_uv_setup(dm); + if (mcol) { + GPU_color_setup(dm, colType); + } + + tottri = dm->drawObject->tot_triangle_point / 3; + next_actualFace = dm->drawObject->triangle_to_mface[0]; + + glShadeModel(GL_SMOOTH); + /* lastFlag = 0; */ /* UNUSED */ + for (i = 0; i < tottri; i++) { + int actualFace = next_actualFace; + DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; + int flush = 0; + + if (i != tottri - 1) + next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; + + if (drawParams) { + draw_option = drawParams(use_tface && tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr); } - - DEBUG_VBO("Using legacy code. cdDM_drawFacesTex_common\n"); - for (i = 0; i < dm->numTessFaceData; i++, mf++) { - MVert *mvert; - DMDrawOption draw_option; - unsigned char *cp = NULL; - - if (uvflag & DM_DRAW_USE_TEXPAINT_UV) { - if (mf->mat_nr != mat_nr_cache) { - tf_base = DM_paint_uvlayer_active_get(dm, mf->mat_nr); - - mat_nr_cache = mf->mat_nr; - } - } - - tf = tf_base ? tf_base + i : NULL; - tf_stencil = tf_stencil_base ? tf_stencil_base + i : NULL; - - if (drawParams) { - draw_option = drawParams(use_tface ? tf : NULL, (mcol != NULL), mf->mat_nr); - } - else { - if (index_mf_to_mpoly) { - orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i); - if (orig == ORIGINDEX_NONE) { - /* XXX, this is not really correct - * it will draw the previous faces context for this one when we don't know its settings. - * but better then skipping it altogether. - campbell */ - draw_option = DM_DRAW_OPTION_NORMAL; - } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, orig); - } - else { - if (nors) { - nors += 3; - } - continue; - } + else { + if (index_mf_to_mpoly) { + orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace); + if (orig == ORIGINDEX_NONE) { + /* XXX, this is not really correct + * it will draw the previous faces context for this one when we don't know its settings. + * but better then skipping it altogether. - campbell */ + draw_option = DM_DRAW_OPTION_NORMAL; } else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, i); - } - else { - if (nors) { - nors += 3; - } - continue; + draw_option = drawParamsMapped(userData, orig, mf[actualFace].mat_nr); } } - - if (draw_option != DM_DRAW_OPTION_SKIP) { - if (draw_option != DM_DRAW_OPTION_NO_MCOL && mcol) - cp = (unsigned char *) &mcol[i * 4]; - - if (!(lnors || (mf->flag & ME_SMOOTH))) { - if (nors) { - glNormal3fv(nors); - } - else { - float nor[3]; - if (mf->v4) { - normal_quad_v3(nor, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co); - } - else { - normal_tri_v3(nor, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co); - } - glNormal3fv(nor); - } - } - - glBegin(mf->v4 ? GL_QUADS : GL_TRIANGLES); - if (tf) glTexCoord2fv(tf->uv[0]); - if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[0]); - if (cp) glColor3ub(cp[3], cp[2], cp[1]); - mvert = &mv[mf->v1]; - if (lnors) glNormal3sv((const GLshort *)lnors[0][0]); - else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); - glVertex3fv(mvert->co); - - if (tf) glTexCoord2fv(tf->uv[1]); - if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[1]); - if (cp) glColor3ub(cp[7], cp[6], cp[5]); - mvert = &mv[mf->v2]; - if (lnors) glNormal3sv((const GLshort *)lnors[0][1]); - else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); - glVertex3fv(mvert->co); - - if (tf) glTexCoord2fv(tf->uv[2]); - if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[2]); - if (cp) glColor3ub(cp[11], cp[10], cp[9]); - mvert = &mv[mf->v3]; - if (lnors) glNormal3sv((const GLshort *)lnors[0][2]); - else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); - glVertex3fv(mvert->co); - - if (mf->v4) { - if (tf) glTexCoord2fv(tf->uv[3]); - if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[3]); - if (cp) glColor3ub(cp[15], cp[14], cp[13]); - mvert = &mv[mf->v4]; - if (lnors) glNormal3sv((const GLshort *)lnors[0][3]); - else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); - glVertex3fv(mvert->co); - } - glEnd(); + else if (drawParamsMapped) { + draw_option = drawParamsMapped(userData, actualFace, mf[actualFace].mat_nr); } - - if (nors) - nors += 3; - if (lnors) - lnors++; - } - } - else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - if (uvflag & DM_DRAW_USE_TEXPAINT_UV) - GPU_texpaint_uv_setup(dm); - else - GPU_uv_setup(dm); - if (mcol) { - GPU_color_setup(dm, colType); } - - if (!GPU_buffer_legacy(dm)) { - int tottri = dm->drawObject->tot_triangle_point / 3; - int next_actualFace = dm->drawObject->triangle_to_mface[0]; - - glShadeModel(GL_SMOOTH); - /* lastFlag = 0; */ /* UNUSED */ - for (i = 0; i < tottri; i++) { - int actualFace = next_actualFace; - DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - int flush = 0; - - if (i != tottri - 1) - next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; - - if (drawParams) { - draw_option = drawParams(use_tface && tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr); - } - else { - if (index_mf_to_mpoly) { - orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace); - if (orig == ORIGINDEX_NONE) { - /* XXX, this is not really correct - * it will draw the previous faces context for this one when we don't know its settings. - * but better then skipping it altogether. - campbell */ - draw_option = DM_DRAW_OPTION_NORMAL; - } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, orig); - } - } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, actualFace); - } - } - - /* flush buffer if current triangle isn't drawable or it's last triangle */ - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == tottri - 1); - - if (!flush && compareDrawOptions) { - /* also compare draw options and flush buffer if they're different + + /* flush buffer if current triangle isn't drawable or it's last triangle */ + flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == tottri - 1); + + if (!flush && compareDrawOptions) { + /* also compare draw options and flush buffer if they're different * need for face selection highlight in edit mode */ - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - if (flush) { - int first = startFace * 3; - /* Add one to the length if we're drawing at the end of the array */ - int count = (i - startFace + (draw_option != DM_DRAW_OPTION_SKIP ? 1 : 0)) * 3; - - if (count) { - if (mcol && draw_option != DM_DRAW_OPTION_NO_MCOL) - GPU_color_switch(1); - else - GPU_color_switch(0); - - glDrawArrays(GL_TRIANGLES, first, count); - } - - startFace = i + 1; - } + flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; + } + + if (flush) { + int first = startFace * 3; + /* Add one to the length if we're drawing at the end of the array */ + int count = (i - startFace + (draw_option != DM_DRAW_OPTION_SKIP ? 1 : 0)) * 3; + + if (count) { + if (mcol && draw_option != DM_DRAW_OPTION_NO_MCOL) + GPU_color_switch(1); + else + GPU_color_switch(0); + + glDrawArrays(GL_TRIANGLES, first, count); } + + startFace = i + 1; } - - GPU_buffer_unbind(); - glShadeModel(GL_FLAT); } + + GPU_buffer_unbind(); + glShadeModel(GL_FLAT); + } static void cdDM_drawFacesTex(DerivedMesh *dm, @@ -968,7 +671,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, /* back-buffer always uses legacy since VBO's would need the * color array temporarily overwritten for drawing, then reset. */ - if (GPU_buffer_legacy(dm) || G.f & G_BACKBUFSEL) { + if (G.f & G_BACKBUFSEL) { DEBUG_VBO("Using legacy code. cdDM_drawMappedFaces\n"); for (i = 0; i < dm->numTessFaceData; i++, mf++) { int drawSmooth = ((flag & DM_DRAW_ALWAYS_SMOOTH) || lnors) ? 1 : (mf->flag & ME_SMOOTH); @@ -1070,79 +773,85 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, } else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ int prevstart = 0; + int tottri; + GPU_vertex_setup(dm); GPU_normal_setup(dm); if (useColors && mcol) { GPU_color_setup(dm, colType); } - if (!GPU_buffer_legacy(dm)) { - int tottri = dm->drawObject->tot_triangle_point / 3; - glShadeModel(GL_SMOOTH); + tottri = dm->drawObject->tot_triangle_point / 3; + glShadeModel(GL_SMOOTH); + + if (tottri == 0) { + /* avoid buffer problems in following code */ + } + if (setDrawOptions == NULL) { + /* just draw the entire face array */ + glDrawArrays(GL_TRIANGLES, 0, (tottri) * 3); + } + else { + /* we need to check if the next material changes */ + int next_actualFace = dm->drawObject->triangle_to_mface[0]; + int prev_mat_nr = -1; - if (tottri == 0) { - /* avoid buffer problems in following code */ - } - if (setDrawOptions == NULL) { - /* just draw the entire face array */ - glDrawArrays(GL_TRIANGLES, 0, (tottri) * 3); - } - else { - /* we need to check if the next material changes */ - int next_actualFace = dm->drawObject->triangle_to_mface[0]; + for (i = 0; i < tottri; i++) { + //int actualFace = dm->drawObject->triangle_to_mface[i]; + int actualFace = next_actualFace; + MFace *mface = mf + actualFace; + /*int drawSmooth = (flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : (mface->flag & ME_SMOOTH);*/ /* UNUSED */ + DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; + int flush = 0; - for (i = 0; i < tottri; i++) { - //int actualFace = dm->drawObject->triangle_to_mface[i]; - int actualFace = next_actualFace; - MFace *mface = mf + actualFace; - /*int drawSmooth = (flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : (mface->flag & ME_SMOOTH);*/ /* UNUSED */ - DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - int flush = 0; - - if (i != tottri - 1) - next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; - - orig = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace) : actualFace; - - if (orig == ORIGINDEX_NONE) + if (i != tottri - 1) + next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; + + orig = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace) : actualFace; + + if (mface->mat_nr != prev_mat_nr) { + if (setMaterial) draw_option = setMaterial(mface->mat_nr + 1, NULL); - else if (setDrawOptions != NULL) - draw_option = setDrawOptions(userData, orig); - - if (draw_option == DM_DRAW_OPTION_STIPPLE) { - glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple(stipple_quarttone); - } - - /* Goal is to draw as long of a contiguous triangle + + prev_mat_nr = mface->mat_nr; + } + + if (setDrawOptions != NULL && (orig != ORIGINDEX_NONE)) + draw_option = setDrawOptions(userData, orig); + + if (draw_option == DM_DRAW_OPTION_STIPPLE) { + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(stipple_quarttone); + } + + /* Goal is to draw as long of a contiguous triangle * array as possible, so draw when we hit either an * invisible triangle or at the end of the array */ - - /* flush buffer if current triangle isn't drawable or it's last triangle... */ - flush = (ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE)) || (i == tottri - 1); - - /* ... or when material setting is dissferent */ - flush |= mf[actualFace].mat_nr != mf[next_actualFace].mat_nr; - - if (!flush && compareDrawOptions) { - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - if (flush) { - int first = prevstart * 3; - /* Add one to the length if we're drawing at the end of the array */ - int count = (i - prevstart + (draw_option != DM_DRAW_OPTION_SKIP ? 1 : 0)) * 3; - - if (count) - glDrawArrays(GL_TRIANGLES, first, count); - - prevstart = i + 1; - - if (draw_option == DM_DRAW_OPTION_STIPPLE) - glDisable(GL_POLYGON_STIPPLE); - } + + /* flush buffer if current triangle isn't drawable or it's last triangle... */ + flush = (ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE)) || (i == tottri - 1); + + /* ... or when material setting is dissferent */ + flush |= mf[actualFace].mat_nr != mf[next_actualFace].mat_nr; + + if (!flush && compareDrawOptions) { + flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; + } + + if (flush) { + int first = prevstart * 3; + /* Add one to the length if we're drawing at the end of the array */ + int count = (i - prevstart + (draw_option != DM_DRAW_OPTION_SKIP ? 1 : 0)) * 3; + + if (count) + glDrawArrays(GL_TRIANGLES, first, count); + + prevstart = i + 1; + + if (draw_option == DM_DRAW_OPTION_STIPPLE) + glDisable(GL_POLYGON_STIPPLE); } } - + glShadeModel(GL_FLAT); } GPU_buffer_unbind(); @@ -1150,7 +859,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, } static void cdDM_drawMappedFacesTex(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, + DMSetDrawOptionsMappedTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag flag) { @@ -1270,7 +979,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, glShadeModel(GL_SMOOTH); - if (GPU_buffer_legacy(dm) || setDrawOptions != NULL) { + if (setDrawOptions != NULL) { DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n"); memset(&attribs, 0, sizeof(attribs)); @@ -1329,11 +1038,11 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, ln3 = &lnors[a][2]; ln4 = &lnors[a][3]; } - + cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v1, 0, ln1, smoothnormal); cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v2, 1, ln2, smoothnormal); cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, ln3, smoothnormal); - + if (mface->v4) cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v4, 3, ln4, smoothnormal); else @@ -1343,218 +1052,217 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, } else { GPUBuffer *buffer = NULL; - const char *varray = NULL; + char *varray = NULL; int numdata = 0, elementsize = 0, offset; int start = 0, numfaces = 0 /* , prevdraw = 0 */ /* UNUSED */, curface = 0; int i; - + const MFace *mf = mface; GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/ memset(&attribs, 0, sizeof(attribs)); - + GPU_vertex_setup(dm); GPU_normal_setup(dm); - - if (!GPU_buffer_legacy(dm)) { - for (i = 0; i < dm->drawObject->tot_triangle_point / 3; i++) { - - a = dm->drawObject->triangle_to_mface[i]; - - mface = mf + a; - new_matnr = mface->mat_nr + 1; - - if (new_matnr != matnr) { - numfaces = curface - start; - if (numfaces > 0) { - - if (do_draw) { - - if (numdata != 0) { - - GPU_buffer_unlock(buffer); - - GPU_interleaved_attrib_setup(buffer, datatypes, numdata); - } - - glDrawArrays(GL_TRIANGLES, start * 3, numfaces * 3); - - if (numdata != 0) { - - GPU_buffer_free(buffer); - - buffer = NULL; - } - + + for (i = 0; i < dm->drawObject->tot_triangle_point / 3; i++) { + + a = dm->drawObject->triangle_to_mface[i]; + + mface = mf + a; + new_matnr = mface->mat_nr + 1; + + if (new_matnr != matnr) { + numfaces = curface - start; + if (numfaces > 0) { + + if (do_draw) { + + if (numdata != 0) { + + GPU_buffer_unlock(buffer); + + GPU_interleaved_attrib_setup(buffer, datatypes, numdata); + } + + glDrawArrays(GL_TRIANGLES, start * 3, numfaces * 3); + + if (numdata != 0) { + + GPU_buffer_free(buffer); + + buffer = NULL; } + } - numdata = 0; - start = curface; - /* prevdraw = do_draw; */ /* UNUSED */ - do_draw = setMaterial(matnr = new_matnr, &gattribs); - if (do_draw) { - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - - if (attribs.totorco && attribs.orco.array) { - datatypes[numdata].index = attribs.orco.gl_index; - datatypes[numdata].size = 3; + } + numdata = 0; + start = curface; + /* prevdraw = do_draw; */ /* UNUSED */ + do_draw = setMaterial(matnr = new_matnr, &gattribs); + if (do_draw) { + DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); + + if (attribs.totorco && attribs.orco.array) { + datatypes[numdata].index = attribs.orco.gl_index; + datatypes[numdata].size = 3; + datatypes[numdata].type = GL_FLOAT; + numdata++; + } + for (b = 0; b < attribs.tottface; b++) { + if (attribs.tface[b].array) { + datatypes[numdata].index = attribs.tface[b].gl_index; + datatypes[numdata].size = 2; datatypes[numdata].type = GL_FLOAT; numdata++; } - for (b = 0; b < attribs.tottface; b++) { - if (attribs.tface[b].array) { - datatypes[numdata].index = attribs.tface[b].gl_index; - datatypes[numdata].size = 2; - datatypes[numdata].type = GL_FLOAT; - numdata++; - } - } - for (b = 0; b < attribs.totmcol; b++) { - if (attribs.mcol[b].array) { - datatypes[numdata].index = attribs.mcol[b].gl_index; - datatypes[numdata].size = 4; - datatypes[numdata].type = GL_UNSIGNED_BYTE; - numdata++; - } - } - if (attribs.tottang && attribs.tang.array) { - datatypes[numdata].index = attribs.tang.gl_index; + } + for (b = 0; b < attribs.totmcol; b++) { + if (attribs.mcol[b].array) { + datatypes[numdata].index = attribs.mcol[b].gl_index; datatypes[numdata].size = 4; - datatypes[numdata].type = GL_FLOAT; + datatypes[numdata].type = GL_UNSIGNED_BYTE; numdata++; } - if (numdata != 0) { - elementsize = GPU_attrib_element_size(datatypes, numdata); - buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point); - if (buffer == NULL) { - GPU_buffer_unbind(); - dm->drawObject->legacy = 1; - return; - } - varray = GPU_buffer_lock_stream(buffer); - if (varray == NULL) { - GPU_buffer_unbind(); - GPU_buffer_free(buffer); - dm->drawObject->legacy = 1; - return; - } + } + if (attribs.tottang && attribs.tang.array) { + datatypes[numdata].index = attribs.tang.gl_index; + datatypes[numdata].size = 4; + datatypes[numdata].type = GL_FLOAT; + numdata++; + } + if (numdata != 0) { + elementsize = GPU_attrib_element_size(datatypes, numdata); + buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, false); + if (buffer == NULL) { + GPU_buffer_unbind(); + buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, true); + return; } - else { - /* if the buffer was set, don't use it again. - * prevdraw was assumed true but didnt run so set to false - [#21036] */ - /* prevdraw = 0; */ /* UNUSED */ - buffer = NULL; + varray = GPU_buffer_lock_stream(buffer); + if (varray == NULL) { + GPU_buffer_unbind(); + GPU_buffer_free(buffer); + fprintf(stderr, "Out of memory, can't draw object\n"); + return; } } + else { + /* if the buffer was set, don't use it again. + * prevdraw was assumed true but didnt run so set to false - [#21036] */ + /* prevdraw = 0; */ /* UNUSED */ + buffer = NULL; + } } - + } + + if (do_draw && numdata != 0) { + offset = 0; + if (attribs.totorco && attribs.orco.array) { + copy_v3_v3((float *)&varray[elementsize * curface * 3], (float *)attribs.orco.array[mface->v1]); + copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize], (float *)attribs.orco.array[mface->v2]); + copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize * 2], (float *)attribs.orco.array[mface->v3]); + offset += sizeof(float) * 3; + } + for (b = 0; b < attribs.tottface; b++) { + if (attribs.tface[b].array) { + MTFace *tf = &attribs.tface[b].array[a]; + copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset], tf->uv[0]); + copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize], tf->uv[1]); + + copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tf->uv[2]); + offset += sizeof(float) * 2; + } + } + for (b = 0; b < attribs.totmcol; b++) { + if (attribs.mcol[b].array) { + MCol *cp = &attribs.mcol[b].array[a * 4 + 0]; + GLubyte col[4]; + col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; + copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset], (char *)col); + cp = &attribs.mcol[b].array[a * 4 + 1]; + col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; + copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize], (char *)col); + cp = &attribs.mcol[b].array[a * 4 + 2]; + col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; + copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize * 2], (char *)col); + offset += sizeof(unsigned char) * 4; + } + } + if (attribs.tottang && attribs.tang.array) { + const float *tang = attribs.tang.array[a * 4 + 0]; + copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset], tang); + tang = attribs.tang.array[a * 4 + 1]; + copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize], tang); + tang = attribs.tang.array[a * 4 + 2]; + copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tang); + offset += sizeof(float) * 4; + } + (void)offset; + } + curface++; + if (mface->v4) { if (do_draw && numdata != 0) { offset = 0; if (attribs.totorco && attribs.orco.array) { - copy_v3_v3((float *)&varray[elementsize * curface * 3], (float *)attribs.orco.array[mface->v1]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize], (float *)attribs.orco.array[mface->v2]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize * 2], (float *)attribs.orco.array[mface->v3]); + copy_v3_v3((float *)&varray[elementsize * curface * 3], (float *)attribs.orco.array[mface->v3]); + copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize], (float *)attribs.orco.array[mface->v4]); + copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize * 2], (float *)attribs.orco.array[mface->v1]); offset += sizeof(float) * 3; } for (b = 0; b < attribs.tottface; b++) { if (attribs.tface[b].array) { MTFace *tf = &attribs.tface[b].array[a]; - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset], tf->uv[0]); - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize], tf->uv[1]); - - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tf->uv[2]); + copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset], tf->uv[2]); + copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize], tf->uv[3]); + copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tf->uv[0]); offset += sizeof(float) * 2; } } for (b = 0; b < attribs.totmcol; b++) { if (attribs.mcol[b].array) { - MCol *cp = &attribs.mcol[b].array[a * 4 + 0]; + MCol *cp = &attribs.mcol[b].array[a * 4 + 2]; GLubyte col[4]; col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 1]; + cp = &attribs.mcol[b].array[a * 4 + 3]; col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 2]; + cp = &attribs.mcol[b].array[a * 4 + 0]; col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize * 2], (char *)col); offset += sizeof(unsigned char) * 4; } } if (attribs.tottang && attribs.tang.array) { - const float *tang = attribs.tang.array[a * 4 + 0]; + const float *tang = attribs.tang.array[a * 4 + 2]; copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset], tang); - tang = attribs.tang.array[a * 4 + 1]; + tang = attribs.tang.array[a * 4 + 3]; copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize], tang); - tang = attribs.tang.array[a * 4 + 2]; + tang = attribs.tang.array[a * 4 + 0]; copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tang); offset += sizeof(float) * 4; } (void)offset; } curface++; - if (mface->v4) { - if (do_draw && numdata != 0) { - offset = 0; - if (attribs.totorco && attribs.orco.array) { - copy_v3_v3((float *)&varray[elementsize * curface * 3], (float *)attribs.orco.array[mface->v3]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize], (float *)attribs.orco.array[mface->v4]); - copy_v3_v3((float *)&varray[elementsize * curface * 3 + elementsize * 2], (float *)attribs.orco.array[mface->v1]); - offset += sizeof(float) * 3; - } - for (b = 0; b < attribs.tottface; b++) { - if (attribs.tface[b].array) { - MTFace *tf = &attribs.tface[b].array[a]; - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset], tf->uv[2]); - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize], tf->uv[3]); - copy_v2_v2((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tf->uv[0]); - offset += sizeof(float) * 2; - } - } - for (b = 0; b < attribs.totmcol; b++) { - if (attribs.mcol[b].array) { - MCol *cp = &attribs.mcol[b].array[a * 4 + 2]; - GLubyte col[4]; - col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 3]; - col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize], (char *)col); - cp = &attribs.mcol[b].array[a * 4 + 0]; - col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a; - copy_v4_v4_char((char *)&varray[elementsize * curface * 3 + offset + elementsize * 2], (char *)col); - offset += sizeof(unsigned char) * 4; - } - } - if (attribs.tottang && attribs.tang.array) { - const float *tang = attribs.tang.array[a * 4 + 2]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset], tang); - tang = attribs.tang.array[a * 4 + 3]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize], tang); - tang = attribs.tang.array[a * 4 + 0]; - copy_v4_v4((float *)&varray[elementsize * curface * 3 + offset + elementsize * 2], tang); - offset += sizeof(float) * 4; - } - (void)offset; - } - curface++; - i++; - } + i++; } - numfaces = curface - start; - if (numfaces > 0) { - if (do_draw) { - if (numdata != 0) { - GPU_buffer_unlock(buffer); - GPU_interleaved_attrib_setup(buffer, datatypes, numdata); - } - glDrawArrays(GL_TRIANGLES, start * 3, (curface - start) * 3); + } + numfaces = curface - start; + if (numfaces > 0) { + if (do_draw) { + if (numdata != 0) { + GPU_buffer_unlock(buffer); + GPU_interleaved_attrib_setup(buffer, datatypes, numdata); } + glDrawArrays(GL_TRIANGLES, start * 3, (curface - start) * 3); } - GPU_buffer_unbind(); } + GPU_buffer_unbind(); + GPU_buffer_free(buffer); } - + glShadeModel(GL_FLAT); } @@ -2725,10 +2433,10 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2) (pk1->totloops == pk2->totloops)) { /* Equality - note that this does not mean equality of polys */ - return 0; + return false; } else { - return 1; + return true; } } diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index a63e06c7cb8..89c3e4b0cfc 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -50,7 +50,6 @@ #include "IMB_colormanagement.h" -#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" /* ********************************* color curve ********************* */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 574001e2f80..f591fe857f8 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -229,7 +229,8 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob) * of a matrix from one space to another for constraint evaluation. * For now, this is only implemented for Objects and PoseChannels. */ -void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to) +void BKE_constraint_mat_convertspace( + Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale) { float diff_mat[4][4]; float imat[4][4]; @@ -252,7 +253,7 @@ void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[ /* use pose-space as stepping stone for other spaces... */ if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); } break; } @@ -288,7 +289,7 @@ void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[ /* use pose-space as stepping stone for other spaces */ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) { /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); } break; } @@ -303,7 +304,7 @@ void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[ /* use pose-space as stepping stone for other spaces */ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); } break; } @@ -323,8 +324,17 @@ void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[ /* Local space in this case will have to be defined as local to the owner's * transform-property-rotated axes. So subtract this rotation component. */ + /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as + * global space! + * Think what we want actually here is some kind of 'Final Space', i.e. once transformations + * are applied - users are often confused about this too, this is not consistent with bones + * local space either... Meh :| + * --mont29 + */ BKE_object_to_mat4(ob, diff_mat); - normalize_m4(diff_mat); + if (!keep_scale) { + normalize_m4(diff_mat); + } zero_v3(diff_mat[3]); invert_m4_m4_safe(imat, diff_mat); @@ -342,8 +352,11 @@ void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[ /* Local space in this case will have to be defined as local to the owner's * transform-property-rotated axes. So add back this rotation component. */ + /* XXX See comment above for world->local case... */ BKE_object_to_mat4(ob, diff_mat); - normalize_m4(diff_mat); + if (!keep_scale) { + normalize_m4(diff_mat); + } zero_v3(diff_mat[3]); mul_m4_m4m4(mat, diff_mat, mat); @@ -511,7 +524,7 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m /* Case OBJECT */ if (!strlen(substring)) { copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); } /* Case VERTEXGROUP */ /* Current method just takes the average location of all the points in the @@ -524,11 +537,11 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m */ else if (ob->type == OB_MESH) { contarget_get_mesh_mat(ob, substring, mat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); } else if (ob->type == OB_LATTICE) { contarget_get_lattice_mat(ob, substring, mat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); } /* Case BONE */ else { @@ -561,7 +574,7 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m copy_m4_m4(mat, ob->obmat); /* convert matrix space as required */ - BKE_constraint_mat_convertspace(ob, pchan, mat, from, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false); } } @@ -1971,7 +1984,7 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa static void pycon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { #ifndef WITH_PYTHON - (void)con; (void)cob; (void)targets; /* unused */ + UNUSED_VARS(con, cob, targets); return; #else bPythonConstraint *data = con->data; @@ -2709,7 +2722,7 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t } if (bulge < 1.0f) { if (data->flag & STRETCHTOCON_USE_BULGE_MIN) { - float bulge_min = CLAMPIS(data->bulge_max, 0.0f, 1.0f); + float bulge_min = CLAMPIS(data->bulge_min, 0.0f, 1.0f); float hard = max_ff(bulge, bulge_min); float range = 1.0f - bulge_min; @@ -3461,16 +3474,13 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra } /* transform normal into requested space */ - /* We cannot use BKE_constraint_mat_convertspace here, it does not take into account scaling... - * In theory we would not need it, but in this case we'd have to tweak SpaceTransform to also - * optionally ignore scaling when handling normals - simpler to directly call BKE_object_to_mat4 - * if needed! See T42447. */ - if (scon->projAxisSpace == CONSTRAINT_SPACE_WORLD) { - BKE_object_to_mat4(cob->ob, mat); - invert_m4(mat); - mul_mat3_m4_v3(mat, no); - } - /* Else, we remain in local space, nothing to do. */ + /* Note that in this specific case, we need to keep scaling in non-parented 'local2world' object + * case, because SpaceTransform also takes it into account when handling normals. See T42447. */ + unit_m4(mat); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, mat, + CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true); + invert_m4(mat); + mul_mat3_m4_v3(mat, no); if (normalize_v3(no) < FLT_EPSILON) { fail = true; @@ -3688,6 +3698,9 @@ static void splineik_new_data(void *cdata) bSplineIKConstraint *data = (bSplineIKConstraint *)cdata; data->chainlen = 1; + data->bulge = 1.0; + data->bulge_max = 1.0f; + data->bulge_min = 1.0f; } static void splineik_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -4395,10 +4408,10 @@ bool BKE_constraint_remove(ListBase *list, bConstraint *con) if (con) { BKE_constraint_free_data(con); BLI_freelinkN(list, con); - return 1; + return true; } else - return 0; + return false; } /* ......... */ @@ -4662,15 +4675,15 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan) /* On bone-level, check if bone is on proxy-protected layer */ if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected)) - return 1; + return true; } else { /* FIXME: constraints on object-level are not handled well yet */ - return 1; + return true; } } - return 0; + return false; } /* -------- Target-Matrix Stuff ------- */ @@ -4816,7 +4829,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime) copy_m4_m4(oldmat, cob->matrix); /* move owner matrix into right space */ - BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); /* prepare targets for constraint solving */ BKE_constraint_targets_for_solving_get(con, cob, &targets, ctime); @@ -4834,7 +4847,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime) /* move owner back into worldspace for next constraint/other business */ if ((con->flag & CONSTRAINT_SPACEONCE) == 0) - BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false); /* Interpolate the enforcement, to blend result of constraint into final owner transform * - all this happens in worldspace to prevent any weirdness creeping in ([#26014] and [#25725]), diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 4b0adafef4b..8f6c9735aaf 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -37,6 +37,7 @@ #include "DNA_windowmanager_types.h" #include "DNA_object_types.h" #include "DNA_linestyle_types.h" +#include "DNA_gpencil_types.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -257,7 +258,7 @@ static void *ctx_wm_python_context_get( } } #else - (void)C, (void)member, (void)member_type; + UNUSED_VARS(C, member, member_type); #endif /* don't allow UI context access from non-main threads */ @@ -1090,3 +1091,34 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_pose_bones", list); } + +bGPdata *CTX_data_gpencil_data(const bContext *C) +{ + return ctx_data_pointer_get(C, "gpencil_data"); +} + +bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_gpencil_layer"); +} + +bGPDframe *CTX_data_active_gpencil_frame(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_gpencil_frame"); +} + +int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "visible_gpencil_layers", list); +} + +int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "editable_gpencil_layers", list); +} + +int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "editable_gpencil_strokes", list); +} + diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 937ceffc765..3abe3c58562 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -237,6 +237,10 @@ Curve *BKE_curve_copy(Curve *cu) id_us_plus((ID *)cun->vfonti); id_us_plus((ID *)cun->vfontbi); + if (cu->id.lib) { + BKE_id_lib_local_paths(G.main, cu->id.lib, &cun->id); + } + return cun; } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 8f02ccdd8b2..89ebed258a3 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -48,6 +48,7 @@ #include "BLI_string.h" #include "BLI_path_util.h" #include "BLI_math.h" +#include "BLI_math_color_blend.h" #include "BLI_mempool.h" #include "BLF_translation.h" @@ -56,6 +57,8 @@ #include "BKE_customdata_file.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" #include "BKE_multires.h" #include "bmesh.h" @@ -92,7 +95,7 @@ typedef struct LayerTypeInfo { * (deep copy if appropriate) * if NULL, memcpy is used */ - void (*copy)(const void *source, void *dest, int count); + cd_copy copy; /** * a function to free any dynamically allocated components of this @@ -117,8 +120,7 @@ typedef struct LayerTypeInfo { * applying changes while reading from sources. * See bug [#32395] - Campbell. */ - void (*interp)(void **sources, const float *weights, const float *sub_weights, - int count, void *dest); + cd_interp interp; /** a function to swap the data in corners of the element */ void (*swap)(void *data, const int *corner_indices); @@ -134,7 +136,7 @@ typedef struct LayerTypeInfo { void (*initminmax)(void *min, void *max); void (*add)(void *data1, const void *data2); void (*dominmax)(const void *data1, void *min, void *max); - void (*copyvalue)(const void *source, void *dest); + void (*copyvalue)(const void *source, void *dest, const int mixmode, const float mixfactor); /** a function to read data from a cdf file */ int (*read)(CDataFile *cdf, void *data, int count); @@ -620,14 +622,53 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size)) } /* --------- */ -static void layerCopyValue_mloopcol(const void *source, void *dest) +static void layerCopyValue_mloopcol(const void *source, void *dest, const int mixmode, const float mixfactor) { const MLoopCol *m1 = source; MLoopCol *m2 = dest; - - m2->r = m1->r; - m2->g = m1->g; - m2->b = m1->b; + unsigned char tmp_col[4]; + + if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* Modes that do a full copy or nothing. */ + if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* TODO: Check for a real valid way to get 'factor' value of our dest color? */ + const float f = ((float)m2->r + (float)m2->g + (float)m2->b) / 3.0f; + if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) { + return; /* Do Nothing! */ + } + else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) { + return; /* Do Nothing! */ + } + } + m2->r = m1->r; + m2->g = m1->g; + m2->b = m1->b; + } + else { /* Modes that support 'real' mix factor. */ + unsigned char src[4] = {m1->r, m1->g, m1->b, m1->a}; + unsigned char dst[4] = {m2->r, m2->g, m2->b, m2->a}; + + if (mixmode == CDT_MIX_MIX) { + blend_color_mix_byte(tmp_col, dst, src); + } + else if (mixmode == CDT_MIX_ADD) { + blend_color_add_byte(tmp_col, dst, src); + } + else if (mixmode == CDT_MIX_SUB) { + blend_color_sub_byte(tmp_col, dst, src); + } + else if (mixmode == CDT_MIX_MUL) { + blend_color_mul_byte(tmp_col, dst, src); + } + else { + memcpy(tmp_col, src, sizeof(tmp_col)); + } + blend_color_interpolate_byte(dst, dst, tmp_col, mixfactor); + + m2->r = (char)dst[0]; + m2->g = (char)dst[1]; + m2->b = (char)dst[2]; + } m2->a = m1->a; } @@ -758,12 +799,19 @@ static int layerMaxNum_mloopcol(void) return MAX_MCOL; } -static void layerCopyValue_mloopuv(const void *source, void *dest) +static void layerCopyValue_mloopuv(const void *source, void *dest, const int mixmode, const float mixfactor) { const MLoopUV *luv1 = source; MLoopUV *luv2 = dest; - copy_v2_v2(luv2->uv, luv1->uv); + /* We only support a limited subset of advanced mixing here - namely the mixfactor interpolation. */ + + if (mixmode == CDT_MIX_NOMIX) { + copy_v2_v2(luv2->uv, luv1->uv); + } + else { + interp_v2_v2v2(luv2->uv, luv2->uv, luv1->uv, mixfactor); + } } static bool layerEqual_mloopuv(const void *data1, const void *data2) @@ -833,7 +881,8 @@ static void layerInterp_mloopuv(void **sources, const float *weights, } /* origspace is almost exact copy of mloopuv's, keep in sync */ -static void layerCopyValue_mloop_origspace(const void *source, void *dest) +static void layerCopyValue_mloop_origspace(const void *source, void *dest, + const int UNUSED(mixmode), const float UNUSED(mixfactor)) { const OrigSpaceLoop *luv1 = source; OrigSpaceLoop *luv2 = dest; @@ -1798,7 +1847,8 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index) const int n = index - CustomData_get_layer_index(data, type); int i; - if (index < 0) return 0; + if (index < 0) + return false; customData_free_layer__internal(&data->layers[index], totelem); @@ -1828,14 +1878,15 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index) customData_update_offsets(data); - return 1; + return true; } bool CustomData_free_layer_active(CustomData *data, int type, int totelem) { int index = 0; index = CustomData_get_active_layer_index(data, type); - if (index == -1) return 0; + if (index == -1) + return false; return CustomData_free_layer(data, type, totelem, index); } @@ -1942,7 +1993,8 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type) /* get the layer index of the first layer of type */ layer_index = CustomData_get_active_layer_index(data, type); - if (layer_index == -1) return 0; + if (layer_index == -1) + return false; layer = &data->layers[layer_index]; @@ -2258,16 +2310,23 @@ int CustomData_get_n_offset(const CustomData *data, int type, int n) bool CustomData_set_layer_name(const CustomData *data, int type, int n, const char *name) { /* get the layer index of the first layer of type */ - int layer_index = CustomData_get_layer_index_n(data, type, n); + const int layer_index = CustomData_get_layer_index_n(data, type, n); - if (layer_index == -1) return false; - if (!name) return false; + if ((layer_index == -1) || !name) + return false; BLI_strncpy(data->layers[layer_index].name, name, sizeof(data->layers[layer_index].name)); return true; } +const char *CustomData_get_layer_name(const CustomData *data, int type, int n) +{ + const int layer_index = CustomData_get_layer_index_n(data, type, n); + + return (layer_index == -1) ? NULL : data->layers[layer_index].name; +} + void *CustomData_set_layer(const CustomData *data, int type, void *ptr) { /* get the layer index of the first layer of type */ @@ -2761,11 +2820,28 @@ void CustomData_data_copy_value(int type, const void *source, void *dest) if (!dest) return; if (typeInfo->copyvalue) - typeInfo->copyvalue(source, dest); + typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f); else memcpy(dest, source, typeInfo->size); } +/* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into + * another, while not overwriting anything else (e.g. flags)*/ +void CustomData_data_mix_value(int type, const void *source, void *dest, const int mixmode, const float mixfactor) +{ + const LayerTypeInfo *typeInfo = layerType_getInfo(type); + + if (!dest) return; + + if (typeInfo->copyvalue) { + typeInfo->copyvalue(source, dest, mixmode, mixfactor); + } + else { + /* Mere copy if no advanced interpolation is supported. */ + memcpy(dest, source, typeInfo->size); + } +} + bool CustomData_data_equals(int type, const void *data1, const void *data2) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -3461,3 +3537,233 @@ void CustomData_external_remove_object(CustomData *data, ID *id) } #endif +/* ********** Mesh-to-mesh data transfer ********** */ +static void copy_bit_flag(void *dst, void *src, const size_t data_size, const uint64_t flag) +{ +#define COPY_BIT_FLAG(_type, _dst, _src, _f) \ +{ \ + const _type _val = *((_type *)(_src)) & ((_type)(_f)); \ + *((_type *)(_dst)) &= ~((_type)(_f)); \ + *((_type *)(_dst)) |= _val; \ +} (void) 0 + + switch (data_size) { + case 1: + COPY_BIT_FLAG(uint8_t, dst, src, flag); + break; + case 2: + COPY_BIT_FLAG(uint16_t, dst, src, flag); + break; + case 4: + COPY_BIT_FLAG(uint32_t, dst, src, flag); + break; + case 8: + COPY_BIT_FLAG(uint64_t, dst, src, flag); + break; + default: + //printf("ERROR %s: Unknown flags-container size (%zu)\n", __func__, datasize); + break; + } + +#undef COPY_BIT_FLAG +} + +static bool check_bit_flag(void *data, const size_t data_size, const uint64_t flag) +{ + switch (data_size) { + case 1: + return ((*((uint8_t *)data) & ((uint8_t)flag)) != 0); + case 2: + return ((*((uint16_t *)data) & ((uint16_t)flag)) != 0); + case 4: + return ((*((uint32_t *)data) & ((uint32_t)flag)) != 0); + case 8: + return ((*((uint64_t *)data) & ((uint64_t)flag)) != 0); + default: + //printf("ERROR %s: Unknown flags-container size (%zu)\n", __func__, datasize); + return false; + } +} + +static void customdata_data_transfer_interp_generic( + const CustomDataTransferLayerMap *laymap, void *data_dst, void **sources, const float *weights, const int count, + const float mix_factor) +{ + /* Fake interpolation, we actually copy highest weighted source to dest. + * Note we also handle bitflags here, in which case we rather choose to transfer value of elements totaling + * more than 0.5 of weight. */ + + int best_src_idx = 0; + + const int data_type = laymap->data_type; + const int mix_mode = laymap->mix_mode; + + size_t data_size; + const uint64_t data_flag = laymap->data_flag; + + cd_interp interp_cd = NULL; + cd_copy copy_cd = NULL; + + void *tmp_dst; + + if (!sources) { + /* Not supported here, abort. */ + return; + } + + if (data_type & CD_FAKE) { + data_size = laymap->data_size; + } + else { + const LayerTypeInfo *type_info = layerType_getInfo(data_type); + + data_size = (size_t)type_info->size; + interp_cd = type_info->interp; + copy_cd = type_info->copy; + } + + tmp_dst = MEM_mallocN(data_size, __func__); + + if (count > 1 && !interp_cd) { + int i; + + if (data_flag) { + /* Boolean case, we can 'interpolate' in two groups, and choose value from highest weighted group. */ + float tot_weight_true = 0.0f; + int item_true_idx = -1, item_false_idx = -1; + + for (i = 0; i < count; i++) { + if (check_bit_flag(sources[i], data_size, data_flag)) { + tot_weight_true += weights[i]; + item_true_idx = i; + } + else { + item_false_idx = i; + } + } + best_src_idx = (tot_weight_true >= 0.5f) ? item_true_idx : item_false_idx; + } + else { + /* We just choose highest weighted source. */ + float max_weight = 0.0f; + + for (i = 0; i < count; i++) { + if (weights[i] > max_weight) { + max_weight = weights[i]; + best_src_idx = i; + } + } + } + } + + BLI_assert(best_src_idx >= 0); + + if (interp_cd) { + interp_cd(sources, weights, NULL, count, (char *)tmp_dst); + } + else if (data_flag) { + copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag); + } + /* No interpolation, just copy highest weight source element's data. */ + else if (copy_cd) { + copy_cd((char *)sources[best_src_idx], (char *)tmp_dst, 1); + } + else { + memcpy(tmp_dst, sources[best_src_idx], data_size); + } + + if (data_flag) { + /* Bool flags, only copy if dest data is set (resp. unset) - only 'advanced' modes we can support here! */ + if (mix_factor >= 0.5f && + ((mix_mode == CDT_MIX_TRANSFER) || + (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && check_bit_flag(data_dst, data_size, data_flag)) || + (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD && !check_bit_flag(data_dst, data_size, data_flag)))) + { + copy_bit_flag(data_dst, tmp_dst, data_size, data_flag); + } + } + else if (!(data_type & CD_FAKE)) { + CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor); + } + /* Else we can do nothing by default, needs custom interp func! + * Note this is here only for sake of consistency, not expected to be used much actually? */ + else { + if (mix_factor >= 0.5f) { + memcpy(data_dst, tmp_dst, data_size); + } + } + + MEM_freeN(tmp_dst); +} + +void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap) +{ + MeshPairRemapItem *mapit = me_remap->items; + const int totelem = me_remap->items_num; + int i; + + const int data_type = laymap->data_type; + void *data_src = laymap->data_src; + void *data_dst = laymap->data_dst; + + size_t data_step; + size_t data_size; + size_t data_offset; + + cd_datatransfer_interp interp = NULL; + + size_t tmp_buff_size = 32; + void **tmp_data_src = NULL; + + /* Note: NULL data_src may happen and be valid (see vgroups...). */ + if (!data_dst) { + return; + } + + if (data_src) { + tmp_data_src = MEM_mallocN(sizeof(*tmp_data_src) * tmp_buff_size, __func__); + } + + if (data_type & CD_FAKE) { + data_step = laymap->elem_size; + data_size = laymap->data_size; + data_offset = laymap->data_offset; + } + else { + const LayerTypeInfo *type_info = layerType_getInfo(data_type); + + /* Note: we can use 'fake' CDLayers, like e.g. for crease, bweight, etc. :/ */ + data_size = (size_t)type_info->size; + data_step = laymap->elem_size ? laymap->elem_size : data_size; + data_offset = laymap->data_offset; + } + + interp = laymap->interp ? laymap->interp : customdata_data_transfer_interp_generic; + + for (i = 0; i < totelem; i++, data_dst = (char *)data_dst + data_step, mapit++) { + const int sources_num = mapit->sources_num; + const float mix_factor = laymap->mix_weights ? laymap->mix_weights[i] : laymap->mix_factor; + int j; + + if (!sources_num) { + /* No sources for this element, skip it. */ + continue; + } + + if (tmp_data_src) { + if (UNLIKELY(sources_num > tmp_buff_size)) { + tmp_buff_size = (size_t)sources_num; + tmp_data_src = MEM_reallocN(tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size); + } + + for (j = 0; j < sources_num; j++) { + const size_t src_idx = (size_t)mapit->indices_src[j]; + tmp_data_src[j] = (char *)data_src + data_step * src_idx + data_offset; + } + } + + interp(laymap, (char *)data_dst + data_offset, tmp_data_src, mapit->weights_src, sources_num, mix_factor); + } + + MEM_SAFE_FREE(tmp_data_src); +} diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c new file mode 100644 index 00000000000..d41c74770f1 --- /dev/null +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -0,0 +1,1241 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/data_transfer.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_customdata_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_array.h" +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_data_transfer.h" +#include "BKE_deform.h" +#include "BKE_DerivedMesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" +#include "BKE_object.h" +#include "BKE_object_deform.h" +#include "BKE_report.h" + +#include "data_transfer_intern.h" + + +CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types) +{ + CustomDataMask cddata_mask = 0; + int i; + + for (i = 0; i < DT_TYPE_MAX; i++) { + const int dtdata_type = 1 << i; + int cddata_type; + + if (!(dtdata_types & dtdata_type)) { + continue; + } + + cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); + if (!(cddata_type & CD_FAKE)) { + cddata_mask |= 1LL << cddata_type; + } + else if (cddata_type == CD_FAKE_MDEFORMVERT) { + cddata_mask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */ + } + else if (cddata_type == CD_FAKE_UV) { + cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV; + } + } + + return cddata_mask; +} + +/* Check what can do each layer type (if it is actually handled by transferdata, if it supports advanced mixing... */ +bool BKE_object_data_transfer_get_dttypes_capacity( + const int dtdata_types, bool *r_advanced_mixing, bool *r_threshold) +{ + int i; + bool ret = false; + + *r_advanced_mixing = false; + *r_threshold = false; + + for (i = 0; (i < DT_TYPE_MAX) && !(ret && *r_advanced_mixing && *r_threshold); i++) { + const int dtdata_type = 1 << i; + + if (!(dtdata_types & dtdata_type)) { + continue; + } + + switch (dtdata_type) { + /* Vertex data */ + case DT_TYPE_MDEFORMVERT: + *r_advanced_mixing = true; + *r_threshold = true; + ret = true; + break; + case DT_TYPE_SKIN: + *r_threshold = true; + ret = true; + break; + case DT_TYPE_BWEIGHT_VERT: + ret = true; + break; + /* Edge data */ + case DT_TYPE_SHARP_EDGE: + *r_threshold = true; + ret = true; + break; + case DT_TYPE_SEAM: + *r_threshold = true; + ret = true; + break; + case DT_TYPE_CREASE: + ret = true; + break; + case DT_TYPE_BWEIGHT_EDGE: + ret = true; + break; + case DT_TYPE_FREESTYLE_EDGE: + *r_threshold = true; + ret = true; + break; + /* Loop/Poly data */ + case DT_TYPE_UV: + ret = true; + break; + case DT_TYPE_VCOL: + *r_advanced_mixing = true; + *r_threshold = true; + ret = true; + break; + case DT_TYPE_SHARP_FACE: + *r_threshold = true; + ret = true; + break; + case DT_TYPE_FREESTYLE_FACE: + *r_threshold = true; + ret = true; + break; + } + } + + return ret; +} + +int BKE_object_data_transfer_get_dttypes_item_types(const int dtdata_types) +{ + int i, ret = 0; + + for (i = 0; (i < DT_TYPE_MAX) && (ret ^ (ME_VERT | ME_EDGE | ME_LOOP | ME_POLY)); i++) { + const int dtdata_type = 1 << i; + + if (!(dtdata_types & dtdata_type)) { + continue; + } + + if (DT_DATATYPE_IS_VERT(dtdata_type)) { + ret |= ME_VERT; + } + if (DT_DATATYPE_IS_EDGE(dtdata_type)) { + ret |= ME_EDGE; + } + if (DT_DATATYPE_IS_LOOP(dtdata_type)) { + ret |= ME_LOOP; + } + if (DT_DATATYPE_IS_POLY(dtdata_type)) { + ret |= ME_POLY; + } + } + + return ret; +} + +int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type) +{ + switch (dtdata_type) { + case DT_TYPE_MDEFORMVERT: + return CD_FAKE_MDEFORMVERT; + case DT_TYPE_SHAPEKEY: + return CD_FAKE_SHAPEKEY; + case DT_TYPE_SKIN: + return CD_MVERT_SKIN; + case DT_TYPE_BWEIGHT_VERT: + return CD_FAKE_BWEIGHT; + + case DT_TYPE_SHARP_EDGE: + return CD_FAKE_SHARP; + case DT_TYPE_SEAM: + return CD_FAKE_SEAM; + case DT_TYPE_CREASE: + return CD_FAKE_CREASE; + case DT_TYPE_BWEIGHT_EDGE: + return CD_FAKE_BWEIGHT; + case DT_TYPE_FREESTYLE_EDGE: + return CD_FREESTYLE_EDGE; + + case DT_TYPE_UV: + return CD_FAKE_UV; + case DT_TYPE_SHARP_FACE: + return CD_FAKE_SHARP; + case DT_TYPE_FREESTYLE_FACE: + return CD_FREESTYLE_FACE; + + case DT_TYPE_VCOL: + return CD_MLOOPCOL; + + default: + BLI_assert(0); + } + return 0; /* Should never be reached! */ +} + +int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type) +{ + switch (dtdata_type) { + case DT_TYPE_MDEFORMVERT: + return DT_MULTILAYER_INDEX_MDEFORMVERT; + case DT_TYPE_SHAPEKEY: + return DT_MULTILAYER_INDEX_SHAPEKEY; + case DT_TYPE_UV: + return DT_MULTILAYER_INDEX_UV; + case DT_TYPE_VCOL: + return DT_MULTILAYER_INDEX_VCOL; + default: + return DT_MULTILAYER_INDEX_INVALID; + } +} + +/* ********** */ + +static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int cddata_type) +{ + switch (cddata_type) { + case CD_FAKE_UV: + return BKE_mesh_calc_islands_loop_poly_uv; + break; + default: + break; + } + return NULL; +} + +float data_transfer_interp_float_do( + const int mix_mode, const float val_dst, const float val_src, const float mix_factor) +{ + float val_ret; + + if (((mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && (val_dst < mix_factor)) || + (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD && (val_dst > mix_factor)))) + { + return val_dst; /* Do not affect destination. */ + } + + switch (mix_mode) { + case CDT_MIX_REPLACE_ABOVE_THRESHOLD: + case CDT_MIX_REPLACE_BELOW_THRESHOLD: + return val_src; + case CDT_MIX_MIX: + val_ret = (val_dst + val_src) * 0.5f; + break; + case CDT_MIX_ADD: + val_ret = val_dst + val_src; + break; + case CDT_MIX_SUB: + val_ret = val_dst - val_src; + break; + case CDT_MIX_MUL: + val_ret = val_dst * val_src; + break; + case CDT_MIX_TRANSFER: + default: + val_ret = val_src; + break; + } + return interpf(val_ret, val_dst, mix_factor); +} + +static void data_transfer_interp_char(const CustomDataTransferLayerMap *laymap, void *dest, + void **sources, const float *weights, const int count, const float mix_factor) +{ + char **data_src = (char **)sources; + char *data_dst = (char *)dest; + + const int mix_mode = laymap->mix_mode; + float val_src = 0.0f; + const float val_dst = (float)(*data_dst) / 255.0f; + + int i; + + for (i = count; i--;) { + val_src += ((float)(*data_src[i]) / 255.0f) * weights[i]; + } + + val_src = data_transfer_interp_float_do(mix_mode, val_dst, val_src, mix_factor); + + CLAMP(val_src, 0.0f, 1.0f); + + *data_dst = (char)(val_src * 255.0f); +} + +/* Helpers to match sources and destinations data layers (also handles 'conversions' in CD_FAKE cases). */ + +void data_transfer_layersmapping_add_item( + ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, + void *data_src, void *data_dst, const int data_src_n, const int data_dst_n, + const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag, + cd_datatransfer_interp interp) +{ + CustomDataTransferLayerMap *item = MEM_mallocN(sizeof(*item), __func__); + + BLI_assert(data_dst != NULL); + + item->data_type = cddata_type; + item->mix_mode = mix_mode; + item->mix_factor = mix_factor; + item->mix_weights = mix_weights; + + item->data_src = data_src; + item->data_dst = data_dst; + item->data_src_n = data_src_n; + item->data_dst_n = data_dst_n; + item->elem_size = elem_size; + + item->data_size = data_size; + item->data_offset = data_offset; + item->data_flag = data_flag; + + item->interp = interp; + + BLI_addtail(r_map, item); +} + +static void data_transfer_layersmapping_add_item_cd( + ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, + void *data_src, void *data_dst) +{ + data_transfer_layersmapping_add_item( + r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst, + 0, 0, 0, 0, 0, 0, NULL); +} + +/* Note: All those layer mapping handlers return false *only* if they were given invalid parameters. + * This means that even if they do nothing, they will return true if all given parameters were OK. + * Also, r_map may be NULL, in which case they will 'only' create/delete destination layers according + * to given parameters. + */ + +static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst( + ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, + const int num_elem_dst, const bool use_create, const bool use_delete, + CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, + const int tolayers, bool *use_layers_src, const int num_layers_src) +{ + void *data_src, *data_dst = NULL; + int idx_src = num_layers_src; + int idx_dst, tot_dst = CustomData_number_of_layers(cd_dst, cddata_type); + bool *data_dst_to_delete = NULL; + + if (!use_layers_src) { + /* No source at all, we can only delete all dest if requested... */ + if (use_delete) { + idx_dst = tot_dst; + while (idx_dst--) { + CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst); + } + } + return true; + } + + switch (tolayers) { + case DT_LAYERS_INDEX_DST: + idx_dst = tot_dst; + + /* Find last source actually used! */ + while (idx_src-- && !use_layers_src[idx_src]); + idx_src++; + + if (idx_dst < idx_src) { + if (!use_create) { + return true; + } + /* Create as much data layers as necessary! */ + for (; idx_dst < idx_src; idx_dst++) { + CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + } + } + else if (use_delete && idx_dst > idx_src) { + while (idx_dst-- > idx_src) { + CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst); + } + } + if (r_map) { + while (idx_src--) { + if (!use_layers_src[idx_src]) { + continue; + } + data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src); + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + if (use_dupref_dst) { + data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst); + } + else { + data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src); + } + data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + data_src, data_dst); + } + } + break; + case DT_LAYERS_NAME_DST: + if (use_delete) { + if (tot_dst) { + data_dst_to_delete = MEM_mallocN(sizeof(*data_dst_to_delete) * (size_t)tot_dst, __func__); + memset(data_dst_to_delete, true, sizeof(*data_dst_to_delete) * (size_t)tot_dst); + } + } + + while (idx_src--) { + const char *name; + + if (!use_layers_src[idx_src]) { + continue; + } + + name = CustomData_get_layer_name(cd_src, cddata_type, idx_src); + data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src); + + if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { + if (!use_create) { + if (r_map) { + BLI_freelistN(r_map); + } + return true; + } + CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); + } + else if (data_dst_to_delete) { + data_dst_to_delete[idx_dst] = false; + } + if (r_map) { + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + if (use_dupref_dst) { + data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); + } + else { + data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); + } + data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + data_src, data_dst); + } + } + + if (data_dst_to_delete) { + /* Note: This won't affect newly created layers, if any, since tot_dst has not been updated! + * Also, looping backward ensures us we do not suffer from index shifting when deleting a layer. + */ + for (idx_dst = tot_dst; idx_dst--;) { + if (data_dst_to_delete[idx_dst]) { + CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst); + } + } + + MEM_freeN(data_dst_to_delete); + } + break; + default: + return false; + } + + return true; +} + +static bool data_transfer_layersmapping_cdlayers( + ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, + const int num_elem_dst, const bool use_create, const bool use_delete, + CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, + const int fromlayers, const int tolayers) +{ + int idx_src, idx_dst; + void *data_src, *data_dst = NULL; + + if (CustomData_layertype_is_singleton(cddata_type)) { + if (!(data_src = CustomData_get_layer(cd_src, cddata_type))) { + if (use_delete) { + CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, 0); + } + return true; + } + + data_dst = CustomData_get_layer(cd_dst, cddata_type); + if (!data_dst) { + if (!use_create) { + return true; + } + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + } + else if (use_dupref_dst && r_map) { + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst); + } + + if (r_map) { + data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + data_src, data_dst); + } + } + else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) { + /* Note: use_delete has not much meaning in this case, ignored. */ + + if (fromlayers >= 0) { /* Real-layer index */ + idx_src = fromlayers; + } + else { + if ((idx_src = CustomData_get_active_layer(cd_src, cddata_type)) == -1) { + return true; + } + } + data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src); + if (!data_src) { + return true; + } + + if (tolayers >= 0) { /* Real-layer index */ + idx_dst = tolayers; + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + if (use_dupref_dst && r_map) { + data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); + } + else { + data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); + } + } + else if (tolayers == DT_LAYERS_ACTIVE_DST) { + if ((idx_dst = CustomData_get_active_layer(cd_dst, cddata_type)) == -1) { + if (!use_create) { + return true; + } + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + } + else { + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + if (use_dupref_dst && r_map) { + data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); + } + else { + data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); + } + } + } + else if (tolayers == DT_LAYERS_INDEX_DST) { + int num = CustomData_number_of_layers(cd_dst, cddata_type); + idx_dst = idx_src; + if (num <= idx_dst) { + if (!use_create) { + return true; + } + /* Create as much data layers as necessary! */ + for (; num <= idx_dst; num++) { + CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + } + } + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + if (use_dupref_dst && r_map) { + data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); + } + else { + data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); + } + } + else if (tolayers == DT_LAYERS_NAME_DST) { + const char *name = CustomData_get_layer_name(cd_src, cddata_type, idx_src); + if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { + if (!use_create) { + return true; + } + CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); + } + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + if (use_dupref_dst && r_map) { + data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); + } + else { + data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); + } + } + else { + return false; + } + + if (!data_dst) { + return false; + } + + if (r_map) { + data_transfer_layersmapping_add_item_cd( + r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst); + } + } + else if (fromlayers == DT_LAYERS_ALL_SRC) { + int num_src = CustomData_number_of_layers(cd_src, cddata_type); + bool *use_layers_src = num_src ? MEM_mallocN(sizeof(*use_layers_src) * (size_t)num_src, __func__) : NULL; + bool ret; + + if (use_layers_src) { + memset(use_layers_src, true, sizeof(*use_layers_src) * num_src); + } + + ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst( + r_map, cddata_type, mix_mode, mix_factor, mix_weights, + num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst, + tolayers, use_layers_src, num_src); + + if (use_layers_src) { + MEM_freeN(use_layers_src); + } + return ret; + } + else { + return false; + } + + return true; +} + +static bool data_transfer_layersmapping_generate( + ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst, + const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights, + const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers) +{ + CustomData *cd_src, *cd_dst; + + if (elem_type == ME_VERT) { + if (!(cddata_type & CD_FAKE)) { + cd_src = dm_src->getVertDataLayout(dm_src); + cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata; + + if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + num_elem_dst, use_create, use_delete, + cd_src, cd_dst, dm_dst != NULL, + fromlayers, tolayers)) + { + /* We handle specific source selection cases here. */ + return false; + } + return true; + } + else if (cddata_type == CD_FAKE_BWEIGHT) { + const size_t elem_size = sizeof(*((MVert *)NULL)); + const size_t data_size = sizeof(((MVert *)NULL)->bweight); + const size_t data_offset = offsetof(MVert, bweight); + const uint64_t data_flag = 0; + + if (!(dm_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) { + if (use_delete && !dm_dst) { + me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT; + } + return true; + } + if (dm_dst) { + dm_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; + } + else { + me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; + } + if (r_map) { + data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + dm_src->getVertArray(dm_src), + dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert, + dm_src->getNumVerts(dm_src), + dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert, + elem_size, data_size, data_offset, data_flag, + data_transfer_interp_char); + } + return true; + } + else if (cddata_type == CD_FAKE_MDEFORMVERT) { + cd_src = dm_src->getVertDataLayout(dm_src); + cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata; + + return data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights, + num_elem_dst, use_create, use_delete, + ob_src, ob_dst, cd_src, cd_dst, dm_dst != NULL, + fromlayers, tolayers); + } + else if (cddata_type == CD_FAKE_SHAPEKEY) { + /* TODO: leaving shapekeys asside for now, quite specific case, since we can't access them from MVert :/ */ + return false; + } + } + else if (elem_type == ME_EDGE) { + if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */ + cd_src = dm_src->getEdgeDataLayout(dm_src); + cd_dst = dm_dst ? dm_dst->getEdgeDataLayout(dm_dst) : &me_dst->edata; + + if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + num_elem_dst, use_create, use_delete, + cd_src, cd_dst, dm_dst != NULL, + fromlayers, tolayers)) + { + /* We handle specific source selection cases here. */ + return false; + } + return true; + } + else if (cddata_type == CD_FAKE_CREASE) { + const size_t elem_size = sizeof(*((MEdge *)NULL)); + const size_t data_size = sizeof(((MEdge *)NULL)->crease); + const size_t data_offset = offsetof(MEdge, crease); + const uint64_t data_flag = 0; + + if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) { + if (use_delete && !dm_dst) { + me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE; + } + return true; + } + if (dm_dst) { + dm_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE; + } + else { + me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE; + } + if (r_map) { + data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + dm_src->getEdgeArray(dm_src), + dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge, + dm_src->getNumEdges(dm_src), + dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, + elem_size, data_size, data_offset, data_flag, + data_transfer_interp_char); + } + return true; + } + else if (cddata_type == CD_FAKE_BWEIGHT) { + const size_t elem_size = sizeof(*((MEdge *)NULL)); + const size_t data_size = sizeof(((MEdge *)NULL)->bweight); + const size_t data_offset = offsetof(MEdge, bweight); + const uint64_t data_flag = 0; + + if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) { + if (use_delete && !dm_dst) { + me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT; + } + return true; + } + if (dm_dst) { + dm_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; + } + else { + me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; + } + if (r_map) { + data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights, + dm_src->getEdgeArray(dm_src), + dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge, + dm_src->getNumEdges(dm_src), + dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, + elem_size, data_size, data_offset, data_flag, + data_transfer_interp_char); + } + return true; + } + else if (r_map && ELEM(cddata_type, CD_FAKE_SHARP, CD_FAKE_SEAM)) { + const size_t elem_size = sizeof(*((MEdge *)NULL)); + const size_t data_size = sizeof(((MEdge *)NULL)->flag); + const size_t data_offset = offsetof(MEdge, flag); + const uint64_t data_flag = (cddata_type == CD_FAKE_SHARP) ? ME_SHARP : ME_SEAM; + + data_transfer_layersmapping_add_item( + r_map, cddata_type, mix_mode, mix_factor, mix_weights, + dm_src->getEdgeArray(dm_src), + dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge, + dm_src->getNumEdges(dm_src), + dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, + elem_size, data_size, data_offset, data_flag, NULL); + return true; + } + else { + return false; + } + } + else if (elem_type == ME_LOOP) { + if (cddata_type == CD_FAKE_UV) { + cddata_type = CD_MLOOPUV; + } + + if (!(cddata_type & CD_FAKE)) { + cd_src = dm_src->getLoopDataLayout(dm_src); + cd_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + + if (!data_transfer_layersmapping_cdlayers( + r_map, cddata_type, mix_mode, mix_factor, mix_weights, + num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, + fromlayers, tolayers)) + { + /* We handle specific source selection cases here. */ + return false; + } + return true; + } + else { + return false; + } + } + else if (elem_type == ME_POLY) { + if (cddata_type == CD_FAKE_UV) { + cddata_type = CD_MTEXPOLY; + } + + if (!(cddata_type & CD_FAKE)) { + cd_src = dm_src->getPolyDataLayout(dm_src); + cd_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; + + if (!data_transfer_layersmapping_cdlayers( + r_map, cddata_type, mix_mode, mix_factor, mix_weights, + num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, + fromlayers, tolayers)) + { + /* We handle specific source selection cases here. */ + return false; + } + return true; + } + else if (r_map && cddata_type == CD_FAKE_SHARP) { + const size_t elem_size = sizeof(*((MPoly *)NULL)); + const size_t data_size = sizeof(((MPoly *)NULL)->flag); + const size_t data_offset = offsetof(MPoly, flag); + const uint64_t data_flag = ME_SMOOTH; + + data_transfer_layersmapping_add_item( + r_map, cddata_type, mix_mode, mix_factor, mix_weights, + dm_src->getPolyArray(dm_src), + dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly, + dm_src->getNumPolys(dm_src), + dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly, + elem_size, data_size, data_offset, data_flag, NULL); + return true; + } + else { + return false; + } + } + + return false; +} + +/** + * Transfer data *layout* of selected types from source to destination object. + * By default, it only creates new data layers if needed on \a ob_dst. + * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those from \a ob_src, + * to get (as much as possible) exact copy of source data layout. + */ +void BKE_object_data_transfer_layout( + Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete, + const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]) +{ + DerivedMesh *dm_src; + Mesh *me_dst; + int i; + + const bool use_create = true; /* We always create needed layers here. */ + + CustomDataMask dm_src_mask = CD_MASK_BAREMESH; + + BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); + + me_dst = ob_dst->data; + + /* Get source DM.*/ + dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); + dm_src = mesh_get_derived_final(scene, ob_src, dm_src_mask); + if (!dm_src) { + return; + } + + /* Check all possible data types. */ + for (i = 0; i < DT_TYPE_MAX; i++) { + const int dtdata_type = 1 << i; + int cddata_type; + int fromlayers, tolayers, fromto_idx; + + if (!(data_types & dtdata_type)) { + continue; + } + + cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); + + fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); + if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { + fromlayers = fromlayers_select[fromto_idx]; + tolayers = tolayers_select[fromto_idx]; + } + else { + fromlayers = tolayers = 0; + } + + if (DT_DATATYPE_IS_VERT(dtdata_type)) { + const int num_elem_dst = me_dst->totvert; + + data_transfer_layersmapping_generate( + NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL, + num_elem_dst, use_create, use_delete, fromlayers, tolayers); + } + if (DT_DATATYPE_IS_EDGE(dtdata_type)) { + const int num_elem_dst = me_dst->totedge; + + data_transfer_layersmapping_generate( + NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL, + num_elem_dst, use_create, use_delete, fromlayers, tolayers); + } + if (DT_DATATYPE_IS_LOOP(dtdata_type)) { + const int num_elem_dst = me_dst->totloop; + + data_transfer_layersmapping_generate( + NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL, + num_elem_dst, use_create, use_delete, fromlayers, tolayers); + } + if (DT_DATATYPE_IS_POLY(dtdata_type)) { + const int num_elem_dst = me_dst->totpoly; + + data_transfer_layersmapping_generate( + NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL, + num_elem_dst, use_create, use_delete, fromlayers, tolayers); + } + } +} + +bool BKE_object_data_transfer_dm( + Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create, + const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, + SpaceTransform *space_transform, const float max_distance, const float ray_radius, + const float islands_handling_precision, + const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], + const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, + ReportList *reports) +{ +#define VDATA 0 +#define EDATA 1 +#define LDATA 2 +#define PDATA 3 +#define DATAMAX 4 + + DerivedMesh *dm_src; + Mesh *me_dst; + bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */ + int i; + + MDeformVert *mdef = NULL; + int vg_idx = -1; + float *weights[DATAMAX] = {NULL}; + + MeshPairRemap geom_map[DATAMAX] = {{0}}; + bool geom_map_init[DATAMAX] = {0}; + ListBase lay_map = {0}; + bool changed = false; + + const bool use_delete = false; /* We never delete data layers from destination here. */ + + CustomDataMask dm_src_mask = CD_MASK_BAREMESH; + + BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); + + me_dst = ob_dst->data; + if (dm_dst) { + dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0; + use_create = false; /* Never create needed custom layers on DM (modifier case). */ + } + + if (vgroup_name) { + if (dm_dst) { + mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT); + } + else { + mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT); + } + if (mdef) { + vg_idx = defgroup_name_index(ob_dst, vgroup_name); + } + } + + /* Get source DM.*/ + dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); + /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm, + * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers... + * Issue is, this means we cannot be sure to have requested cd layers in source. + */ + dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask); + if (!dm_src) { + return changed; + } + + /* Check all possible data types. + * Note item mappings and dest mix weights are cached. */ + for (i = 0; i < DT_TYPE_MAX; i++) { + const int dtdata_type = 1 << i; + int cddata_type; + int fromlayers, tolayers, fromto_idx; + + if (!(data_types & dtdata_type)) { + continue; + } + + cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); + + fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); + if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { + fromlayers = fromlayers_select[fromto_idx]; + tolayers = tolayers_select[fromto_idx]; + } + else { + fromlayers = tolayers = 0; + } + + if (DT_DATATYPE_IS_VERT(dtdata_type)) { + MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; + const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; + + if (!geom_map_init[VDATA]) { + if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != dm_src->getNumVerts(dm_src))) { + BKE_report(reports, RPT_ERROR, + "Source and destination meshes do not have the same amount of vertices, " + "'Topology' mapping cannot be used in this case"); + return changed; + } + BKE_mesh_remap_calc_verts_from_dm( + map_vert_mode, space_transform, max_distance, ray_radius, + verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]); + geom_map_init[VDATA] = true; + } + + if (mdef && vg_idx != -1 && !weights[VDATA]) { + weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__); + BKE_defvert_extract_vgroup_to_vertweights(mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup); + } + + if (data_transfer_layersmapping_generate( + &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT, + cddata_type, mix_mode, mix_factor, weights[VDATA], + num_verts_dst, use_create, use_delete, fromlayers, tolayers)) + { + CustomDataTransferLayerMap *lay_mapit; + + changed = (lay_map.first != NULL); + + for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { + CustomData_data_transfer(&geom_map[VDATA], lay_mapit); + } + + BLI_freelistN(&lay_map); + } + } + if (DT_DATATYPE_IS_EDGE(dtdata_type)) { + MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; + const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; + MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; + const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; + + if (!geom_map_init[EDATA]) { + if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != dm_src->getNumEdges(dm_src))) { + BKE_report(reports, RPT_ERROR, + "Source and destination meshes do not have the same amount of edges, " + "'Topology' mapping cannot be used in this case"); + return changed; + } + BKE_mesh_remap_calc_edges_from_dm( + map_edge_mode, space_transform, max_distance, ray_radius, + verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst, + dm_src, &geom_map[EDATA]); + geom_map_init[EDATA] = true; + } + + if (mdef && vg_idx != -1 && !weights[EDATA]) { + weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__); + BKE_defvert_extract_vgroup_to_edgeweights( + mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst, + weights[EDATA], invert_vgroup); + } + + if (data_transfer_layersmapping_generate( + &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE, + cddata_type, mix_mode, mix_factor, weights[EDATA], + num_edges_dst, use_create, use_delete, fromlayers, tolayers)) + { + CustomDataTransferLayerMap *lay_mapit; + + changed = (lay_map.first != NULL); + + for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { + CustomData_data_transfer(&geom_map[EDATA], lay_mapit); + } + + BLI_freelistN(&lay_map); + } + } + if (DT_DATATYPE_IS_LOOP(dtdata_type)) { + MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; + const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; + MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; + const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; + MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; + const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; + MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; + const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; + CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; + CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + + MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type); + + if (!geom_map_init[LDATA]) { + if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != dm_src->getNumLoops(dm_src))) { + BKE_report(reports, RPT_ERROR, + "Source and destination meshes do not have the same amount of face corners, " + "'Topology' mapping cannot be used in this case"); + return changed; + } + BKE_mesh_remap_calc_loops_from_dm( + map_loop_mode, space_transform, max_distance, ray_radius, + verts_dst, num_verts_dst, edges_dst, num_edges_dst, + loops_dst, num_loops_dst, polys_dst, num_polys_dst, + ldata_dst, pdata_dst, me_dst->smoothresh, dirty_nors_dst, + dm_src, island_callback, islands_handling_precision, &geom_map[LDATA]); + geom_map_init[LDATA] = true; + } + + if (mdef && vg_idx != -1 && !weights[LDATA]) { + weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__); + BKE_defvert_extract_vgroup_to_loopweights( + mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, + weights[LDATA], invert_vgroup); + } + + if (data_transfer_layersmapping_generate( + &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP, + cddata_type, mix_mode, mix_factor, weights[LDATA], + num_loops_dst, use_create, use_delete, fromlayers, tolayers)) + { + CustomDataTransferLayerMap *lay_mapit; + + changed = (lay_map.first != NULL); + + for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { + CustomData_data_transfer(&geom_map[LDATA], lay_mapit); + } + + BLI_freelistN(&lay_map); + } + } + if (DT_DATATYPE_IS_POLY(dtdata_type)) { + MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; + const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; + MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; + const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; + MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; + const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; + CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; + + if (!geom_map_init[PDATA]) { + if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != dm_src->getNumPolys(dm_src))) { + BKE_report(reports, RPT_ERROR, + "Source and destination meshes do not have the same amount of faces, " + "'Topology' mapping cannot be used in this case"); + return changed; + } + BKE_mesh_remap_calc_polys_from_dm( + map_poly_mode, space_transform, max_distance, ray_radius, + verts_dst, num_verts_dst, loops_dst, num_loops_dst, + polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst, + dm_src, &geom_map[PDATA]); + geom_map_init[PDATA] = true; + } + + if (mdef && vg_idx != -1 && !weights[PDATA]) { + weights[PDATA] = MEM_mallocN(sizeof(*weights[PDATA]) * (size_t)num_polys_dst, __func__); + BKE_defvert_extract_vgroup_to_polyweights( + mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, + polys_dst, num_polys_dst, weights[PDATA], invert_vgroup); + } + + if (data_transfer_layersmapping_generate( + &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY, + cddata_type, mix_mode, mix_factor, weights[PDATA], + num_polys_dst, use_create, use_delete, fromlayers, tolayers)) + { + CustomDataTransferLayerMap *lay_mapit; + + changed = (lay_map.first != NULL); + + for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { + CustomData_data_transfer(&geom_map[PDATA], lay_mapit); + } + + BLI_freelistN(&lay_map); + } + } + } + + for (i = 0; i < DATAMAX; i++) { + BKE_mesh_remap_free(&geom_map[i]); + MEM_SAFE_FREE(weights[i]); + } + + return changed; + +#undef VDATA +#undef EDATA +#undef LDATA +#undef PDATA +#undef DATAMAX +} + +bool BKE_object_data_transfer_mesh( + Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_create, + const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, + SpaceTransform *space_transform, const float max_distance, const float ray_radius, + const float islands_handling_precision, + const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], + const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, + ReportList *reports) +{ + return BKE_object_data_transfer_dm( + scene, ob_src, ob_dst, NULL, data_types, use_create, + map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, space_transform, + max_distance, ray_radius, islands_handling_precision, fromlayers_select, tolayers_select, + mix_mode, mix_factor, vgroup_name, invert_vgroup, reports); +} diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h new file mode 100644 index 00000000000..913325afce0 --- /dev/null +++ b/source/blender/blenkernel/intern/data_transfer_intern.h @@ -0,0 +1,60 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Bastien Montagne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/data_transfer_intern.h + * \ingroup bke + */ + +#ifndef __DATA_TRANSFER_INTERN_H__ +#define __DATA_TRANSFER_INTERN_H__ + +struct CustomDataTransferLayerMap; +struct CustomData; +struct ListBase; + +float data_transfer_interp_float_do( + const int mix_mode, const float val_dst, const float val_src, const float mix_factor); + +/* Copied from BKE_customdata.h :( */ +typedef void (*cd_datatransfer_interp)(const struct CustomDataTransferLayerMap *laymap, void *dest, + void **sources, const float *weights, const int count, const float mix_factor); + +void data_transfer_layersmapping_add_item( + struct ListBase *r_map, const int data_type, const int mix_mode, + const float mix_factor, const float *mix_weights, + void *data_src, void *data_dst, const int data_src_n, const int data_dst_n, + const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag, + cd_datatransfer_interp interp); + +/* Type-specific. */ + +bool data_transfer_layersmapping_vgroups( + struct ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, + const int num_elem_dst, const bool use_create, const bool use_delete, + struct Object *ob_src, struct Object *ob_dst, struct CustomData *cd_src, struct CustomData *cd_dst, + const bool use_dupref_dst, const int fromlayers, const int tolayers); + +#endif /* __DATA_TRANSFER_INTERN_H__ */ diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index d3148dbc8e9..80db62801d6 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -39,7 +39,9 @@ #include "MEM_guardedalloc.h" #include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -49,7 +51,14 @@ #include "BLF_translation.h" +#include "BKE_customdata.h" +#include "BKE_data_transfer.h" #include "BKE_deform.h" /* own include */ +#include "BKE_mesh_mapping.h" +#include "BKE_object_deform.h" + +#include "data_transfer_intern.h" + bDeformGroup *BKE_defgroup_new(Object *ob, const char *name) { @@ -960,3 +969,385 @@ void BKE_defvert_array_free(MDeformVert *dvert, int totvert) MEM_freeN(dvert); } + +void BKE_defvert_extract_vgroup_to_vertweights( + MDeformVert *dvert, const int defgroup, const int num_verts, float *r_weights, const bool invert_vgroup) +{ + if (dvert && defgroup != -1) { + int i = num_verts; + + while (i--) { + const float w = defvert_find_weight(&dvert[i], defgroup); + r_weights[i] = invert_vgroup ? (1.0f - w) : w; + } + } + else { + fill_vn_fl(r_weights, invert_vgroup ? 1.0f : 0.0f, num_verts); + } +} + +/* The following three make basic interpolation, using temp vert_weights array to avoid looking up same weight + * several times. */ + +void BKE_defvert_extract_vgroup_to_edgeweights( + MDeformVert *dvert, const int defgroup, const int num_verts, MEdge *edges, const int num_edges, + float *r_weights, const bool invert_vgroup) +{ + if (dvert && defgroup != -1) { + int i = num_edges; + float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__); + + BKE_defvert_extract_vgroup_to_vertweights(dvert, defgroup, num_verts, tmp_weights, invert_vgroup); + + while (i--) { + MEdge *me = &edges[i]; + + r_weights[i] = (tmp_weights[me->v1] + tmp_weights[me->v2]) * 0.5f; + } + + MEM_freeN(tmp_weights); + } + else { + fill_vn_fl(r_weights, 0.0f, num_edges); + } +} + +void BKE_defvert_extract_vgroup_to_loopweights( + MDeformVert *dvert, const int defgroup, const int num_verts, MLoop *loops, const int num_loops, + float *r_weights, const bool invert_vgroup) +{ + if (dvert && defgroup != -1) { + int i = num_loops; + float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__); + + BKE_defvert_extract_vgroup_to_vertweights(dvert, defgroup, num_verts, tmp_weights, invert_vgroup); + + while (i--) { + MLoop *ml = &loops[i]; + + r_weights[i] = tmp_weights[ml->v]; + } + + MEM_freeN(tmp_weights); + } + else { + fill_vn_fl(r_weights, 0.0f, num_loops); + } +} + +void BKE_defvert_extract_vgroup_to_polyweights( + MDeformVert *dvert, const int defgroup, const int num_verts, MLoop *loops, const int UNUSED(num_loops), + MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup) +{ + if (dvert && defgroup != -1) { + int i = num_polys; + float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__); + + BKE_defvert_extract_vgroup_to_vertweights(dvert, defgroup, num_verts, tmp_weights, invert_vgroup); + + while (i--) { + MPoly *mp = &polys[i]; + MLoop *ml = &loops[mp->loopstart]; + int j = mp->totloop; + float w = 0.0f; + + for (; j--; ml++) { + w += tmp_weights[ml->v]; + } + r_weights[i] = w / (float)mp->totloop; + } + + MEM_freeN(tmp_weights); + } + else { + fill_vn_fl(r_weights, 0.0f, num_polys); + } +} + +/*********** Data Transfer **********/ + +static void vgroups_datatransfer_interp(const CustomDataTransferLayerMap *laymap, void *dest, + void **sources, const float *weights, const int count, const float mix_factor) +{ + MDeformVert **data_src = (MDeformVert **)sources; + MDeformVert *data_dst = (MDeformVert *)dest; + const int idx_src = laymap->data_src_n; + const int idx_dst = laymap->data_dst_n; + + const int mix_mode = laymap->mix_mode; + + int i, j; + + MDeformWeight *dw_src; + MDeformWeight *dw_dst = defvert_find_index(data_dst, idx_dst); + float weight_src = 0.0f, weight_dst = 0.0f; + + if (sources) { + for (i = count; i--;) { + for (j = data_src[i]->totweight; j--;) { + if ((dw_src = &data_src[i]->dw[j])->def_nr == idx_src) { + weight_src += dw_src->weight * weights[i]; + break; + } + } + } + } + + if (dw_dst) { + weight_dst = dw_dst->weight; + } + else if (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD) { + return; /* Do not affect destination. */ + } + + weight_src = data_transfer_interp_float_do(mix_mode, weight_dst, weight_src, mix_factor); + + CLAMP(weight_src, 0.0f, 1.0f); + + if (!dw_dst) { + defvert_add_index_notest(data_dst, idx_dst, weight_src); + } + else { + dw_dst->weight = weight_src; + } +} + +static bool data_transfer_layersmapping_vgroups_multisrc_to_dst( + ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, + const int num_elem_dst, const bool use_create, const bool use_delete, + Object *ob_src, Object *ob_dst, MDeformVert *data_src, MDeformVert *data_dst, + CustomData *UNUSED(cd_src), CustomData *cd_dst, const bool UNUSED(use_dupref_dst), + const int tolayers, bool *use_layers_src, const int num_layers_src) +{ + int idx_src; + int idx_dst; + int tot_dst = BLI_listbase_count(&ob_dst->defbase); + + const size_t elem_size = sizeof(*((MDeformVert *)NULL)); + + switch (tolayers) { + case DT_LAYERS_INDEX_DST: + idx_dst = tot_dst; + + /* Find last source actually used! */ + idx_src = num_layers_src; + while (idx_src-- && !use_layers_src[idx_src]); + idx_src++; + + if (idx_dst < idx_src) { + if (!use_create) { + return false; + } + /* Create as much vgroups as necessary! */ + for (; idx_dst < idx_src; idx_dst++) { + BKE_object_defgroup_add(ob_dst); + } + } + else if (use_delete && idx_dst > idx_src) { + while (idx_dst-- > idx_src) { + BKE_object_defgroup_remove(ob_dst, ob_dst->defbase.last); + } + } + if (r_map) { + /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! + * Again, use_create is not relevant in this case */ + if (!data_dst) { + data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + } + + while (idx_src--) { + if (!use_layers_src[idx_src]) { + continue; + } + data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, + data_src, data_dst, idx_src, idx_src, + elem_size, 0, 0, 0, vgroups_datatransfer_interp); + } + } + break; + case DT_LAYERS_NAME_DST: + { + bDeformGroup *dg_src, *dg_dst; + + if (use_delete) { + /* Remove all unused dst vgroups first, simpler in this case. */ + for (dg_dst = ob_dst->defbase.first; dg_dst;) { + bDeformGroup *dg_dst_next = dg_dst->next; + + if (defgroup_name_index(ob_src, dg_dst->name) == -1) { + BKE_object_defgroup_remove(ob_dst, dg_dst); + } + dg_dst = dg_dst_next; + } + } + + for (idx_src = 0, dg_src = ob_src->defbase.first; + idx_src < num_layers_src; + idx_src++, dg_src = dg_src->next) + { + if (!use_layers_src[idx_src]) { + continue; + } + + if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) { + if (!use_create) { + if (r_map) { + BLI_freelistN(r_map); + } + return false; + } + BKE_object_defgroup_add_name(ob_dst, dg_src->name); + idx_dst = ob_dst->actdef - 1; + } + if (r_map) { + /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! + * use_create is not relevant in this case */ + if (!data_dst) { + data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + } + + data_transfer_layersmapping_add_item( + r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, + data_src, data_dst, idx_src, idx_dst, + elem_size, 0, 0, 0, vgroups_datatransfer_interp); + } + } + break; + } + default: + return false; + } + + return true; +} + +bool data_transfer_layersmapping_vgroups( + ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights, + const int num_elem_dst, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst, + CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers) +{ + int idx_src, idx_dst; + MDeformVert *data_src, *data_dst = NULL; + + const size_t elem_size = sizeof(*((MDeformVert *)NULL)); + + /* Note: VGroups are a bit hairy, since their layout is defined on object level (ob->defbase), while their actual + * data is a (mesh) CD layer. + * This implies we may have to handle data layout itself while having NULL data itself, + * and even have to support NULL data_src in transfer data code (we always create a data_dst, though). + */ + + if (BLI_listbase_is_empty(&ob_src->defbase)) { + if (use_delete) { + BKE_object_defgroup_remove_all(ob_dst); + } + return true; + } + + data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT); + + data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT); + if (data_dst && use_dupref_dst && r_map) { + /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst); + } + + if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) { + /* Note: use_delete has not much meaning in this case, ignored. */ + + if (fromlayers >= 0) { + idx_src = fromlayers; + BLI_assert(idx_src < BLI_listbase_count(&ob_src->defbase)); + } + else if ((idx_src = ob_src->actdef - 1) == -1) { + return false; + } + + if (tolayers >= 0) { + /* Note: in this case we assume layer exists! */ + idx_dst = tolayers; + BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase)); + } + else if (tolayers == DT_LAYERS_ACTIVE_DST) { + if ((idx_dst = ob_dst->actdef - 1) == -1) { + bDeformGroup *dg_src; + if (!use_create) { + return true; + } + dg_src = BLI_findlink(&ob_src->defbase, idx_src); + BKE_object_defgroup_add_name(ob_dst, dg_src->name); + idx_dst = ob_dst->actdef - 1; + } + } + else if (tolayers == DT_LAYERS_INDEX_DST) { + int num = BLI_listbase_count(&ob_src->defbase); + idx_dst = idx_src; + if (num <= idx_dst) { + if (!use_create) { + return true; + } + /* Create as much vgroups as necessary! */ + for (; num <= idx_dst; num++) { + BKE_object_defgroup_add(ob_dst); + } + } + } + else if (tolayers == DT_LAYERS_NAME_DST) { + bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src); + if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) { + if (!use_create) { + return true; + } + BKE_object_defgroup_add_name(ob_dst, dg_src->name); + idx_dst = ob_dst->actdef - 1; + } + } + else { + return false; + } + + if (r_map) { + /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! + * use_create is not relevant in this case */ + if (!data_dst) { + data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + } + + data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights, + data_src, data_dst, idx_src, idx_dst, + elem_size, 0, 0, 0, vgroups_datatransfer_interp); + } + } + else { + int num_src, num_sel_unused; + bool *use_layers_src = NULL; + bool ret = false; + + switch (fromlayers) { + case DT_LAYERS_ALL_SRC: + use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_ALL, + &num_src, &num_sel_unused); + break; + case DT_LAYERS_VGROUP_SRC_BONE_SELECT: + use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_SELECT, + &num_src, &num_sel_unused); + break; + case DT_LAYERS_VGROUP_SRC_BONE_DEFORM: + use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_DEFORM, + &num_src, &num_sel_unused); + break; + } + + if (use_layers_src) { + ret = data_transfer_layersmapping_vgroups_multisrc_to_dst( + r_map, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, + ob_src, ob_dst, data_src, data_dst, cd_src, cd_dst, use_dupref_dst, + tolayers, use_layers_src, num_src); + } + + MEM_SAFE_FREE(use_layers_src); + return ret; + } + + return true; +} diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index cf425afe5db..1f3f31c3220 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2359,6 +2359,15 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) ob->recalc |= OB_RECALC_DATA; lib_id_recalc_tag(bmain, &ob->id); } + /* This should not be needed here, but in some cases, like after a redo, we can end up with + * a wrong final matrix (see T42472). + * Quoting Sergey, this comes from BKE_object_handle_update_ex, which is calling + * BKE_object_where_is_calc_ex when it shouldn't, but that issue is not easily fixable. + */ + else { + ob->recalc |= OB_RECALC_OB; + lib_id_recalc_tag(bmain, &ob->id); + } if (ob->proxy && (ob->proxy_group == NULL)) { ob->proxy->recalc |= OB_RECALC_DATA; lib_id_recalc_tag(bmain, &ob->id); diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 893c69741cd..9ea5a5638b9 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -37,7 +37,6 @@ #include "MEM_guardedalloc.h" #include "DNA_curve_types.h" -#include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_vfont_types.h" @@ -814,7 +813,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, required_mode |= eModifierMode_Editmode; if (cu->editnurb == NULL) { - keyVerts = BKE_key_evaluate_object(scene, ob, &numVerts); + keyVerts = BKE_key_evaluate_object(ob, &numVerts); if (keyVerts) { /* split coords from key data, the latter also includes diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index c4f91f0ba89..58a7702828c 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -73,10 +73,6 @@ #include "BKE_scene.h" #include "BKE_texture.h" -#include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" - /* for image output */ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -259,20 +255,20 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface) bool dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface) { if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { - return 0; + return false; } else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WAVE) { - return 0; + return false; } else { - return 1; + return true; } } else { - return 1; + return true; } } @@ -327,7 +323,7 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object else if (output == 1) name = surface->output_name2; else - return 0; + return false; if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { @@ -338,7 +334,7 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object return (defgroup_name_index(ob, surface->output_name) != -1); } - return 0; + return false; } static bool surface_duplicateOutputExists(void *arg, const char *name) @@ -1106,13 +1102,13 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaint Canvas"); if (!canvas) - return 0; + return false; canvas->pmd = pmd; canvas->dm = NULL; /* Create one surface */ if (!dynamicPaint_createNewSurface(canvas, scene)) - return 0; + return false; } else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) { @@ -1122,7 +1118,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint"); if (!brush) - return 0; + return false; brush->pmd = pmd; brush->psys = NULL; @@ -1157,7 +1153,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str brush->paint_ramp = add_colorband(false); if (!brush->paint_ramp) - return 0; + return false; ramp = brush->paint_ramp->data; /* Add default smooth-falloff ramp. */ ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f; @@ -1173,7 +1169,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str brush->vel_ramp = add_colorband(false); if (!brush->vel_ramp) - return 0; + return false; ramp = brush->vel_ramp->data; ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f; ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f; @@ -1181,10 +1177,11 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str } } } - else - return 0; + else { + return false; + } - return 1; + return true; } void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tpmd) @@ -1630,12 +1627,12 @@ bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface) if (surface->data) dynamicPaint_freeSurfaceData(surface); /* don't reallocate for image sequence types. they get handled only on bake */ - if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return 1; - if (numOfPoints < 1) return 0; + if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return true; + if (numOfPoints < 1) return false; /* allocate memory */ surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData"); - if (!surface->data) return 0; + if (!surface->data) return false; /* allocate data depending on surface type and format */ surface->data->total_points = numOfPoints; @@ -1646,7 +1643,7 @@ bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface) if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) dynamicPaint_setInitialColor(scene, surface); - return 1; + return true; } /* make sure allocated surface size matches current requirements */ @@ -1655,7 +1652,7 @@ static bool dynamicPaint_checkSurfaceData(Scene *scene, DynamicPaintSurface *sur if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) { return dynamicPaint_resetSurface(scene, surface); } - return 1; + return true; } diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 7d64892d6b4..eb7c78c2760 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -526,6 +526,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, setDrawOptions(userData, BM_elem_index_get(efa))); if (draw_option != DM_DRAW_OPTION_SKIP) { const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ + if (setMaterial) + setMaterial(efa->mat_nr + 1, NULL); if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ if (poly_prev != GL_ZERO) glEnd(); @@ -608,12 +610,17 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, efa = ltri[0]->f; drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH)); + + draw_option = (setDrawOptions ? + setDrawOptions(userData, BM_elem_index_get(efa)) : + DM_DRAW_OPTION_NORMAL); - draw_option = (!setDrawOptions ? - DM_DRAW_OPTION_NORMAL : - setDrawOptions(userData, BM_elem_index_get(efa))); if (draw_option != DM_DRAW_OPTION_SKIP) { const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ + + if (setMaterial) + setMaterial(efa->mat_nr + 1, NULL); + if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ if (poly_prev != GL_ZERO) glEnd(); @@ -717,7 +724,7 @@ static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned c static void emDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, - DMSetDrawOptions drawParamsMapped, + DMSetDrawOptionsMappedTex drawParamsMapped, DMCompareDrawOptions compareDrawOptions, void *userData) { @@ -785,7 +792,7 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, if (drawParams) draw_option = drawParams(&mtf, has_vcol, efa->mat_nr); else if (drawParamsMapped) - draw_option = drawParamsMapped(userData, BM_elem_index_get(efa)); + draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr); else draw_option = DM_DRAW_OPTION_NORMAL; @@ -854,7 +861,7 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, if (drawParams) draw_option = drawParams(&mtf, has_vcol, efa->mat_nr); else if (drawParamsMapped) - draw_option = drawParamsMapped(userData, BM_elem_index_get(efa)); + draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr); else draw_option = DM_DRAW_OPTION_NORMAL; @@ -916,7 +923,7 @@ static void emDM_drawFacesTex(DerivedMesh *dm, } static void emDM_drawMappedFacesTex(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, + DMSetDrawOptionsMappedTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag UNUSED(flag)) { @@ -1555,7 +1562,8 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type) if (type == CD_MTFACE || type == CD_MCOL) { const int type_from = (type == CD_MTFACE) ? CD_MTEXPOLY : CD_MLOOPCOL; int index; - const char *data, *bmdata; + const char *bmdata; + char *data; index = CustomData_get_layer_index(&bm->pdata, type_from); if (index != -1) { @@ -1580,11 +1588,11 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type) // bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); bmdata = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - ME_MTEXFACE_CPY(((MTFace *)data), ((MTexPoly *)bmdata)); + ME_MTEXFACE_CPY(((MTFace *)data), ((const MTexPoly *)bmdata)); for (j = 0; j < 3; j++) { // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPUV); bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_uv_offset); - copy_v2_v2(((MTFace *)data)->uv[j], ((MLoopUV *)bmdata)->uv); + copy_v2_v2(((MTFace *)data)->uv[j], ((const MLoopUV *)bmdata)->uv); } } } @@ -1594,7 +1602,7 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type) for (j = 0; j < 3; j++) { // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPCOL); bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_color_offset); - MESH_MLOOPCOL_TO_MCOL(((MLoopCol *)bmdata), (((MCol *)data) + j)); + MESH_MLOOPCOL_TO_MCOL(((const MLoopCol *)bmdata), (((MCol *)data) + j)); } } } diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c index 442ab26ffc8..5f2660b5365 100644 --- a/source/blender/blenkernel/intern/editmesh_bvh.c +++ b/source/blender/blenkernel/intern/editmesh_bvh.c @@ -239,6 +239,32 @@ struct RayCastUserData { float uv[2]; }; + +static BMFace *bmbvh_ray_cast_handle_hit( + BMBVHTree *bmtree, struct RayCastUserData *bmcb_data, const BVHTreeRayHit *hit, + float *r_dist, float r_hitout[3], float r_cagehit[3]) +{ + if (r_hitout) { + if (bmtree->flag & BMBVH_RETURN_ORIG) { + BMLoop **ltri = bmtree->looptris[hit->index]; + interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data->uv); + } + else { + copy_v3_v3(r_hitout, hit->co); + } + + if (r_cagehit) { + copy_v3_v3(r_cagehit, hit->co); + } + } + + if (r_dist) { + *r_dist = hit->dist; + } + + return bmtree->looptris[hit->index][0]->f; +} + static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { struct RayCastUserData *bmcb_data = userdata; @@ -284,32 +310,68 @@ BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage; BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data); + if (hit.index != -1 && hit.dist != dist) { - if (r_hitout) { - if (bmtree->flag & BMBVH_RETURN_ORIG) { - BMLoop **ltri = bmtree->looptris[hit.index]; - interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data.uv); - } - else { - copy_v3_v3(r_hitout, hit.co); - } + return bmbvh_ray_cast_handle_hit(bmtree, &bmcb_data, &hit, r_dist, r_hitout, r_cagehit); + } - if (r_cagehit) { - copy_v3_v3(r_cagehit, hit.co); - } - } + return NULL; +} - if (r_dist) { - *r_dist = hit.dist; - } +/* -------------------------------------------------------------------- */ +/* bmbvh_ray_cast_cb_filter */ - return bmtree->looptris[hit.index][0]->f; +/* Same as BKE_bmbvh_ray_cast but takes a callback to filter out faces. + */ + +struct RayCastUserData_Filter { + struct RayCastUserData bmcb_data; + + BMBVHTree_FaceFilter filter_cb; + void *filter_userdata; +}; + +static void bmbvh_ray_cast_cb_filter(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + struct RayCastUserData_Filter *bmcb_data_filter = userdata; + struct RayCastUserData *bmcb_data = &bmcb_data_filter->bmcb_data; + const BMLoop **ltri = bmcb_data->looptris[index]; + if (bmcb_data_filter->filter_cb(ltri[0]->f, bmcb_data_filter->filter_userdata)) { + bmbvh_ray_cast_cb(bmcb_data, index, ray, hit); + } +} + +BMFace *BKE_bmbvh_ray_cast_filter( + BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius, + float *r_dist, float r_hitout[3], float r_cagehit[3], + BMBVHTree_FaceFilter filter_cb, void *filter_userdata) +{ + BVHTreeRayHit hit; + struct RayCastUserData_Filter bmcb_data_filter; + struct RayCastUserData *bmcb_data = &bmcb_data_filter.bmcb_data; + + const float dist = r_dist ? *r_dist : FLT_MAX; + + bmcb_data_filter.filter_cb = filter_cb; + bmcb_data_filter.filter_userdata = filter_userdata; + + if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT)); + + hit.dist = dist; + hit.index = -1; + + /* ok to leave 'uv' uninitialized */ + bmcb_data->looptris = (const BMLoop *(*)[3])bmtree->looptris; + bmcb_data->cos_cage = (const float (*)[3])bmtree->cos_cage; + + BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb_filter, &bmcb_data_filter); + if (hit.index != -1 && hit.dist != dist) { + return bmbvh_ray_cast_handle_hit(bmtree, bmcb_data, &hit, r_dist, r_hitout, r_cagehit); } return NULL; } - /* -------------------------------------------------------------------- */ /* BKE_bmbvh_find_face_segment */ diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 88d70691120..b50e563775e 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -687,11 +687,11 @@ bool fcurve_are_keyframes_usable(FCurve *fcu) { /* F-Curve must exist */ if (fcu == NULL) - return 0; + return false; /* F-Curve must not have samples - samples are mutually exclusive of keyframes */ if (fcu->fpt) - return 0; + return false; /* if it has modifiers, none of these should "drastically" alter the curve */ if (fcu->modifiers.first) { @@ -718,7 +718,7 @@ bool fcurve_are_keyframes_usable(FCurve *fcu) FMod_Generator *data = (FMod_Generator *)fcm->data; if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) - return 0; + return false; break; } case FMODIFIER_TYPE_FN_GENERATOR: @@ -726,18 +726,18 @@ bool fcurve_are_keyframes_usable(FCurve *fcu) FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data; if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) - return 0; + return false; break; } /* always harmful - cannot allow */ default: - return 0; + return false; } } } /* keyframes are usable */ - return 1; + return true; } bool BKE_fcurve_is_protected(FCurve *fcu) @@ -1283,7 +1283,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* extract transform just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); /* ... and from that, we get our transform */ copy_v3_v3(tmp_loc, mat[3]); @@ -1308,7 +1308,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* extract transform just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); /* ... and from that, we get our transform */ copy_v3_v3(tmp_loc, mat[3]); @@ -1385,7 +1385,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); } else { /* specially calculate local matrix, since chan_mat is not valid @@ -1412,7 +1412,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); } else { /* transforms to matrix */ @@ -2165,8 +2165,8 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime * the value is simply the shared value (see T40372 -> F91346) */ cvalue = v1[1]; - } - else { + } + else { /* adjust handles so that they don't overlap (forming a loop) */ correct_bezpart(v1, v2, v3, v4); diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 56b087e7eb6..af0db5e1c47 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -27,8 +27,6 @@ * \ingroup bke */ - - #include <math.h> #include <stdio.h> #include <stddef.h> @@ -1173,7 +1171,7 @@ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm) /* sanity check */ if (fcm == NULL) - return 0; + return false; /* free modifier's special data (stored inside fcm->data) */ if (fcm->data) { @@ -1187,13 +1185,13 @@ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm) /* remove modifier from stack */ if (modifiers) { BLI_freelinkN(modifiers, fcm); - return 1; + return true; } else { /* XXX this case can probably be removed some day, as it shouldn't happen... */ printf("remove_fmodifier() - no modifier stack given\n"); MEM_freeN(fcm); - return 0; + return false; } } @@ -1264,7 +1262,7 @@ bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype) /* sanity checks */ if (ELEM(NULL, modifiers, modifiers->first)) - return 0; + return false; /* find the first mdifier fitting these criteria */ for (fcm = modifiers->first; fcm; fcm = fcm->next) { @@ -1279,11 +1277,11 @@ bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype) /* if both are ok, we've found a hit */ if (mOk && aOk) - return 1; + return true; } /* no matches */ - return 0; + return false; } /* Evaluation API --------------------------- */ diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index e226e9d9797..dd2155505fb 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -45,6 +45,7 @@ #include "DNA_gpencil_types.h" #include "DNA_userdef_types.h" +#include "BKE_animsys.h" #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" @@ -115,6 +116,12 @@ void BKE_gpencil_free(bGPdata *gpd) { /* free layers */ free_gpencil_layers(&gpd->layers); + + /* free animation data */ + if (gpd->adt) { + BKE_free_animdata(&gpd->id); + gpd->adt = NULL; + } } /* -------- Container Creation ---------- */ @@ -276,7 +283,7 @@ bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src) } /* make a copy of a given gpencil datablock */ -bGPdata *gpencil_data_duplicate(bGPdata *src) +bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy) { bGPDlayer *gpl, *gpld; bGPdata *dst; @@ -286,7 +293,14 @@ bGPdata *gpencil_data_duplicate(bGPdata *src) return NULL; /* make a copy of the base-data */ - dst = MEM_dupallocN(src); + if (internal_copy) { + /* make a straight copy for undo buffers used during stroke drawing */ + dst = MEM_dupallocN(src); + } + else { + /* make a copy when others use this */ + dst = BKE_libblock_copy(&src->id); + } /* copy layers */ BLI_listbase_clear(&dst->layers); @@ -300,6 +314,31 @@ bGPdata *gpencil_data_duplicate(bGPdata *src) return dst; } +/* -------- GP-Stroke API --------- */ + +/* ensure selection status of stroke is in sync with its points */ +void gpencil_stroke_sync_selection(bGPDstroke *gps) +{ + bGPDspoint *pt; + int i; + + /* error checking */ + if (gps == NULL) + return; + + /* we'll stop when we find the first selected point, + * so initially, we must deselect + */ + gps->flag &= ~GP_STROKE_SELECT; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + gps->flag |= GP_STROKE_SELECT; + break; + } + } +} + /* -------- GP-Frame API ---------- */ /* delete the last stroke of the given frame */ @@ -359,7 +398,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew) /* do not allow any changes to layer's active frame if layer is locked from changes * or if the layer has been set to stay on the current frame */ - if (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_FRAMELOCK)) + if (gpl->flag & GP_LAYER_FRAMELOCK) return gpf; /* do not allow any changes to actframe if frame has painting tag attached to it */ if (gpf->flag & GP_FRAME_PAINT) @@ -468,16 +507,23 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew) bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) { bool changed = false; - + /* error checking */ if (ELEM(NULL, gpl, gpf)) return false; - + + /* if this frame was active, make the previous frame active instead + * since it's tricky to set active frame otherwise + */ + if (gpl->actframe == gpf) + gpl->actframe = gpf->prev; + else + gpl->actframe = NULL; + /* free the frame and its data */ changed = free_gpencil_strokes(gpf); BLI_freelinkN(&gpl->frames, gpf); - gpl->actframe = NULL; - + return changed; } diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 6ea6bafaa14..1f9cf2e11b7 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -149,6 +149,10 @@ Group *BKE_group_copy(Group *group) groupn = BKE_libblock_copy(&group->id); BLI_duplicatelist(&groupn->gobject, &group->gobject); + if (group->id.lib) { + BKE_id_lib_local_paths(G.main, group->id.lib, &groupn->id); + } + return groupn; } diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index a7c76acedbb..2b99b5f4620 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -42,10 +42,18 @@ #include "MEM_guardedalloc.h" +#include "BLI_strict_flags.h" + /* IDPropertyTemplate is a union in DNA_ID.h */ +/** + * if the new is 'IDP_ARRAY_REALLOC_LIMIT' items less, + * than #IDProperty.totallen, reallocate anyway. + */ +#define IDP_ARRAY_REALLOC_LIMIT 200 + /*local size table.*/ -static char idp_size_table[] = { +static size_t idp_size_table[] = { 1, /*strings*/ sizeof(int), sizeof(float), @@ -158,9 +166,8 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) BLI_assert(prop->type == IDP_IDPARRAY); /* first check if the array buffer size has room */ - /* if newlen is 200 items less then totallen, reallocate anyway */ if (newlen <= prop->totallen) { - if (newlen < prop->len && prop->totallen - newlen < 200) { + if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) { int i; for (i = newlen; i < prop->len; i++) @@ -194,7 +201,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) */ newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; - prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * newsize); + prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize); prop->len = newlen; prop->totallen = newsize; } @@ -235,8 +242,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) const bool is_grow = newlen >= prop->len; /* first check if the array buffer size has room */ - /* if newlen is 200 chars less then totallen, reallocate anyway */ - if (newlen <= prop->totallen && prop->totallen - newlen < 200) { + if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) { idp_resize_group_array(prop, newlen, prop->data.pointer); prop->len = newlen; return; @@ -256,7 +262,8 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) if (is_grow == false) idp_resize_group_array(prop, newlen, prop->data.pointer); - prop->data.pointer = MEM_recallocN(prop->data.pointer, idp_size_table[(int)prop->subtype] * newsize); + prop->data.pointer = MEM_recallocN( + prop->data.pointer, idp_size_table[(int)prop->subtype] * (size_t)newsize); if (is_grow == true) idp_resize_group_array(prop, newlen, prop->data.pointer); @@ -336,14 +343,14 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) } else { /* include null terminator '\0' */ - int stlen = strlen(st) + 1; + int stlen = (int)strlen(st) + 1; if (maxlen > 0 && maxlen < stlen) stlen = maxlen; - prop->data.pointer = MEM_mallocN(stlen, "id property string 2"); + prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 2"); prop->len = prop->totallen = stlen; - BLI_strncpy(prop->data.pointer, st, stlen); + BLI_strncpy(prop->data.pointer, st, (size_t)stlen); } prop->type = IDP_STRING; @@ -374,18 +381,18 @@ void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) int stlen; BLI_assert(prop->type == IDP_STRING); - stlen = strlen(st); + stlen = (int)strlen(st); if (maxlen > 0 && maxlen < stlen) stlen = maxlen; if (prop->subtype == IDP_STRING_SUB_BYTE) { IDP_ResizeArray(prop, stlen); - memcpy(prop->data.pointer, st, stlen); + memcpy(prop->data.pointer, st, (size_t)stlen); } else { stlen++; IDP_ResizeArray(prop, stlen); - BLI_strncpy(prop->data.pointer, st, stlen); + BLI_strncpy(prop->data.pointer, st, (size_t)stlen); } } @@ -395,7 +402,7 @@ void IDP_ConcatStringC(IDProperty *prop, const char *st) BLI_assert(prop->type == IDP_STRING); - newlen = prop->len + strlen(st); + newlen = prop->len + (int)strlen(st); /* we have to remember that prop->len includes the null byte for strings. * so there's no need to add +1 to the resize function.*/ IDP_ResizeArray(prop, newlen); @@ -795,10 +802,15 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is case IDP_DOUBLE: return (IDP_Double(prop1) == IDP_Double(prop2)); case IDP_STRING: - return ((prop1->len == prop2->len) && strncmp(IDP_String(prop1), IDP_String(prop2), prop1->len) == 0); + { + return (((prop1->len == prop2->len) && + strncmp(IDP_String(prop1), IDP_String(prop2), (size_t)prop1->len) == 0)); + } case IDP_ARRAY: if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) { - return memcmp(IDP_Array(prop1), IDP_Array(prop2), idp_size_table[(int)prop1->subtype] * prop1->len); + return (memcmp(IDP_Array(prop1), + IDP_Array(prop2), + idp_size_table[(int)prop1->subtype] * (size_t)prop1->len) == 0); } return false; case IDP_GROUP: @@ -870,7 +882,7 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2) * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in * a memory leak. */ -IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *name) +IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name) { IDProperty *prop = NULL; @@ -897,8 +909,10 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n { prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); prop->subtype = val->array.type; - if (val->array.len) - prop->data.pointer = MEM_callocN(idp_size_table[val->array.type] * val->array.len, "id property array"); + if (val->array.len) { + prop->data.pointer = MEM_callocN( + idp_size_table[val->array.type] * (size_t)val->array.len, "id property array"); + } prop->len = prop->totallen = val->array.len; break; } @@ -918,9 +932,9 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n prop->len = 0; } else { - prop->data.pointer = MEM_mallocN(val->string.len, "id property string 2"); + prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 2"); prop->len = prop->totallen = val->string.len; - memcpy(prop->data.pointer, st, val->string.len); + memcpy(prop->data.pointer, st, (size_t)val->string.len); } prop->subtype = IDP_STRING_SUB_BYTE; } @@ -932,10 +946,10 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ } else { - int stlen = strlen(st) + 1; - prop->data.pointer = MEM_mallocN(stlen, "id property string 3"); + int stlen = (int)strlen(st) + 1; + prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 3"); prop->len = prop->totallen = stlen; - memcpy(prop->data.pointer, st, stlen); + memcpy(prop->data.pointer, st, (size_t)stlen); } prop->subtype = IDP_STRING_SUB_UTF8; } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 54f5cb7a68e..870c077ff78 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -117,21 +117,21 @@ typedef struct ImageCacheKey { static unsigned int imagecache_hashhash(const void *key_v) { - const ImageCacheKey *key = (ImageCacheKey *) key_v; + const ImageCacheKey *key = key_v; return key->index; } static bool imagecache_hashcmp(const void *a_v, const void *b_v) { - const ImageCacheKey *a = (ImageCacheKey *) a_v; - const ImageCacheKey *b = (ImageCacheKey *) b_v; + const ImageCacheKey *a = a_v; + const ImageCacheKey *b = b_v; return (a->index != b->index); } static void imagecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags) { - ImageCacheKey *key = (ImageCacheKey *)userkey; + ImageCacheKey *key = userkey; *framenr = IMA_INDEX_FRAME(key->index); *proxy = IMB_PROXY_NONE; @@ -273,7 +273,13 @@ void BKE_image_free_buffers(Image *ima) ima->rr = NULL; } - GPU_free_image(ima); + if (!G.background) { + /* Background mode doesn't use opnegl, + * so we can avoid freeing GPU images and save some + * time by skipping mutex lock. + */ + GPU_free_image(ima); + } ima->ok = IMA_OK; } @@ -378,6 +384,10 @@ Image *BKE_image_copy(Main *bmain, Image *ima) if (ima->packedfile) nima->packedfile = dupPackedFile(ima->packedfile); + if (ima->id.lib) { + BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id); + } + return nima; } @@ -661,7 +671,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) /* otherwise creates new. */ /* does not load ibuf itself */ /* pass on optional frame for #name images */ -Image *BKE_image_load_exists(const char *filepath) +Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists) { Image *ima; char str[FILE_MAX], strtest[FILE_MAX]; @@ -681,16 +691,24 @@ Image *BKE_image_load_exists(const char *filepath) ima->id.us++; /* officially should not, it doesn't link here! */ if (ima->ok == 0) ima->ok = IMA_OK; - /* RETURN! */ + if (r_exists) + *r_exists = true; return ima; } } } } + if (r_exists) + *r_exists = false; return BKE_image_load(G.main, filepath); } +Image *BKE_image_load_exists(const char *filepath) +{ + return BKE_image_load_exists_ex(filepath, NULL); +} + static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], ColorManagedColorspaceSettings *colorspace_settings) { @@ -3393,9 +3411,9 @@ bool BKE_image_has_alpha(struct Image *image) BKE_image_release_ibuf(image, ibuf, lock); if (planes == 32) - return 1; + return true; else - return 0; + return false; } void BKE_image_get_size(Image *image, ImageUser *iuser, int *width, int *height) diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 3ba0c6e5ffa..560a3c0726b 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -73,10 +73,6 @@ #define IPO_BEZTRIPLE 100 #define IPO_BPOINT 101 -/* extern, not threadsafe */ -int slurph_opt = 1; - - void BKE_key_free(Key *key) { KeyBlock *kb; @@ -171,7 +167,11 @@ Key *BKE_key_copy(Key *key) kbn = kbn->next; kb = kb->next; } - + + if (key->id.lib) { + BKE_id_lib_local_paths(G.main, key->id.lib, &keyn->id); + } + return keyn; } @@ -607,7 +607,7 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key k1 = key_block_get_data(key, actkb, kb, &freek1); kref = key_block_get_data(key, actkb, key->refkey, &freekref); - /* this exception is needed for slurphing */ + /* this exception is needed curves with multiple splines */ if (start != 0) { poin += poinsize * start; @@ -891,7 +891,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key } } - /* this exception needed for slurphing */ + /* this exception is needed for curves with multiple splines */ if (start != 0) { poin += poinsize * start; @@ -1168,53 +1168,29 @@ void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, MEM_freeN(per_keyblock_weights); } -static void do_mesh_key(Scene *scene, Object *ob, Key *key, char *out, const int tot) +static void do_mesh_key(Object *ob, Key *key, char *out, const int tot) { KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob); float t[4]; int flag = 0; - if (key->slurph && key->type != KEY_RELATIVE) { + if (key->type == KEY_RELATIVE) { + WeightsArrayCache cache = {0, NULL}; + float **per_keyblock_weights; + per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, &cache); + BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); + BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache); + } + else { const float ctime_scaled = key->ctime / 100.0f; - float delta = (float)key->slurph / tot; - float cfra = BKE_scene_frame_get(scene); - int step, a; - if (tot > 100 && slurph_opt) { - step = tot / 50; - delta *= step; - /* in do_key and cp_key the case a>tot is handled */ - } - else { - step = 1; - } + flag = setkeys(ctime_scaled, &key->block, k, t, 0); - for (a = 0; a < tot; a += step, cfra += delta) { - flag = setkeys(ctime_scaled, &key->block, k, t, 0); - - if (flag == 0) - do_key(a, a + step, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY); - else - cp_key(a, a + step, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY); - } - } - else { - if (key->type == KEY_RELATIVE) { - WeightsArrayCache cache = {0, NULL}; - float **per_keyblock_weights; - per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, &cache); - BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); - BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache); + if (flag == 0) { + do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY); } else { - const float ctime_scaled = key->ctime / 100.0f; - - flag = setkeys(ctime_scaled, &key->block, k, t, 0); - - if (flag == 0) - do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY); - else - cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY); + cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY); } } } @@ -1259,135 +1235,63 @@ static void do_rel_cu_key(Curve *cu, Key *key, KeyBlock *actkb, char *out, const } } -static void do_curve_key(Scene *scene, Object *ob, Key *key, char *out, const int tot) +static void do_curve_key(Object *ob, Key *key, char *out, const int tot) { Curve *cu = ob->data; KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob); float t[4]; int flag = 0; - if (key->slurph && key->type != KEY_RELATIVE) { + if (key->type == KEY_RELATIVE) { + do_rel_cu_key(cu, cu->key, actkb, out, tot); + } + else { const float ctime_scaled = key->ctime / 100.0f; - float delta = (float)key->slurph / tot; - float cfra = BKE_scene_frame_get(scene); - Nurb *nu; - int i = 0, remain = 0; - int step, a; - if (tot > 100 && slurph_opt) { - step = tot / 50; - delta *= step; - /* in do_key and cp_key the case a>tot has been handled */ - } - else { - step = 1; - } + flag = setkeys(ctime_scaled, &key->block, k, t, 0); - for (nu = cu->nurb.first; nu; nu = nu->next) { - int estep, mode; - - if (nu->bp) { - mode = KEY_MODE_BPOINT; - estep = nu->pntsu * nu->pntsv; - } - else if (nu->bezt) { - mode = KEY_MODE_BEZTRIPLE; - estep = 3 * nu->pntsu; - } - else { - mode = 0; - estep = 0; - } - - a = 0; - while (a < estep) { - int count; - - if (remain <= 0) { - cfra += delta; - flag = setkeys(ctime_scaled, &key->block, k, t, 0); - - remain = step; - } - - count = min_ii(remain, estep); - if (mode == KEY_MODE_BEZTRIPLE) { - count += 3 - count % 3; - } - - if (flag == 0) - do_key(i, i + count, tot, (char *)out, key, actkb, k, t, mode); - else - cp_key(i, i + count, tot, (char *)out, key, actkb, k[2], NULL, mode); - - a += count; - i += count; - remain -= count; - } - } - } - else { - if (key->type == KEY_RELATIVE) { - do_rel_cu_key(cu, cu->key, actkb, out, tot); + if (flag == 0) { + do_cu_key(cu, key, actkb, k, t, out, tot); } else { - const float ctime_scaled = key->ctime / 100.0f; - - flag = setkeys(ctime_scaled, &key->block, k, t, 0); - - if (flag == 0) do_cu_key(cu, key, actkb, k, t, out, tot); - else cp_cu_key(cu, key, actkb, k[2], 0, tot, out, tot); + cp_cu_key(cu, key, actkb, k[2], 0, tot, out, tot); } } } -static void do_latt_key(Scene *scene, Object *ob, Key *key, char *out, const int tot) +static void do_latt_key(Object *ob, Key *key, char *out, const int tot) { Lattice *lt = ob->data; KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob); float t[4]; int flag; - if (key->slurph && key->type != KEY_RELATIVE) { - const float ctime_scaled = key->ctime / 100.0f; - float delta = (float)key->slurph / tot; - float cfra = BKE_scene_frame_get(scene); - int a; - - for (a = 0; a < tot; a++, cfra += delta) { - flag = setkeys(ctime_scaled, &key->block, k, t, 0); - - if (flag == 0) - do_key(a, a + 1, tot, out, key, actkb, k, t, KEY_MODE_DUMMY); - else - cp_key(a, a + 1, tot, out, key, actkb, k[2], NULL, KEY_MODE_DUMMY); - } + if (key->type == KEY_RELATIVE) { + float **per_keyblock_weights; + per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, NULL); + BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); + BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, NULL); } else { - if (key->type == KEY_RELATIVE) { - float **per_keyblock_weights; - per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, NULL); - BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); - BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, NULL); + const float ctime_scaled = key->ctime / 100.0f; + + flag = setkeys(ctime_scaled, &key->block, k, t, 0); + + if (flag == 0) { + do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY); } else { - const float ctime_scaled = key->ctime / 100.0f; - - flag = setkeys(ctime_scaled, &key->block, k, t, 0); - - if (flag == 0) - do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY); - else - cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY); + cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY); } } - + if (lt->flag & LT_OUTSIDE) outside_lattice(lt); } /* returns key coordinates (+ tilt) when key applied, NULL otherwise */ -float *BKE_key_evaluate_object_ex(Scene *scene, Object *ob, int *r_totelem, - float *arr, size_t arr_size) +float *BKE_key_evaluate_object_ex( + Object *ob, int *r_totelem, + float *arr, size_t arr_size) { Key *key = BKE_key_from_object(ob); KeyBlock *actkb = BKE_keyblock_from_object(ob); @@ -1469,10 +1373,10 @@ float *BKE_key_evaluate_object_ex(Scene *scene, Object *ob, int *r_totelem, } else { - if (ob->type == OB_MESH) do_mesh_key(scene, ob, key, out, tot); - else if (ob->type == OB_LATTICE) do_latt_key(scene, ob, key, out, tot); - else if (ob->type == OB_CURVE) do_curve_key(scene, ob, key, out, tot); - else if (ob->type == OB_SURF) do_curve_key(scene, ob, key, out, tot); + if (ob->type == OB_MESH) do_mesh_key(ob, key, out, tot); + else if (ob->type == OB_LATTICE) do_latt_key(ob, key, out, tot); + else if (ob->type == OB_CURVE) do_curve_key(ob, key, out, tot); + else if (ob->type == OB_SURF) do_curve_key(ob, key, out, tot); } if (r_totelem) { @@ -1481,9 +1385,9 @@ float *BKE_key_evaluate_object_ex(Scene *scene, Object *ob, int *r_totelem, return (float *)out; } -float *BKE_key_evaluate_object(Scene *scene, Object *ob, int *r_totelem) +float *BKE_key_evaluate_object(Object *ob, int *r_totelem) { - return BKE_key_evaluate_object_ex(scene, ob, r_totelem, NULL, 0); + return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0); } Key *BKE_key_from_object(Object *ob) diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 4a413850ec0..93b9c22566d 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -41,7 +41,6 @@ #include "DNA_scene_types.h" #include "DNA_texture_types.h" -#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -127,6 +126,10 @@ Lamp *BKE_lamp_copy(Lamp *la) if (la->preview) lan->preview = BKE_previewimg_copy(la->preview); + if (la->id.lib) { + BKE_id_lib_local_paths(G.main, la->id.lib, &lan->id); + } + return lan; } diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 3f12e3efcc7..fa62308ec53 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -284,6 +284,10 @@ Lattice *BKE_lattice_copy(Lattice *lt) ltn->editlatt = NULL; + if (lt->id.lib) { + BKE_id_lib_local_paths(G.main, lt->id.lib, <n->id); + } + return ltn; } @@ -575,7 +579,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di /* test for cyclic */ bl = ob->curve_cache->bev.first; - if (!bl->nr) return 0; + if (!bl->nr) return false; if (bl->poly > -1) cycl = 1; if (cycl == 0) { @@ -608,9 +612,9 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di /* weight - not used but could be added */ } } - return 1; + return true; } - return 0; + return false; } /* for each point, rotate & translate to curve */ @@ -634,9 +638,7 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], #endif if (par->curve_cache->path == NULL) { - return 0; /* happens on append, cyclic dependencies - * and empty curves - */ + return false; /* happens on append, cyclic dependencies and empty curves */ } /* options */ @@ -718,9 +720,9 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], if (r_quat) copy_qt_qt(r_quat, quat); - return 1; + return true; } - return 0; + return false; } void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], @@ -939,10 +941,10 @@ bool object_deform_mball(Object *ob, ListBase *dispbase) (float(*)[3])dl->verts, dl->nr, NULL, 1.0f); } - return 1; + return true; } else { - return 0; + return false; } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index b49eee3ea22..752c2961f28 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -139,7 +139,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id) BKE_bpath_traverse_id(bmain, id, BKE_bpath_relocate_visitor, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, - bpath_user_data); + (void *)bpath_user_data); } void id_lib_extern(ID *id) @@ -351,7 +351,7 @@ bool id_copy(ID *id, ID **newid, bool test) case ID_VF: return false; /* not implemented */ case ID_TXT: - if (!test) *newid = (ID *)BKE_text_copy((Text *)id); + if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id); return true; case ID_SCRIPT: return false; /* deprecated */ diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index bcdaf9b7af0..d244e9d79d2 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -53,8 +53,6 @@ #include "BKE_colortools.h" #include "BKE_animsys.h" -#include "RNA_access.h" - static const char *modifier_name[LS_MODIFIER_NUM] = { NULL, "Along Stroke", @@ -212,6 +210,10 @@ FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle) for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next) BKE_linestyle_geometry_modifier_copy(new_linestyle, m); + if (linestyle->id.lib) { + BKE_id_lib_local_paths(G.main, linestyle->id.lib, &new_linestyle->id); + } + return new_linestyle; } diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index b05634f5fe5..83ca6cd8d72 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -50,6 +50,7 @@ #include "DNA_sequence_types.h" #include "BKE_curve.h" +#include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mask.h" @@ -59,8 +60,6 @@ #include "BKE_movieclip.h" #include "BKE_image.h" -#include "NOD_composite.h" - static struct { ListBase splines; struct GHash *id_hash; @@ -857,6 +856,10 @@ Mask *BKE_mask_copy(Mask *mask) mask_new->id.us++; } + if (mask->id.lib) { + BKE_id_lib_local_paths(G.main, mask->id.lib, &mask_new->id); + } + return mask_new; } @@ -1187,11 +1190,12 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(tracking, ob, parent->sub_parent); if (plane_track) { - MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr); + float corners[4][2]; float aspx, aspy; float frame_size[2], H[3][3], mask_from_clip_matrix[3][3], mask_to_clip_matrix[3][3]; - BKE_tracking_homography_between_two_quads(parent->parent_corners_orig, plane_marker->corners, H); + BKE_tracking_plane_marker_get_subframe_corners(plane_track, ctime, corners); + BKE_tracking_homography_between_two_quads(parent->parent_corners_orig, corners, H); unit_m3(mask_from_clip_matrix); diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index 3ed6148054c..5517fc36bc1 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -40,8 +40,6 @@ #include "BLI_math.h" #include "DNA_mask_types.h" -#include "DNA_node_types.h" -#include "DNA_scene_types.h" #include "BKE_curve.h" #include "BKE_mask.h" diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index ea1b9a3f13d..981064bb22a 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -116,7 +116,7 @@ void BKE_material_free_ex(Material *ma, bool do_id_user) MEM_freeN(ma->texpaintslot); if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); } void init_material(Material *ma) @@ -252,6 +252,10 @@ Material *BKE_material_copy(Material *ma) BLI_listbase_clear(&man->gpumaterial); + if (ma->id.lib) { + BKE_id_lib_local_paths(G.main, ma->id.lib, &man->id); + } + return man; } @@ -681,16 +685,16 @@ Material *give_current_material(Object *ob, short act) /* if object cannot have material, (totcolp == NULL) */ totcolp = give_totcolp(ob); if (totcolp == NULL || ob->totcol == 0) return NULL; - - if (act < 0) { - printf("Negative material index!\n"); - } - + /* return NULL for invalid 'act', can happen for mesh face indices */ if (act > ob->totcol) return NULL; - else if (act <= 0) + else if (act <= 0) { + if (act < 0) { + printf("Negative material index!\n"); + } return NULL; + } if (ob->matbits && ob->matbits[act - 1]) { /* in object */ ma = ob->mat[act - 1]; @@ -1137,28 +1141,28 @@ static bool material_in_nodetree(bNodeTree *ntree, Material *mat) if (node->id) { if (GS(node->id->name) == ID_MA) { if (node->id == (ID *)mat) { - return 1; + return true; } } else if (node->type == NODE_GROUP) { if (material_in_nodetree((bNodeTree *)node->id, mat)) { - return 1; + return true; } } } } - return 0; + return false; } bool material_in_material(Material *parmat, Material *mat) { if (parmat == mat) - return 1; + return true; else if (parmat->nodetree && parmat->use_nodes) return material_in_nodetree(parmat->nodetree, mat); else - return 0; + return false; } @@ -1724,7 +1728,7 @@ void paste_matcopybuf(Material *ma) MEM_freeN(ma->nodetree); } - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); id = (ma->id); memcpy(ma, &matcopybuf, sizeof(Material)); diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 453c6df6e3b..34ab2a85593 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -238,6 +238,10 @@ MetaBall *BKE_mball_copy(MetaBall *mb) mbn->editelems = NULL; mbn->lastelem = NULL; + if (mb->id.lib) { + BKE_id_lib_local_paths(G.main, mb->id.lib, &mbn->id); + } + return mbn; } @@ -2436,10 +2440,10 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) if (BKE_mball_minmax(mb, min, max)) { mid_v3_v3v3(r_cent, min, max); - return 1; + return true; } - return 0; + return false; } void BKE_mball_transform(MetaBall *mb, float mat[4][4]) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 2e80379522c..c47d294cfb2 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -562,6 +562,10 @@ Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me) men->key = BKE_key_copy(me->key); if (men->key) men->key->from = (ID *)men; + if (me->id.lib) { + BKE_id_lib_local_paths(bmain, me->id.lib, &men->id); + } + return men; } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 4c9e44682c3..915abdb6766 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -896,13 +896,6 @@ float BKE_mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart, mvarray[loopstart[2].v].co ); } - else if (mpoly->totloop == 4) { - return area_quad_v3(mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - mvarray[loopstart[2].v].co, - mvarray[loopstart[3].v].co - ); - } else { int i; MLoop *l_iter = loopstart; diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index 53d1aae104c..9e490ae6766 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -32,10 +32,12 @@ #include "DNA_meshdata_types.h" #include "BLI_utildefines.h" +#include "BLI_bitmap.h" #include "BLI_math.h" #include "BKE_mesh_mapping.h" #include "BKE_customdata.h" +#include "BLI_memarena.h" #include "BLI_strict_flags.h" @@ -156,18 +158,25 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap) } } -/* Generates a map where the key is the vertex and the value is a list - * of polys that use that vertex as a corner. The lists are allocated - * from one memory pool. */ -void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, int **r_mem, - const MPoly *mpoly, const MLoop *mloop, - int totvert, int totpoly, int totloop) +/** + + + * Generates a map where the key is the vertex and the value is a list + * of polys or loops that use that vertex as a corner. The lists are allocated + * from one memory pool. + * + * Wrapped by #BKE_mesh_vert_poly_map_create & BKE_mesh_vert_loop_map_create + */ +static void mesh_vert_poly_or_loop_map_create( + MeshElemMap **r_map, int **r_mem, + const MPoly *mpoly, const MLoop *mloop, + int totvert, int totpoly, int totloop, const bool do_loops) { - MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert poly map"); + MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__); int *indices, *index_iter; int i, j; - indices = index_iter = MEM_mallocN(sizeof(int) * (size_t)totloop, "vert poly map mem"); + indices = index_iter = MEM_mallocN(sizeof(int) * (size_t)totloop, __func__); /* Count number of polys for each vertex */ for (i = 0; i < totpoly; i++) { @@ -193,7 +202,7 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, int **r_mem, for (j = 0; j < p->totloop; j++) { unsigned int v = mloop[p->loopstart + j].v; - map[v].indices[map[v].count] = i; + map[v].indices[map[v].count] = do_loops ? p->loopstart + j : i; map[v].count++; } } @@ -202,6 +211,28 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, int **r_mem, *r_mem = indices; } +/** + * Generates a map where the key is the vertex and the value is a list of polys that use that vertex as a corner. + * The lists are allocated from one memory pool. + */ +void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, int **r_mem, + const MPoly *mpoly, const MLoop *mloop, + int totvert, int totpoly, int totloop) +{ + mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false); +} + +/** + * Generates a map where the key is the vertex and the value is a list of loops that use that vertex as a corner. + * The lists are allocated from one memory pool. + */ +void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem, + const MPoly *mpoly, const MLoop *mloop, + int totvert, int totpoly, int totloop) +{ + mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true); +} + /* Generates a map where the key is the vertex and the value is a list * of edges that use that vertex as an endpoint. The lists are allocated * from one memory pool. */ @@ -345,26 +376,30 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map, int **r_mem, /** \} */ - /* -------------------------------------------------------------------- */ -/** \name Mesh Smooth Groups +/** \name Mesh loops/poly islands. + * Used currently for UVs and 'smooth groups'. * \{ */ -/** - * Calculate smooth groups from sharp edges. - * - * \param r_totgroup The total number of groups, 1 or more. - * \return Polygon aligned array of group index values (bitflags if use_bitflags is true), starting at 1. +/** Callback deciding whether the given poly/loop/edge define an island boundary or not. */ -int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, - const MPoly *mpoly, const int totpoly, - const MLoop *mloop, const int totloop, - int *r_totgroup, const bool use_bitflags) +typedef bool (*MeshRemap_CheckIslandBoundary)( + const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge, + const int nbr_egde_users); + +static void poly_edge_loop_islands_calc( + const MEdge *medge, const int totedge, const MPoly *mpoly, const int totpoly, + const MLoop *mloop, const int totloop, MeshElemMap *edge_poly_map, + const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, + int **r_poly_groups, int *r_totgroup, BLI_bitmap **r_edge_borders, int *r_totedgeborder) { int *poly_groups; int *poly_stack; + BLI_bitmap *edge_borders = NULL; + int num_edgeborders = 0; + int poly_prev = 0; const int temp_poly_group_id = 3; /* Placeholder value. */ const int poly_group_id_overflowed = 5; /* Group we could not find any available bit, will be reset to 0 at end */ @@ -372,18 +407,27 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, bool group_id_overflow = false; /* map vars */ - MeshElemMap *edge_poly_map; - int *edge_poly_mem; + int *edge_poly_mem = NULL; if (totpoly == 0) { *r_totgroup = 0; - return NULL; + *r_poly_groups = NULL; + if (r_edge_borders) { + *r_edge_borders = NULL; + *r_totedgeborder = 0; + } + return; } - BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem, - medge, totedge, - mpoly, totpoly, - mloop, totloop); + if (r_edge_borders) { + edge_borders = BLI_BITMAP_NEW(totedge, __func__); + *r_totedgeborder = 0; + } + + if (!edge_poly_map) { + BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem, + medge, totedge, mpoly, totpoly, mloop, totloop); + } poly_groups = MEM_callocN(sizeof(int) * (size_t)totpoly, __func__); poly_stack = MEM_mallocN(sizeof(int) * (size_t)totpoly, __func__); @@ -416,22 +460,20 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, while (ps_curr_idx != ps_end_idx) { const MPoly *mp; const MLoop *ml; - bool sharp_poly; int j; poly = poly_stack[ps_curr_idx++]; BLI_assert(poly_groups[poly] == poly_group_id); mp = &mpoly[poly]; - sharp_poly = !(mp->flag & ME_SMOOTH); for (ml = &mloop[mp->loopstart], j = mp->totloop; j--; ml++) { /* loop over poly users */ - const MeshElemMap *map_ele = &edge_poly_map[ml->e]; + const int me_idx = (int)ml->e; + const MEdge *me = &medge[me_idx]; + const MeshElemMap *map_ele = &edge_poly_map[me_idx]; const int *p = map_ele->indices; int i = map_ele->count; - /* Edge is smooth only if its poly is not sharp, edge is not sharp, - * and edge is used by exactly two polygons. */ - if (!sharp_poly && !(medge[ml->e].flag & ME_SHARP) && i == 2) { + if (!edge_boundary_check(mp, ml, me, i)) { for (; i--; p++) { /* if we meet other non initialized its a bug */ BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id)); @@ -442,14 +484,20 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, } } } - else if (use_bitflags) { - /* Find contiguous smooth groups already assigned, these are the values we can't reuse! */ - for (; i--; p++) { - int bit = poly_groups[*p]; - if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) && - !(bit_poly_group_mask & bit)) - { - bit_poly_group_mask |= bit; + else { + if (edge_borders && !BLI_BITMAP_TEST(edge_borders, me_idx)) { + BLI_BITMAP_ENABLE(edge_borders, me_idx); + num_edgeborders++; + } + if (use_bitflags) { + /* Find contiguous smooth groups already assigned, these are the values we can't reuse! */ + for (; i--; p++) { + int bit = poly_groups[*p]; + if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) && + !(bit_poly_group_mask & bit)) + { + bit_poly_group_mask |= bit; + } } } } @@ -502,12 +550,255 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, tot_group++; } - MEM_freeN(edge_poly_map); - MEM_freeN(edge_poly_mem); + if (edge_poly_mem) { + MEM_freeN(edge_poly_map); + MEM_freeN(edge_poly_mem); + } MEM_freeN(poly_stack); *r_totgroup = tot_group; + *r_poly_groups = poly_groups; + if (r_edge_borders) { + *r_edge_borders = edge_borders; + *r_totedgeborder = num_edgeborders; + } +} + +static bool poly_is_island_boundary_smooth_cb( + const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, + const int nbr_egde_users) +{ + /* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */ + return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2)); +} + +/** + * Calculate smooth groups from sharp edges. + * + * \param r_totgroup The total number of groups, 1 or more. + * \return Polygon aligned array of group index values (bitflags if use_bitflags is true), starting at 1 + * (0 being used as 'invalid' flag). + * Note it's callers's responsibility to MEM_freeN returned array. + */ +int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, + const MPoly *mpoly, const int totpoly, + const MLoop *mloop, const int totloop, + int *r_totgroup, const bool use_bitflags) +{ + int *poly_groups = NULL; + + poly_edge_loop_islands_calc( + medge, totedge, mpoly, totpoly, mloop, totloop, NULL, use_bitflags, + poly_is_island_boundary_smooth_cb, &poly_groups, r_totgroup, NULL, NULL); return poly_groups; } + +#define MISLAND_DEFAULT_BUFSIZE 64 + +void BKE_mesh_loop_islands_init( + MeshIslandStore *island_store, + const short item_type, const int items_num, const short island_type, const short innercut_type) +{ + MemArena *mem = island_store->mem; + + if (mem == NULL) { + mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + island_store->mem = mem; + } + /* else memarena should be cleared */ + + BLI_assert(ELEM(item_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP)); + BLI_assert(ELEM(island_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP)); + + island_store->item_type = item_type; + island_store->items_to_islands_num = items_num; + island_store->items_to_islands = BLI_memarena_alloc(mem, sizeof(*island_store->items_to_islands) * (size_t)items_num); + + island_store->island_type = island_type; + island_store->islands_num_alloc = MISLAND_DEFAULT_BUFSIZE; + island_store->islands = BLI_memarena_alloc(mem, sizeof(*island_store->islands) * island_store->islands_num_alloc); + + island_store->innercut_type = innercut_type; + island_store->innercuts = BLI_memarena_alloc(mem, sizeof(*island_store->innercuts) * island_store->islands_num_alloc); +} + +void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store) +{ + island_store->item_type = MISLAND_TYPE_NONE; + island_store->items_to_islands_num = 0; + island_store->items_to_islands = NULL; + + island_store->island_type = MISLAND_TYPE_NONE; + island_store->islands_num = 0; + island_store->islands = NULL; + + island_store->innercut_type = MISLAND_TYPE_NONE; + island_store->innercuts = NULL; + + if (island_store->mem) { + BLI_memarena_clear(island_store->mem); + } + + island_store->islands_num_alloc = 0; +} + +void BKE_mesh_loop_islands_free(MeshIslandStore *island_store) +{ + if (island_store->mem) { + BLI_memarena_free(island_store->mem); + island_store->mem = NULL; + } +} + +void BKE_mesh_loop_islands_add( + MeshIslandStore *island_store, const int item_num, int *items_indices, + const int num_island_items, int *island_item_indices, + const int num_innercut_items, int *innercut_item_indices) +{ + MemArena *mem = island_store->mem; + + MeshElemMap *isld, *innrcut; + const int curr_island_idx = island_store->islands_num++; + const size_t curr_num_islands = (size_t)island_store->islands_num; + int i = item_num; + + island_store->items_to_islands_num = item_num; + while (i--) { + island_store->items_to_islands[items_indices[i]] = curr_island_idx; + } + + if (UNLIKELY(curr_num_islands > island_store->islands_num_alloc)) { + MeshElemMap **islds, **innrcuts; + + island_store->islands_num_alloc *= 2; + islds = BLI_memarena_alloc(mem, sizeof(*islds) * island_store->islands_num_alloc); + memcpy(islds, island_store->islands, sizeof(*islds) * (curr_num_islands - 1)); + island_store->islands = islds; + + innrcuts = BLI_memarena_alloc(mem, sizeof(*innrcuts) * island_store->islands_num_alloc); + memcpy(innrcuts, island_store->innercuts, sizeof(*innrcuts) * (curr_num_islands - 1)); + island_store->innercuts = innrcuts; + } + + island_store->islands[curr_island_idx] = isld = BLI_memarena_alloc(mem, sizeof(*isld)); + isld->count = num_island_items; + isld->indices = BLI_memarena_alloc(mem, sizeof(*isld->indices) * (size_t)num_island_items); + memcpy(isld->indices, island_item_indices, sizeof(*isld->indices) * (size_t)num_island_items); + + island_store->innercuts[curr_island_idx] = innrcut = BLI_memarena_alloc(mem, sizeof(*innrcut)); + innrcut->count = num_innercut_items; + innrcut->indices = BLI_memarena_alloc(mem, sizeof(*innrcut->indices) * (size_t)num_innercut_items); + memcpy(innrcut->indices, innercut_item_indices, sizeof(*innrcut->indices) * (size_t)num_innercut_items); +} + +/* TODO: I'm not sure edge seam flag is enough to define UV islands? Maybe we should also consider UVmaps values + * themselves (i.e. different UV-edges for a same mesh-edge => boundary edge too?). + * Would make things much more complex though, and each UVMap would then need its own mesh mapping, + * not sure we want that at all! + */ +static bool mesh_check_island_boundary_uv( + const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, + const int UNUSED(nbr_egde_users)) +{ + /* Edge is UV boundary if tagged as seam. */ + return (me->flag & ME_SEAM) != 0; +} + +/** + * \note all this could be optimized... + * Not sure it would be worth the more complex code, though, those loops + * are supposed to be really quick to do... + */ +bool BKE_mesh_calc_islands_loop_poly_uv( + MVert *UNUSED(verts), const int UNUSED(totvert), + MEdge *edges, const int totedge, + MPoly *polys, const int totpoly, + MLoop *loops, const int totloop, + MeshIslandStore *r_island_store) +{ + int *poly_groups = NULL; + int num_poly_groups; + + /* map vars */ + MeshElemMap *edge_poly_map; + int *edge_poly_mem; + + int *poly_indices = MEM_mallocN(sizeof(*poly_indices) * (size_t)totpoly, __func__); + int *loop_indices = MEM_mallocN(sizeof(*loop_indices) * (size_t)totloop, __func__); + int num_pidx, num_lidx; + + /* Those are used to detect 'inner cuts', i.e. edges that are borders, and yet have two or more polys of + * a same group using them (typical case: seam used to unwrap properly a cylinder). */ + BLI_bitmap *edge_borders; + int num_edge_borders; + char *edge_border_count = NULL; + int *edge_innercut_indices = NULL; + int num_einnercuts = 0; + + int grp_idx, p_idx, pl_idx, l_idx; + + BKE_mesh_loop_islands_clear(r_island_store); + BKE_mesh_loop_islands_init(r_island_store, MISLAND_TYPE_LOOP, totloop, MISLAND_TYPE_POLY, MISLAND_TYPE_EDGE); + + BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem, + edges, totedge, polys, totpoly, loops, totloop); + + poly_edge_loop_islands_calc( + edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false, + mesh_check_island_boundary_uv, &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders); + + if (!num_poly_groups) { + /* Should never happen... */ + return false; + } + + if (num_edge_borders) { + edge_border_count = MEM_mallocN(sizeof(*edge_border_count) * (size_t)totedge, __func__); + edge_innercut_indices = MEM_mallocN(sizeof(*edge_innercut_indices) * (size_t)num_edge_borders, __func__); + } + + /* Note: here we ignore '0' invalid group - this should *never* happen in this case anyway? */ + for (grp_idx = 1; grp_idx <= num_poly_groups; grp_idx++) { + num_pidx = num_lidx = 0; + if (num_edge_borders) { + num_einnercuts = 0; + memset(edge_border_count, 0, sizeof(*edge_border_count) * (size_t)totedge); + } + + for (p_idx = 0; p_idx < totpoly; p_idx++) { + MPoly *mp; + + if (poly_groups[p_idx] != grp_idx) { + continue; + } + + mp = &polys[p_idx]; + poly_indices[num_pidx++] = p_idx; + for (l_idx = mp->loopstart, pl_idx = 0; pl_idx < mp->totloop; l_idx++, pl_idx++) { + MLoop *ml = &loops[l_idx]; + loop_indices[num_lidx++] = l_idx; + if (num_edge_borders && BLI_BITMAP_TEST(edge_borders, ml->e) && (edge_border_count[ml->e] < 2)) { + edge_border_count[ml->e]++; + if (edge_border_count[ml->e] == 2) { + edge_innercut_indices[num_einnercuts++] = (int)ml->e; + } + } + } + } + + BKE_mesh_loop_islands_add(r_island_store, num_lidx, loop_indices, num_pidx, poly_indices, + num_einnercuts, edge_innercut_indices); + } + + MEM_freeN(poly_indices); + MEM_freeN(loop_indices); + MEM_freeN(poly_groups); + if (num_edge_borders) { + MEM_freeN(edge_border_count); + MEM_freeN(edge_innercut_indices); + } + return true; +} + /** \} */ diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c new file mode 100644 index 00000000000..1deb7cfdd7f --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -0,0 +1,1988 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_remap.c + * \ingroup bke + * + * Functions for mapping data between meshes. + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_alloca.h" +#include "BLI_astar.h" +#include "BLI_bitmap.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_polyfill2d.h" +#include "BLI_rand.h" + +#include "BKE_bvhutils.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" /* own include */ + +#include "BLI_strict_flags.h" + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh to mesh mapping + * \{ */ + +void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num) +{ + MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + + BKE_mesh_remap_free(map); + + map->items = BLI_memarena_alloc(mem, sizeof(*map->items) * (size_t)items_num); + map->items_num = items_num; + + map->mem = mem; +} + +void BKE_mesh_remap_free(MeshPairRemap *map) +{ + if (map->mem) { + BLI_memarena_free((MemArena *)map->mem); + } + + map->items_num = 0; + map->items = NULL; + map->mem = NULL; +} + +static void mesh_remap_item_define( + MeshPairRemap *map, const int index, const float UNUSED(hit_dist), const int island, + const int sources_num, const int *indices_src, const float *weights_src) +{ + MeshPairRemapItem *mapit = &map->items[index]; + MemArena *mem = map->mem; + + if (sources_num) { + mapit->sources_num = sources_num; + mapit->indices_src = BLI_memarena_alloc(mem, sizeof(*mapit->indices_src) * (size_t)sources_num); + memcpy(mapit->indices_src, indices_src, sizeof(*mapit->indices_src) * (size_t)sources_num); + mapit->weights_src = BLI_memarena_alloc(mem, sizeof(*mapit->weights_src) * (size_t)sources_num); + memcpy(mapit->weights_src, weights_src, sizeof(*mapit->weights_src) * (size_t)sources_num); + } + else { + mapit->sources_num = 0; + mapit->indices_src = NULL; + mapit->weights_src = NULL; + } + /* UNUSED */ + // mapit->hit_dist = hit_dist; + mapit->island = island; +} + +void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index) +{ + mesh_remap_item_define(map, index, FLT_MAX, 0, 0, NULL, NULL); +} + +static int mesh_remap_interp_poly_data_get( + const MPoly *mp, MLoop *mloops, const float (*vcos_src)[3], const float point[3], + size_t *buff_size, float (**vcos)[3], const bool use_loops, int **indices, float **weights, + const bool do_weights, int *r_closest_index) +{ + MLoop *ml; + float (*vco)[3]; + float ref_dist_sq = FLT_MAX; + int *index; + const int sources_num = mp->totloop; + int i; + + if ((size_t)sources_num > *buff_size) { + *buff_size = (size_t)sources_num; + *vcos = MEM_reallocN(*vcos, sizeof(**vcos) * *buff_size); + *indices = MEM_reallocN(*indices, sizeof(**indices) * *buff_size); + if (do_weights) { + *weights = MEM_reallocN(*weights, sizeof(**weights) * *buff_size); + } + } + + for (i = 0, ml = &mloops[mp->loopstart], vco = *vcos, index = *indices; i < sources_num; i++, ml++, vco++, index++) { + *index = use_loops ? (int)mp->loopstart + i : (int)ml->v; + copy_v3_v3(*vco, vcos_src[ml->v]); + if (r_closest_index) { + /* Find closest vert/loop in this case. */ + const float dist_sq = len_squared_v3v3(point, *vco); + if (dist_sq < ref_dist_sq) { + ref_dist_sq = dist_sq; + *r_closest_index = *index; + } + } + } + + if (do_weights) { + interp_weights_poly_v3(*weights, *vcos, sources_num, point); + } + + return sources_num; +} + +static bool mesh_remap_bvhtree_query_nearest( + BVHTreeFromMesh *treedata, BVHTreeNearest *nearest, const SpaceTransform *space_transform, + const float in_co[3], const float max_dist_sq, + float *r_hit_dist) +{ + float co[3]; + + copy_v3_v3(co, in_co); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, co); + } + + /* Use local proximity heuristics (to reduce the nearest search). */ + if (nearest->index != -1) { + nearest->dist_sq = min_ff(len_squared_v3v3(co, nearest->co), max_dist_sq); + } + else { + nearest->dist_sq = max_dist_sq; + } + /* Compute and store result. If invalid (-1 index), keep FLT_MAX dist. */ + BLI_bvhtree_find_nearest(treedata->tree, co, nearest, treedata->nearest_callback, treedata); + + if ((nearest->index != -1) && (nearest->dist_sq <= max_dist_sq)) { + *r_hit_dist = sqrtf(nearest->dist_sq); + return true; + } + else { + return false; + } +} + +static bool mesh_remap_bvhtree_query_raycast( + BVHTreeFromMesh *treedata, BVHTreeRayHit *rayhit, const SpaceTransform *space_transform, + const float in_co[3], const float in_no[3], const float radius, const float max_dist, + float *r_hit_dist) +{ + BVHTreeRayHit rayhit_tmp; + float co[3], no[3]; + + copy_v3_v3(co, in_co); + copy_v3_v3(no, in_no); + + /* Convert the vertex to tree coordinates, if needed. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, co); + BLI_space_transform_apply_normal(space_transform, no); + } + + rayhit->index = -1; + rayhit->dist = max_dist; + BLI_bvhtree_ray_cast(treedata->tree, co, no, radius, rayhit, treedata->raycast_callback, treedata); + + /* Also cast in the other direction! */ + rayhit_tmp = *rayhit; + negate_v3(no); + BLI_bvhtree_ray_cast(treedata->tree, co, no, radius, &rayhit_tmp, treedata->raycast_callback, treedata); + if (rayhit_tmp.dist < rayhit->dist) { + *rayhit = rayhit_tmp; + } + + if ((rayhit->index != -1) && (rayhit->dist <= max_dist)) { + *r_hit_dist = rayhit->dist; + return true; + } + else { + return false; + } +} + +/* Little helper when dealing with source islands */ +typedef struct IslandResult { + float factor; /* A factor, based on which best island for a given set of elements will be selected. */ + int index_src; /* Index of the source. */ + float hit_dist; /* The actual hit distance. */ + float hit_point[3]; /* The hit point, if relevant. */ +} IslandResult; + +/* Note about all bvh/raycasting stuff below: + * * We must use our ray radius as BVH epsilon too, else rays not hitting anything but 'passing near' an item + * would be missed (since BVH handling would not detect them, 'refining' callbacks won't be executed, + * even though they would return a valid hit). + * * However, in 'islands' case where each hit gets a weight, 'precise' hits should have a better weight than + * 'approximate' hits. To address that, we simplify things with: + * ** A first raycast with default, given rayradius; + * ** If first one fails, we do more raycasting with bigger radius, but if hit is found + * it will get smaller weight. + * This only concerns loops, currently (because of islands), and 'sampled' edges/polys norproj. + */ + +/* At most n raycasts per 'real' ray. */ +#define MREMAP_RAYCAST_APPROXIMATE_NR 3 +/* Each approximated raycasts will have n times bigger radius than previous one. */ +#define MREMAP_RAYCAST_APPROXIMATE_FAC 5.0f +/* BVH epsilon value we have to give to bvh 'constructor' when doing approximated raycasting. */ +#define MREMAP_RAYCAST_APPROXIMATE_BVHEPSILON(_ray_radius) \ + ((float)MREMAP_RAYCAST_APPROXIMATE_NR * MREMAP_RAYCAST_APPROXIMATE_FAC * (_ray_radius)) + +/* min 16 rays/face, max 400. */ +#define MREMAP_RAYCAST_TRI_SAMPLES_MIN 4 +#define MREMAP_RAYCAST_TRI_SAMPLES_MAX 20 + +/* Will be enough in 99% of cases. */ +#define MREMAP_DEFAULT_BUFSIZE 32 + +void BKE_mesh_remap_calc_verts_from_dm( + const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, + const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src, + MeshPairRemap *r_map) +{ + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + int i; + + BLI_assert(mode & MREMAP_MODE_VERT); + + BKE_mesh_remap_init(r_map, numverts_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + BLI_assert(numverts_dst == dm_src->getNumVerts(dm_src)); + for (i = 0; i < numverts_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh treedata = {NULL}; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + float hit_dist; + + if (mode == MREMAP_MODE_VERT_NEAREST) { + bvhtree_from_mesh_verts(&treedata, dm_src, 0.0f, 2, 6); + nearest.index = -1; + + for (i = 0; i < numverts_dst; i++) { + float tmp_co[3]; + + copy_v3_v3(tmp_co, verts_dst[i].co); + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight); + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) { + MEdge *edges_src = dm_src->getEdgeArray(dm_src); + float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); + dm_src->getVertCos(dm_src, vcos_src); + + bvhtree_from_mesh_edges(&treedata, dm_src, 0.0f, 2, 6); + nearest.index = -1; + + for (i = 0; i < numverts_dst; i++) { + float tmp_co[3]; + + copy_v3_v3(tmp_co, verts_dst[i].co); + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + MEdge *me = &edges_src[nearest.index]; + const float *v1cos = vcos_src[me->v1]; + const float *v2cos = vcos_src[me->v2]; + + if (mode == MREMAP_MODE_VERT_EDGE_NEAREST) { + const float dist_v1 = len_squared_v3v3(tmp_co, v1cos); + const float dist_v2 = len_squared_v3v3(tmp_co, v2cos); + const int index = (int)((dist_v1 > dist_v2) ? me->v2 : me->v1); + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight); + } + else if (mode == MREMAP_MODE_VERT_EDGEINTERP_NEAREST) { + int indices[2]; + float weights[2]; + + indices[0] = (int)me->v1; + indices[1] = (int)me->v2; + + /* Weight is inverse of point factor here... */ + weights[0] = line_point_factor_v3(tmp_co, v2cos, v1cos); + CLAMP(weights[0], 0.0f, 1.0f); + weights[1] = 1.0f - weights[0]; + + mesh_remap_item_define(r_map, i, hit_dist, 0, 2, indices, weights); + } + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(vcos_src); + } + else if (ELEM(mode, MREMAP_MODE_VERT_POLY_NEAREST, MREMAP_MODE_VERT_POLYINTERP_NEAREST, + MREMAP_MODE_VERT_POLYINTERP_VNORPROJ)) + { + MPoly *polys_src = dm_src->getPolyArray(dm_src); + MLoop *loops_src = dm_src->getLoopArray(dm_src); + float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); + int *tessface_to_poly_map_src; + + size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE; + float (*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__); + int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__); + float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__); + + dm_src->getVertCos(dm_src, vcos_src); + bvhtree_from_mesh_faces(&treedata, dm_src, (mode & MREMAP_USE_NORPROJ) ? ray_radius : 0.0f, 2, 6); + /* bvhtree here uses tesselated faces... */ + tessface_to_poly_map_src = dm_src->getTessFaceDataArray(dm_src, CD_ORIGINDEX); + + if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) { + for (i = 0; i < numverts_dst; i++) { + float tmp_co[3], tmp_no[3]; + + copy_v3_v3(tmp_co, verts_dst[i].co); + normal_short_to_float_v3(tmp_no, verts_dst[i].no); + + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, space_transform, + tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) + { + MPoly *mp_src = &polys_src[tessface_to_poly_map_src[rayhit.index]]; + const int sources_num = mesh_remap_interp_poly_data_get( + mp_src, loops_src, (const float (*)[3])vcos_src, rayhit.co, + &tmp_buff_size, &vcos, false, &indices, &weights, true, NULL); + + mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights); + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else { + nearest.index = -1; + + for (i = 0; i < numverts_dst; i++) { + float tmp_co[3]; + + /* Convert the vertex to tree coordinates. */ + copy_v3_v3(tmp_co, verts_dst[i].co); + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + MPoly *mp = &polys_src[tessface_to_poly_map_src[nearest.index]]; + + if (mode == MREMAP_MODE_VERT_POLY_NEAREST) { + int index; + mesh_remap_interp_poly_data_get( + mp, loops_src, (const float (*)[3])vcos_src, nearest.co, + &tmp_buff_size, &vcos, false, &indices, &weights, false, + &index); + + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight); + } + else if (mode == MREMAP_MODE_VERT_POLYINTERP_NEAREST) { + const int sources_num = mesh_remap_interp_poly_data_get( + mp, loops_src, (const float (*)[3])vcos_src, nearest.co, + &tmp_buff_size, &vcos, false, &indices, &weights, true, + NULL); + + mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights); + } + } + else { + /* No source for this dest vertex! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + + MEM_freeN(vcos_src); + MEM_freeN(vcos); + MEM_freeN(indices); + MEM_freeN(weights); + } + else { + printf("WARNING! Unsupported mesh-to-mesh vertex mapping mode (%d)!\n", mode); + memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numverts_dst); + } + + free_bvhtree_from_mesh(&treedata); + } +} + +void BKE_mesh_remap_calc_edges_from_dm( + const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, + const MVert *verts_dst, const int numverts_dst, const MEdge *edges_dst, const int numedges_dst, + const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src, MeshPairRemap *r_map) +{ + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + int i; + + BLI_assert(mode & MREMAP_MODE_EDGE); + + BKE_mesh_remap_init(r_map, numedges_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + BLI_assert(numedges_dst == dm_src->getNumEdges(dm_src)); + for (i = 0; i < numedges_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh treedata = {NULL}; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + float hit_dist; + + if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) { + const int num_verts_src = dm_src->getNumVerts(dm_src); + const int num_edges_src = dm_src->getNumEdges(dm_src); + MEdge *edges_src = dm_src->getEdgeArray(dm_src); + float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); + + MeshElemMap *vert_to_edge_src_map; + int *vert_to_edge_src_map_mem; + + struct { + float hit_dist; + int index; + } *v_dst_to_src_map = MEM_mallocN(sizeof(*v_dst_to_src_map) * (size_t)numverts_dst, __func__); + + for (i = 0; i < numverts_dst; i++) { + v_dst_to_src_map[i].hit_dist = -1.0f; + } + + BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map, &vert_to_edge_src_map_mem, + edges_src, num_verts_src, num_edges_src); + + dm_src->getVertCos(dm_src, vcos_src); + + bvhtree_from_mesh_verts(&treedata, dm_src, 0.0f, 2, 6); + nearest.index = -1; + + for (i = 0; i < numedges_dst; i++) { + const MEdge *e_dst = &edges_dst[i]; + float best_totdist = FLT_MAX; + int best_eidx_src = -1; + int j = 2; + + while (j--) { + const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2; + + /* Compute closest verts only once! */ + if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) { + float tmp_co[3]; + + copy_v3_v3(tmp_co, verts_dst[vidx_dst].co); + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + v_dst_to_src_map[vidx_dst].hit_dist = hit_dist; + v_dst_to_src_map[vidx_dst].index = nearest.index; + } + else { + /* No source for this dest vert! */ + v_dst_to_src_map[vidx_dst].hit_dist = FLT_MAX; + } + } + } + + /* Now, check all source edges of closest sources vertices, and select the one giving the smallest + * total verts-to-verts distance. */ + for (j = 2; j--;) { + const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2; + const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist; + const int vidx_src = v_dst_to_src_map[vidx_dst].index; + int *eidx_src, k; + + if (vidx_src < 0) { + continue; + } + + eidx_src = vert_to_edge_src_map[vidx_src].indices; + k = vert_to_edge_src_map[vidx_src].count; + + for (; k--; eidx_src++) { + MEdge *e_src = &edges_src[*eidx_src]; + const float *other_co_src = vcos_src[BKE_mesh_edge_other_vert(e_src, vidx_src)]; + const float *other_co_dst = verts_dst[BKE_mesh_edge_other_vert(e_dst, (int)vidx_dst)].co; + const float totdist = first_dist + len_v3v3(other_co_src, other_co_dst); + + if (totdist < best_totdist) { + best_totdist = totdist; + best_eidx_src = *eidx_src; + } + } + } + + if (best_eidx_src >= 0) { + const float *co1_src = vcos_src[edges_src[best_eidx_src].v1]; + const float *co2_src = vcos_src[edges_src[best_eidx_src].v2]; + const float *co1_dst = verts_dst[e_dst->v1].co; + const float *co2_dst = verts_dst[e_dst->v2].co; + float co_src[3], co_dst[3]; + + /* TODO: would need an isect_seg_seg_v3(), actually! */ + const int isect_type = isect_line_line_v3(co1_src, co2_src, co1_dst, co2_dst, co_src, co_dst); + if (isect_type != 0) { + const float fac_src = line_point_factor_v3(co_src, co1_src, co2_src); + const float fac_dst = line_point_factor_v3(co_dst, co1_dst, co2_dst); + if (fac_src < 0.0f) { + copy_v3_v3(co_src, co1_src); + } + else if (fac_src > 1.0f) { + copy_v3_v3(co_src, co2_src); + } + if (fac_dst < 0.0f) { + copy_v3_v3(co_dst, co1_dst); + } + else if (fac_dst > 1.0f) { + copy_v3_v3(co_dst, co2_dst); + } + } + hit_dist = len_v3v3(co_dst, co_src); + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight); + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(vcos_src); + MEM_freeN(v_dst_to_src_map); + MEM_freeN(vert_to_edge_src_map); + MEM_freeN(vert_to_edge_src_map_mem); + } + else if (mode == MREMAP_MODE_EDGE_NEAREST) { + bvhtree_from_mesh_edges(&treedata, dm_src, 0.0f, 2, 6); + nearest.index = -1; + + for (i = 0; i < numedges_dst; i++) { + float tmp_co[3]; + + interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight); + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) { + MEdge *edges_src = dm_src->getEdgeArray(dm_src); + MPoly *polys_src = dm_src->getPolyArray(dm_src); + MLoop *loops_src = dm_src->getLoopArray(dm_src); + float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); + int *tessface_to_poly_map_src; + + dm_src->getVertCos(dm_src, vcos_src); + bvhtree_from_mesh_faces(&treedata, dm_src, 0.0f, 2, 6); + /* bvhtree here uses tesselated faces... */ + tessface_to_poly_map_src = dm_src->getTessFaceDataArray(dm_src, CD_ORIGINDEX); + + for (i = 0; i < numedges_dst; i++) { + float tmp_co[3]; + + interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + MPoly *mp_src = &polys_src[tessface_to_poly_map_src[nearest.index]]; + MLoop *ml_src = &loops_src[mp_src->loopstart]; + int nloops = mp_src->totloop; + float best_dist_sq = FLT_MAX; + int best_eidx_src = -1; + + for (; nloops--; ml_src++) { + MEdge *me_src = &edges_src[ml_src->e]; + float *co1_src = vcos_src[me_src->v1]; + float *co2_src = vcos_src[me_src->v2]; + float co_src[3]; + float dist_sq; + + interp_v3_v3v3(co_src, co1_src, co2_src, 0.5f); + dist_sq = len_squared_v3v3(tmp_co, co_src); + if (dist_sq < best_dist_sq) { + best_dist_sq = dist_sq; + best_eidx_src = (int)ml_src->e; + } + } + if (best_eidx_src >= 0) { + mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight); + } + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(vcos_src); + } + else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) { + const int num_rays_min = 5, num_rays_max = 100; + const int numedges_src = dm_src->getNumEdges(dm_src); + + /* Subtleness - this one we can allocate only max number of cast rays per edges! */ + int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), __func__); + /* Here it's simpler to just allocate for all edges :/ */ + float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__); + + bvhtree_from_mesh_edges(&treedata, dm_src, MREMAP_RAYCAST_APPROXIMATE_BVHEPSILON(ray_radius), 2, 6); + + for (i = 0; i < numedges_dst; i++) { + /* For each dst edge, we sample some rays from it (interpolated from its vertices) + * and use their hits to interpolate from source edges. */ + const MEdge *me = &edges_dst[i]; + float tmp_co[3], v1_co[3], v2_co[3]; + float tmp_no[3], v1_no[3], v2_no[3]; + + int grid_size; + float edge_dst_len; + float grid_step; + + float totweights = 0.0f; + float hit_dist_accum = 0.0f; + int sources_num = 0; + int j; + + copy_v3_v3(v1_co, verts_dst[me->v1].co); + copy_v3_v3(v2_co, verts_dst[me->v2].co); + + normal_short_to_float_v3(v1_no, verts_dst[me->v1].no); + normal_short_to_float_v3(v2_no, verts_dst[me->v2].no); + + /* We do our transform here, allows to interpolate from normals already in src space. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, v1_co); + BLI_space_transform_apply(space_transform, v2_co); + BLI_space_transform_apply_normal(space_transform, v1_no); + BLI_space_transform_apply_normal(space_transform, v2_no); + } + + fill_vn_fl(weights, (int)numedges_src, 0.0f); + + /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), + * with lower/upper bounds. */ + edge_dst_len = len_v3v3(v1_co, v2_co); + + grid_size = (int)((edge_dst_len / ray_radius) + 0.5f); + CLAMP(grid_size, num_rays_min, num_rays_max); /* min 5 rays/edge, max 100. */ + + grid_step = 1.0f / (float)grid_size; /* Not actual distance here, rather an interp fac... */ + + /* And now we can cast all our rays, and see what we get! */ + for (j = 0; j < grid_size; j++) { + const float fac = grid_step * (float)j; + + int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; + float w = 1.0f; + + interp_v3_v3v3(tmp_co, v1_co, v2_co, fac); + interp_v3_v3v3_slerp_safe(tmp_no, v1_no, v2_no, fac); + + while (n--) { + /* Note we handle dest to src space conversion ourself, here! */ + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, NULL, + tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) + { + weights[rayhit.index] += w; + totweights += w; + hit_dist_accum += hit_dist; + break; + } + /* Next iteration will get bigger radius but smaller weight! */ + w /= MREMAP_RAYCAST_APPROXIMATE_FAC; + } + } + /* A sampling is valid (as in, its result can be considered as valid sources) only if at least + * half of the rays found a source! */ + if (totweights > ((float)grid_size / 2.0f)) { + for (j = 0; j < (int)numedges_src; j++) { + if (!weights[j]) { + continue; + } + /* Note: sources_num is always <= j! */ + weights[sources_num] = weights[j] / totweights; + indices[sources_num] = j; + sources_num++; + } + mesh_remap_item_define(r_map, i, hit_dist_accum / totweights, 0, + sources_num, indices, weights); + } + else { + /* No source for this dest edge! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(indices); + MEM_freeN(weights); + } + else { + printf("WARNING! Unsupported mesh-to-mesh edge mapping mode (%d)!\n", mode); + memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numedges_dst); + } + + free_bvhtree_from_mesh(&treedata); + } +} + +#define POLY_UNSET 0 +#define POLY_CENTER_INIT 1 +#define POLY_COMPLETE 2 + +static void mesh_island_to_astar_graph_edge_process( + MeshIslandStore *islands, const int island_index, BLI_AStarGraph *as_graph, + MVert *verts, MPoly *polys, MLoop *loops, + const int edge_idx, BLI_bitmap *done_edges, MeshElemMap *edge_to_poly_map, const bool is_edge_innercut, + int *poly_island_index_map, float (*poly_centers)[3], unsigned char *poly_status) +{ + int *poly_island_indices = BLI_array_alloca(poly_island_indices, (size_t)edge_to_poly_map[edge_idx].count); + int i, j; + + for (i = 0; i < edge_to_poly_map[edge_idx].count; i++) { + const int pidx = edge_to_poly_map[edge_idx].indices[i]; + MPoly *mp = &polys[pidx]; + const int pidx_isld = islands ? poly_island_index_map[pidx] : pidx; + void *custom_data = is_edge_innercut ? SET_INT_IN_POINTER(edge_idx) : SET_INT_IN_POINTER(-1); + + if (UNLIKELY(islands && (islands->items_to_islands[mp->loopstart] != island_index))) { + /* poly not in current island, happens with border edges... */ + poly_island_indices[i] = -1; + continue; + } + + if (poly_status[pidx_isld] == POLY_COMPLETE) { + poly_island_indices[i] = pidx_isld; + continue; + } + + if (poly_status[pidx_isld] == POLY_UNSET) { + BKE_mesh_calc_poly_center(mp, &loops[mp->loopstart], verts, poly_centers[pidx_isld]); + BLI_astar_node_init(as_graph, pidx_isld, poly_centers[pidx_isld]); + poly_status[pidx_isld] = POLY_CENTER_INIT; + } + + for (j = i; j--;) { + float dist_cost; + const int pidx_isld_other = poly_island_indices[j]; + + if (pidx_isld_other == -1 || poly_status[pidx_isld_other] == POLY_COMPLETE) { + /* If the other poly is complete, that link has already been added! */ + continue; + } + dist_cost = len_v3v3(poly_centers[pidx_isld_other], poly_centers[pidx_isld]); + BLI_astar_node_link_add(as_graph, pidx_isld_other, pidx_isld, dist_cost, custom_data); + } + + poly_island_indices[i] = pidx_isld; + } + + BLI_BITMAP_ENABLE(done_edges, edge_idx); +} + +static void mesh_island_to_astar_graph( + MeshIslandStore *islands, const int island_index, + MVert *verts, MeshElemMap *edge_to_poly_map, const int numedges, MLoop *loops, MPoly *polys, const int numpolys, + BLI_AStarGraph *r_as_graph) +{ + MeshElemMap *island_poly_map = islands ? islands->islands[island_index] : NULL; + MeshElemMap *island_einnercut_map = islands ? islands->innercuts[island_index] : NULL; + + int *poly_island_index_map = NULL; + BLI_bitmap *done_edges = BLI_BITMAP_NEW(numedges, __func__); + + const int node_num = islands ? island_poly_map->count : numpolys; + unsigned char *poly_status = MEM_callocN(sizeof(*poly_status) * (size_t)node_num, __func__); + float (*poly_centers)[3]; + + int pidx_isld; + int i; + + BLI_astar_graph_init(r_as_graph, node_num, NULL); + /* poly_centers is owned by graph memarena. */ + poly_centers = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_centers) * (size_t)node_num); + + if (islands) { + /* poly_island_index_map is owned by graph memarena. */ + poly_island_index_map = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_island_index_map) * (size_t)numpolys); + for (i = island_poly_map->count; i--;) { + poly_island_index_map[island_poly_map->indices[i]] = i; + } + + r_as_graph->custom_data = poly_island_index_map; + + for (i = island_einnercut_map->count; i--;) { + mesh_island_to_astar_graph_edge_process( + islands, island_index, r_as_graph, verts, polys, loops, + island_einnercut_map->indices[i], done_edges, edge_to_poly_map, true, + poly_island_index_map, poly_centers, poly_status); + } + } + + for (pidx_isld = node_num; pidx_isld--;) { + const int pidx = islands ? island_poly_map->indices[pidx_isld] : pidx_isld; + MPoly *mp = &polys[pidx]; + int pl_idx, l_idx; + + if (poly_status[pidx_isld] == POLY_COMPLETE) { + continue; + } + + for (pl_idx = 0, l_idx = mp->loopstart; pl_idx < mp->totloop; pl_idx++, l_idx++) { + MLoop *ml = &loops[l_idx]; + + if (BLI_BITMAP_TEST(done_edges, ml->e)) { + continue; + } + + mesh_island_to_astar_graph_edge_process( + islands, island_index, r_as_graph, verts, polys, loops, + (int)ml->e, done_edges, edge_to_poly_map, false, + poly_island_index_map, poly_centers, poly_status); + } + poly_status[pidx_isld] = POLY_COMPLETE; + } + + MEM_freeN(done_edges); + MEM_freeN(poly_status); +} + +#undef POLY_UNSET +#undef POLY_CENTER_INIT +#undef POLY_COMPLETE + +/* Our 'f_cost' callback func, to find shortest poly-path between two remapped-loops. + * Note we do not want to make innercuts 'walls' here, just detect when the shortest path goes by those. */ +static float mesh_remap_calc_loops_astar_f_cost( + BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link, + const int node_idx_curr, const int node_idx_next, const int node_idx_dst) +{ + float *co_next, *co_dest; + + if (link && (GET_INT_FROM_POINTER(link->custom_data) != -1)) { + /* An innercut edge... We tag our solution as potentially crossing innercuts. + * Note it might not be the case in the end (AStar will explore around optimal path), but helps + * trimming off some processing later... */ + if (!GET_INT_FROM_POINTER(as_solution->custom_data)) { + as_solution->custom_data = SET_INT_IN_POINTER(true); + } + } + + /* Our heuristic part of current f_cost is distance from next node to destination one. + * It is guaranteed to be less than (or equal to) actual shortest poly-path between next node and destination one. + */ + co_next = (float *)as_graph->nodes[node_idx_next].custom_data; + co_dest = (float *)as_graph->nodes[node_idx_dst].custom_data; + return (link ? (as_solution->g_costs[node_idx_curr] + link->cost) : 0.0f) + len_v3v3(co_next, co_dest); +} + +#define ASTAR_STEPS_MAX 64 + + +void BKE_mesh_remap_calc_loops_from_dm( + const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, + MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst, + MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst, + CustomData *ldata_dst, CustomData *pdata_dst, const float split_angle_dst, const bool dirty_nors_dst, + DerivedMesh *dm_src, + MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map) +{ + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + + int i; + + BLI_assert(mode & MREMAP_MODE_LOOP); + BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f)); + + BKE_mesh_remap_init(r_map, numloops_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + /* In topology mapping, we assume meshes are identical, islands included! */ + BLI_assert(numloops_dst == dm_src->getNumLoops(dm_src)); + for (i = 0; i < numloops_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh *treedata = NULL; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + int num_trees = 0; + float hit_dist; + + const bool use_from_vert = (mode & MREMAP_USE_VERT); + + MeshIslandStore island_store = {0}; + bool use_islands = false; + + BLI_AStarGraph *as_graphdata = NULL; + BLI_AStarSolution as_solution = {0}; + const int isld_steps_src = islands_precision_src ? + max_ii((int)(ASTAR_STEPS_MAX * islands_precision_src + 0.499f), 1) : 0; + + float (*poly_nors_src)[3] = NULL; + float (*loop_nors_src)[3] = NULL; + float (*poly_nors_dst)[3] = NULL; + float (*loop_nors_dst)[3] = NULL; + + MeshElemMap *vert_to_loop_map_src = NULL; + int *vert_to_loop_map_src_buff = NULL; + MeshElemMap *vert_to_poly_map_src = NULL; + int *vert_to_poly_map_src_buff = NULL; + MeshElemMap *edge_to_poly_map_src = NULL; + int *edge_to_poly_map_src_buff = NULL; + MeshElemMap *poly_to_tessface_map_src = NULL; + int *poly_to_tessface_map_src_buff = NULL; + + /* Unlike above, those are one-to-one mappings, simpler! */ + int *loop_to_poly_map_src = NULL; + int *tessface_to_poly_map_src = NULL; + + bool verts_allocated_src; + MVert *verts_src = DM_get_vert_array(dm_src, &verts_allocated_src); + const int num_verts_src = dm_src->getNumVerts(dm_src); + float (*vcos_src)[3] = NULL; + bool edges_allocated_src; + MEdge *edges_src = DM_get_edge_array(dm_src, &edges_allocated_src); + const int num_edges_src = dm_src->getNumEdges(dm_src); + bool loops_allocated_src; + MLoop *loops_src = DM_get_loop_array(dm_src, &loops_allocated_src); + const int num_loops_src = dm_src->getNumLoops(dm_src); + bool polys_allocated_src; + MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src); + const int num_polys_src = dm_src->getNumPolys(dm_src); + bool faces_allocated_src = false; + MFace *faces_src = NULL; + int num_faces_src = 0; + + size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE; + float (*vcos_interp)[3] = NULL; + int *indices_interp = NULL; + float *weights_interp = NULL; + + int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src; + + IslandResult **islands_res; + size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE; + + const float bvh_epsilon = (mode & MREMAP_USE_NORPROJ) ? MREMAP_RAYCAST_APPROXIMATE_BVHEPSILON(ray_radius) : 0.0f; + + if (!use_from_vert) { + vcos_src = MEM_mallocN(sizeof(*vcos_src) * (size_t)num_verts_src, __func__); + dm_src->getVertCos(dm_src, vcos_src); + + vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__); + indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__); + weights_interp = MEM_mallocN(sizeof(*weights_interp) * buff_size_interp, __func__); + } + + { + const bool need_lnors_src = (mode & MREMAP_USE_LOOP) && (mode & MREMAP_USE_NORMAL); + const bool need_lnors_dst = need_lnors_src || (mode & MREMAP_USE_NORPROJ); + const bool need_pnors_src = need_lnors_src || ((mode & MREMAP_USE_POLY) && (mode & MREMAP_USE_NORMAL)); + const bool need_pnors_dst = need_lnors_dst || need_pnors_src; + + if (need_pnors_dst) { + /* Cache poly nors into a temp CDLayer. */ + poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); + if (!poly_nors_dst) { + poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst); + CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst) { + BKE_mesh_calc_normals_poly(verts_dst, numverts_dst, loops_dst, polys_dst, + numloops_dst, numpolys_dst, poly_nors_dst, true); + } + } + if (need_lnors_dst) { + /* Cache poly nors into a temp CDLayer. */ + loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); + if (!loop_nors_dst) { + loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); + CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst) { + BKE_mesh_normals_loop_split(verts_dst, numverts_dst, edges_dst, numedges_dst, + loops_dst, loop_nors_dst, numloops_dst, + polys_dst, poly_nors_dst, numpolys_dst, split_angle_dst); + } + } + if (need_pnors_src || need_lnors_src) { + /* Simpler for now, calcNormals never stores pnors :( */ + dm_src->calcLoopNormals(dm_src, /* TODO */ (float)M_PI); + + if (need_pnors_src) { + poly_nors_src = dm_src->getPolyDataArray(dm_src, CD_NORMAL); + } + if (need_lnors_src) { + loop_nors_src = dm_src->getLoopDataArray(dm_src, CD_NORMAL); + } + } + } + + if (use_from_vert) { + BKE_mesh_vert_loop_map_create(&vert_to_loop_map_src, &vert_to_loop_map_src_buff, + polys_src, loops_src, num_verts_src, num_polys_src, num_loops_src); + if (mode & MREMAP_USE_POLY) { + BKE_mesh_vert_poly_map_create(&vert_to_poly_map_src, &vert_to_poly_map_src_buff, + polys_src, loops_src, num_verts_src, num_polys_src, num_loops_src); + } + } + + /* Needed for islands (or plain mesh) to AStar graph conversion. */ + BKE_mesh_edge_poly_map_create(&edge_to_poly_map_src, &edge_to_poly_map_src_buff, + edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src); + if (use_from_vert) { + loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__); + for (pidx_src = 0; pidx_src < num_polys_src; pidx_src++) { + MPoly *mp = &polys_src[pidx_src]; + for (plidx_src = 0, lidx_src = mp->loopstart; plidx_src < mp->totloop; plidx_src++, lidx_src++) { + loop_to_poly_map_src[lidx_src] = pidx_src; + } + } + } + + /* Island makes things slightly more complex here. + * Basically, we: + * * Make one treedata for each island's elements. + * * Check all loops of a same dest poly against all treedata. + * * Choose the island's elements giving the best results. + */ + + /* First, generate the islands, if possible. */ + if (gen_islands_src) { + use_islands = gen_islands_src( + verts_src, num_verts_src, + edges_src, num_edges_src, + polys_src, num_polys_src, + loops_src, num_loops_src, + &island_store); + + num_trees = use_islands ? island_store.islands_num : 1; + treedata = MEM_callocN(sizeof(*treedata) * (size_t)num_trees, __func__); + if (isld_steps_src) { + as_graphdata = MEM_callocN(sizeof(*as_graphdata) * (size_t)num_trees, __func__); + } + + if (use_islands) { + /* We expect our islands to contain poly indices, with edge indices of 'inner cuts', + * and a mapping loops -> islands indices. + * This implies all loops of a same poly are in the same island. */ + BLI_assert((island_store.item_type == MISLAND_TYPE_LOOP) && + (island_store.island_type == MISLAND_TYPE_POLY) && + (island_store.innercut_type == MISLAND_TYPE_EDGE)); + } + } + else { + num_trees = 1; + treedata = MEM_callocN(sizeof(*treedata), __func__); + if (isld_steps_src) { + as_graphdata = MEM_callocN(sizeof(*as_graphdata), __func__); + } + } + + /* Build our AStar graphs. */ + if (isld_steps_src) { + for (tindex = 0; tindex < num_trees; tindex++) { + mesh_island_to_astar_graph( + use_islands ? &island_store : NULL, tindex, verts_src, edge_to_poly_map_src, num_edges_src, + loops_src, polys_src, num_polys_src, &as_graphdata[tindex]); + } + } + + /* Build our BVHtrees, either from verts or tessfaces. */ + if (use_from_vert) { + if (use_islands) { + BLI_bitmap *verts_active = BLI_BITMAP_NEW((size_t)num_verts_src, __func__); + + for (tindex = 0; tindex < num_trees; tindex++) { + MeshElemMap *isld = island_store.islands[tindex]; + int num_verts_active = 0; + BLI_BITMAP_SET_ALL(verts_active, false, (size_t)num_verts_src); + for (i = 0; i < isld->count; i++) { + MPoly *mp_src = &polys_src[isld->indices[i]]; + for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) { + BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); + num_verts_active++; + } + } + /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ + bvhtree_from_mesh_verts_ex(&treedata[tindex], verts_src, num_verts_src, verts_allocated_src, + verts_active, num_verts_active, bvh_epsilon, 2, 6); + if (verts_allocated_src) { + verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */ + } + } + + MEM_freeN(verts_active); + } + else { + BLI_assert(num_trees == 1); + bvhtree_from_mesh_verts(&treedata[0], dm_src, bvh_epsilon, 2, 6); + } + } + else { /* We use polygons. */ + if (use_islands) { + /* bvhtree here uses tesselated faces... */ + const unsigned int dirty_tess_flag = dm_src->dirty & DM_DIRTY_TESS_CDLAYERS; + BLI_bitmap *faces_active; + + /* We do not care about tessellated data here, only geometry itself is important. */ + if (dirty_tess_flag) { + dm_src->dirty &= ~dirty_tess_flag; + } + DM_ensure_tessface(dm_src); + if (dirty_tess_flag) { + dm_src->dirty |= dirty_tess_flag; + } + faces_src = DM_get_tessface_array(dm_src, &faces_allocated_src); + num_faces_src = dm_src->getNumTessFaces(dm_src); + tessface_to_poly_map_src = dm_src->getTessFaceDataArray(dm_src, CD_ORIGINDEX); + faces_active = BLI_BITMAP_NEW((size_t)num_faces_src, __func__); + + for (tindex = 0; tindex < num_trees; tindex++) { + int num_faces_active = 0; + BLI_BITMAP_SET_ALL(faces_active, false, (size_t)num_faces_src); + for (i = 0; i < num_faces_src; i++) { + MPoly *mp_src = &polys_src[tessface_to_poly_map_src[i]]; + if (island_store.items_to_islands[mp_src->loopstart] == tindex) { + BLI_BITMAP_ENABLE(faces_active, i); + num_faces_active++; + } + } + /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ + bvhtree_from_mesh_faces_ex( + &treedata[tindex], verts_src, verts_allocated_src, + faces_src, num_faces_src, faces_allocated_src, + faces_active, num_faces_active, bvh_epsilon, 2, 6); + if (verts_allocated_src) { + verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */ + } + if (faces_allocated_src) { + faces_allocated_src = false; /* Only 'give' our faces once, to first tree! */ + } + } + + MEM_freeN(faces_active); + } + else { + BLI_assert(num_trees == 1); + bvhtree_from_mesh_faces(&treedata[0], dm_src, bvh_epsilon, 2, 6); + tessface_to_poly_map_src = dm_src->getTessFaceDataArray(dm_src, CD_ORIGINDEX); + } + } + + /* And check each dest poly! */ + islands_res = MEM_mallocN(sizeof(*islands_res) * (size_t)num_trees, __func__); + for (tindex = 0; tindex < num_trees; tindex++) { + islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__); + } + + for (pidx_dst = 0; pidx_dst < numpolys_dst; pidx_dst++) { + MPoly *mp_dst = &polys_dst[pidx_dst]; + float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst]; + + if ((size_t)mp_dst->totloop > islands_res_buff_size) { + islands_res_buff_size = (size_t)mp_dst->totloop; + for (tindex = 0; tindex < num_trees; tindex++) { + islands_res[tindex] = MEM_reallocN(islands_res[tindex], sizeof(**islands_res) * islands_res_buff_size); + } + } + + for (tindex = 0; tindex < num_trees; tindex++) { + BVHTreeFromMesh *tdata = &treedata[tindex]; + MLoop *ml_dst = &loops_dst[mp_dst->loopstart]; + + for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) { + if (use_from_vert) { + float tmp_co[3]; + MeshElemMap *vert_to_refelem_map_src = NULL; + + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + nearest.index = -1; + + if (mesh_remap_bvhtree_query_nearest( + tdata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + float (*nor_dst)[3]; + float (*nors_src)[3]; + float best_nor_dot = -2.0f; + int best_index_src = -1; + + if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { + nor_dst = &loop_nors_dst[plidx_dst + mp_dst->loopstart]; + nors_src = loop_nors_src; + vert_to_refelem_map_src = vert_to_loop_map_src; + } + else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */ + nor_dst = pnor_dst; + nors_src = poly_nors_src; + vert_to_refelem_map_src = vert_to_poly_map_src; + } + + for (i = vert_to_refelem_map_src[nearest.index].count; i--;) { + const int index_src = vert_to_refelem_map_src[nearest.index].indices[i]; + const float dot = dot_v3v3(nors_src[index_src], *nor_dst); + if (dot > best_nor_dot) { + best_nor_dot = dot; + best_index_src = index_src; + } + } + if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { + /* Our best_index_src is a poly one for now! + * Have to find its loop matching our closest vertex. */ + MPoly *mp_src = &polys_src[best_index_src]; + MLoop *ml_src = &loops_src[mp_src->loopstart]; + for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) { + if ((int)ml_src->v == nearest.index) { + best_index_src = plidx_src + mp_src->loopstart; + break; + } + } + } + islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / (hit_dist * best_nor_dot)) : 1e18f; + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = best_index_src; + } + else { + /* No source for this dest loop! */ + islands_res[tindex][plidx_dst].factor = 0.0f; + islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; + islands_res[tindex][plidx_dst].index_src = -1; + } + } + else if (mode & MREMAP_USE_NORPROJ) { + float tmp_co[3], tmp_no[3]; + + int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; + float w = 1.0f; + + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); + + /* We do our transform here, since we may do several raycast/nearest queries. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + BLI_space_transform_apply_normal(space_transform, tmp_no); + } + + while (n--) { + /* Note we handle dest to src space conversion ourself, here! */ + if (mesh_remap_bvhtree_query_raycast( + tdata, &rayhit, NULL, + tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) + { + islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w; + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = tessface_to_poly_map_src[rayhit.index]; + copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co); + break; + } + /* Next iteration will get bigger radius but smaller weight! */ + w /= MREMAP_RAYCAST_APPROXIMATE_FAC; + } + if (n == -1) { + /* Fallback to 'nearest' hit here, loops usually comes in 'face group', not good to + * have only part of one dest face's loops to map to source. + * Note that since we give this a null weight, if whole weight for a given face + * is null, it means none of its loop mapped to this source island, hence we can skip it + * later. + */ + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + nearest.index = -1; + + /* In any case, this fallback nearest hit should have no weight at all + * in 'best island' decision! */ + islands_res[tindex][plidx_dst].factor = 0.0f; + + /* Note we handle dest to src space conversion ourself, here! */ + if (mesh_remap_bvhtree_query_nearest( + tdata, &nearest, NULL, + tmp_co, max_dist_sq, &hit_dist)) + { + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = tessface_to_poly_map_src[nearest.index]; + copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co); + } + else { + /* No source for this dest loop! */ + islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; + islands_res[tindex][plidx_dst].index_src = -1; + } + } + } + else { /* Nearest poly either to use all its loops/verts or just closest one. */ + float tmp_co[3]; + + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + nearest.index = -1; + + if (mesh_remap_bvhtree_query_nearest( + tdata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f; + islands_res[tindex][plidx_dst].hit_dist = hit_dist; + islands_res[tindex][plidx_dst].index_src = tessface_to_poly_map_src[nearest.index]; + copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co); + } + else { + /* No source for this dest loop! */ + islands_res[tindex][plidx_dst].factor = 0.0f; + islands_res[tindex][plidx_dst].hit_dist = FLT_MAX; + islands_res[tindex][plidx_dst].index_src = -1; + } + } + } + } + + /* And now, find best island to use! */ + /* We have to first select the 'best source island' for given dst poly and its loops. + * Then, we have to check that poly does not 'spread' across some island's limits + * (like inner seams for UVs, etc.). + * Note we only still partially support that kind of situation here, i.e. polys spreading over actual cracks + * (like a narrow space without faces on src, splitting a 'tube-like' geometry). That kind of situation + * should be relatively rare, though. + */ + /* XXX This block in itself is big and complex enough to be a separate function but... it uses a bunch + * of locale vars. Not worth sending all that through parameters (for now at least). */ + { + BLI_AStarGraph *as_graph = NULL; + int *poly_island_index_map = NULL; + int pidx_src_prev = -1; + + MeshElemMap *best_island = NULL; + float best_island_fac = 0.0f; + int best_island_index = -1; + + for (tindex = 0; tindex < num_trees; tindex++) { + float island_fac = 0.0f; + + for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) { + island_fac += islands_res[tindex][plidx_dst].factor; + } + island_fac /= (float)mp_dst->totloop; + + if (island_fac > best_island_fac) { + best_island_fac = island_fac; + best_island_index = tindex; + } + } + + if (best_island_index != -1 && isld_steps_src) { + best_island = use_islands ? island_store.islands[best_island_index] : NULL; + as_graph = &as_graphdata[best_island_index]; + poly_island_index_map = (int *)as_graph->custom_data; + BLI_astar_solution_init(as_graph, &as_solution, false); + } + + for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) { + IslandResult *isld_res; + lidx_dst = plidx_dst + mp_dst->loopstart; + + if (best_island_index == -1) { + /* No source for any loops of our dest poly in any source islands. */ + BKE_mesh_remap_item_define_invalid(r_map, lidx_dst); + continue; + } + + as_solution.custom_data = SET_INT_IN_POINTER(false); + + isld_res = &islands_res[best_island_index][plidx_dst]; + if (use_from_vert) { + /* Indices stored in islands_res are those of loops, one per dest loop. */ + lidx_src = isld_res->index_src; + if (lidx_src >= 0) { + pidx_src = loop_to_poly_map_src[lidx_src]; + /* If prev and curr poly are the same, no need to do anything more!!! */ + if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { + BLI_astar_graph_solve( + as_graph, poly_island_index_map[pidx_src_prev], poly_island_index_map[pidx_src], + mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src); + if (GET_INT_FROM_POINTER(as_solution.custom_data) && (as_solution.steps > 0)) { + /* Find first 'cutting edge' on path, and bring back lidx_src on poly just + * before that edge. + * Note we could try to be much smarter (like e.g. storing a whole poly's indices, + * and making decision (on which side of cutting edge(s!) to be) on the end, + * but this is one more level of complexity, better to first see if + * simple solution works! + */ + int pidx_isld_src = poly_island_index_map[pidx_src]; + int last_valid_pidx_isld_src = -1; + /* Note we go backward here, from dest to src poly. */ + for (i = as_solution.steps - 1; i--;) { + BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src]; + const int eidx = GET_INT_FROM_POINTER(as_link->custom_data); + pidx_isld_src = as_solution.prev_nodes[pidx_isld_src]; + BLI_assert(pidx_isld_src != -1); + if (eidx != -1) { + /* we are 'crossing' a cutting edge. */ + last_valid_pidx_isld_src = pidx_isld_src; + } + } + if (last_valid_pidx_isld_src != -1) { + /* Find a new valid loop in that new poly (nearest one for now). + * Note we could be much more subtle here, again that's for later... */ + MPoly *mp_src; + MLoop *ml_src, *ml_dst = &loops_dst[lidx_dst]; + int j; + float best_dist_sq = FLT_MAX; + float tmp_co[3]; + + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + + /* We do our transform here, since we may do several raycast/nearest queries. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + pidx_src = use_islands ? best_island->indices[last_valid_pidx_isld_src] : + last_valid_pidx_isld_src; + mp_src = &polys_src[pidx_src]; + ml_src = &loops_src[mp_src->loopstart]; + for (j = 0; j < mp_src->totloop; j++, ml_src++) { + const float dist_sq = len_squared_v3v3(verts_src[ml_src->v].co, tmp_co); + if (dist_sq < best_dist_sq) { + best_dist_sq = dist_sq; + lidx_src = mp_src->loopstart + j; + } + } + } + } + } + mesh_remap_item_define( + r_map, lidx_dst, isld_res->hit_dist, + best_island_index, 1, &lidx_src, &full_weight); + pidx_src_prev = pidx_src; + } + else { + /* No source for this loop in this island. */ + /* TODO: would probably be better to get a source at all cost in best island anyway? */ + mesh_remap_item_define( + r_map, lidx_dst, FLT_MAX, + best_island_index, 0, NULL, NULL); + } + } + else { + /* Else, we use source poly, indices stored in islands_res are those of polygons. */ + pidx_src = isld_res->index_src; + if (pidx_src >= 0) { + MPoly *mp_src = &polys_src[pidx_src]; + float *hit_co = isld_res->hit_point; + int best_loop_index_src; + + /* If prev and curr poly are the same, no need to do anything more!!! */ + if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { + BLI_astar_graph_solve( + as_graph, poly_island_index_map[pidx_src_prev], poly_island_index_map[pidx_src], + mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src); + if (GET_INT_FROM_POINTER(as_solution.custom_data) && (as_solution.steps > 0)) { + /* Find first 'cutting edge' on path, and bring back lidx_src on poly just + * before that edge. + * Note we could try to be much smarter (like e.g. storing a whole poly's indices, + * and making decision (one which side of cutting edge(s!) to be on the end, + * but this is one more level of complexity, better to first see if + * simple solution works! + */ + int pidx_isld_src = poly_island_index_map[pidx_src]; + int last_valid_pidx_isld_src = -1; + /* Note we go backward here, from dest to src poly. */ + for (i = as_solution.steps - 1; i--;) { + BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src]; + int eidx = GET_INT_FROM_POINTER(as_link->custom_data); + + pidx_isld_src = as_solution.prev_nodes[pidx_isld_src]; + BLI_assert(pidx_isld_src != -1); + if (eidx != -1) { + /* we are 'crossing' a cutting edge. */ + last_valid_pidx_isld_src = pidx_isld_src; + } + } + if (last_valid_pidx_isld_src != -1) { + /* Find a new valid loop in that new poly (nearest point on poly for now). + * Note we could be much more subtle here, again that's for later... */ + MLoop *ml_dst = &loops_dst[lidx_dst]; + float best_dist_sq = FLT_MAX; + float tmp_co[3]; + int j; + + copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); + + /* We do our transform here, since we may do several raycast/nearest queries. */ + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + + pidx_src = use_islands ? best_island->indices[last_valid_pidx_isld_src] : + last_valid_pidx_isld_src; + mp_src = &polys_src[pidx_src]; + + /* Create that one on demand. */ + if (poly_to_tessface_map_src == NULL) { + BKE_mesh_origindex_map_create( + &poly_to_tessface_map_src, &poly_to_tessface_map_src_buff, + num_faces_src, tessface_to_poly_map_src, num_polys_src); + } + + for (j = poly_to_tessface_map_src[pidx_src].count; j--;) { + float h[3]; + MFace *mf = &faces_src[poly_to_tessface_map_src[pidx_src].indices[j]]; + float dist_sq; + + closest_on_tri_to_point_v3( + h, tmp_co, + vcos_src[mf->v1], vcos_src[mf->v2], vcos_src[mf->v3]); + dist_sq = len_squared_v3v3(tmp_co, h); + if (dist_sq < best_dist_sq) { + copy_v3_v3(hit_co, h); + best_dist_sq = dist_sq; + } + if (mf->v4) { + closest_on_tri_to_point_v3( + h, tmp_co, + vcos_src[mf->v1], vcos_src[mf->v3], vcos_src[mf->v4]); + dist_sq = len_squared_v3v3(tmp_co, h); + if (dist_sq < best_dist_sq) { + copy_v3_v3(hit_co, h); + best_dist_sq = dist_sq; + } + } + } + } + } + } + + if (mode == MREMAP_MODE_LOOP_POLY_NEAREST) { + mesh_remap_interp_poly_data_get( + mp_src, loops_src, (const float (*)[3])vcos_src, hit_co, + &buff_size_interp, &vcos_interp, true, &indices_interp, + &weights_interp, false, &best_loop_index_src); + + mesh_remap_item_define( + r_map, lidx_dst, isld_res->hit_dist, + best_island_index, 1, &best_loop_index_src, &full_weight); + } + else { + const int sources_num = mesh_remap_interp_poly_data_get( + mp_src, loops_src, (const float (*)[3])vcos_src, hit_co, + &buff_size_interp, &vcos_interp, true, &indices_interp, + &weights_interp, true, NULL); + + mesh_remap_item_define( + r_map, lidx_dst, + isld_res->hit_dist, best_island_index, + sources_num, indices_interp, weights_interp); + } + + pidx_src_prev = pidx_src; + } + else { + /* No source for this loop in this island. */ + /* TODO: would probably be better to get a source at all cost in best island anyway? */ + mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL); + } + } + } + + BLI_astar_solution_clear(&as_solution); + } + } + + for (tindex = 0; tindex < num_trees; tindex++) { + MEM_freeN(islands_res[tindex]); + free_bvhtree_from_mesh(&treedata[tindex]); + if (isld_steps_src) { + BLI_astar_graph_free(&as_graphdata[tindex]); + } + } + MEM_freeN(islands_res); + BKE_mesh_loop_islands_free(&island_store); + MEM_freeN(treedata); + if (isld_steps_src) { + MEM_freeN(as_graphdata); + BLI_astar_solution_free(&as_solution); + } + + if (verts_allocated_src) { + MEM_freeN(verts_src); + } + if (vcos_src) { + MEM_freeN(vcos_src); + } + if (edges_allocated_src) { + MEM_freeN(edges_src); + } + if (loops_allocated_src) { + MEM_freeN(loops_src); + } + if (polys_allocated_src) { + MEM_freeN(polys_src); + } + if (faces_allocated_src) { + MEM_freeN(faces_src); + } + if (vert_to_loop_map_src_buff) { + MEM_freeN(vert_to_loop_map_src_buff); + } + if (vert_to_poly_map_src_buff) { + MEM_freeN(vert_to_poly_map_src_buff); + } + if (edge_to_poly_map_src_buff) { + MEM_freeN(edge_to_poly_map_src_buff); + } + if (poly_to_tessface_map_src_buff) { + MEM_freeN(poly_to_tessface_map_src_buff); + } + if (loop_to_poly_map_src) { + MEM_freeN(loop_to_poly_map_src); + } + if (vcos_interp) { + MEM_freeN(vcos_interp); + } + if (indices_interp) { + MEM_freeN(indices_interp); + } + if (weights_interp) { + MEM_freeN(weights_interp); + } + } +} + +void BKE_mesh_remap_calc_polys_from_dm( + const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, + MVert *verts_dst, const int numverts_dst, MLoop *loops_dst, const int numloops_dst, + MPoly *polys_dst, const int numpolys_dst, CustomData *pdata_dst, const bool dirty_nors_dst, + DerivedMesh *dm_src, MeshPairRemap *r_map) +{ + const float full_weight = 1.0f; + const float max_dist_sq = max_dist * max_dist; + float (*poly_nors_dst)[3] = NULL; + int i; + + BLI_assert(mode & MREMAP_MODE_POLY); + + if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) { + /* Cache poly nors into a temp CDLayer. */ + poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); + if (!poly_nors_dst) { + poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst); + CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst) { + BKE_mesh_calc_normals_poly(verts_dst, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst, + poly_nors_dst, true); + } + } + + BKE_mesh_remap_init(r_map, numpolys_dst); + + if (mode == MREMAP_MODE_TOPOLOGY) { + BLI_assert(numpolys_dst == dm_src->getNumPolys(dm_src)); + for (i = 0; i < numpolys_dst; i++) { + mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); + } + } + else { + BVHTreeFromMesh treedata = {NULL}; + BVHTreeNearest nearest = {0}; + BVHTreeRayHit rayhit = {0}; + float hit_dist; + + int *tessface_to_poly_map_src; + + bvhtree_from_mesh_faces( + &treedata, dm_src, + (mode & MREMAP_USE_NORPROJ) ? MREMAP_RAYCAST_APPROXIMATE_BVHEPSILON(ray_radius) : 0.0f, + 2, 6); + /* bvhtree here uses tesselated faces... */ + tessface_to_poly_map_src = dm_src->getTessFaceDataArray(dm_src, CD_ORIGINDEX); + + if (mode == MREMAP_MODE_POLY_NEAREST) { + nearest.index = -1; + + for (i = 0; i < numpolys_dst; i++) { + MPoly *mp = &polys_dst[i]; + float tmp_co[3]; + + BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); + + if (mesh_remap_bvhtree_query_nearest( + &treedata, &nearest, space_transform, + tmp_co, max_dist_sq, &hit_dist)) + { + mesh_remap_item_define( + r_map, i, hit_dist, 0, + 1, &tessface_to_poly_map_src[nearest.index], &full_weight); + } + else { + /* No source for this dest poly! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (mode == MREMAP_MODE_POLY_NOR) { + BLI_assert(poly_nors_dst); + + for (i = 0; i < numpolys_dst; i++) { + MPoly *mp = &polys_dst[i]; + float tmp_co[3], tmp_no[3]; + + BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co); + copy_v3_v3(tmp_no, poly_nors_dst[i]); + + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, space_transform, + tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) + { + mesh_remap_item_define( + r_map, i, hit_dist, 0, + 1, &tessface_to_poly_map_src[rayhit.index], &full_weight); + } + else { + /* No source for this dest poly! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + } + else if (mode == MREMAP_MODE_POLY_POLYINTERP_PNORPROJ) { + /* We cast our rays randomly, with a pseudo-even distribution (since we spread across tessellated tris, + * with additional weighting based on each tri's relative area). + */ + RNG *rng = BLI_rng_new(0); + + const size_t numpolys_src = (size_t)dm_src->getNumPolys(dm_src); + + /* Here it's simpler to just allocate for all polys :/ */ + int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__); + float *weights = MEM_mallocN(sizeof(*weights) * numpolys_src, __func__); + + size_t tmp_poly_size = MREMAP_DEFAULT_BUFSIZE; + float (*poly_vcos_2d)[2] = MEM_mallocN(sizeof(*poly_vcos_2d) * tmp_poly_size, __func__); + /* Tessellated 2D poly, always (num_loops - 2) triangles. */ + int (*tri_vidx_2d)[3] = MEM_mallocN(sizeof(*tri_vidx_2d) * (tmp_poly_size - 2), __func__); + + for (i = 0; i < numpolys_dst; i++) { + /* For each dst poly, we sample some rays from it (2D grid in pnor space) + * and use their hits to interpolate from source polys. */ + /* Note: dst poly is early-converted into src space! */ + MPoly *mp = &polys_dst[i]; + float tmp_co[3], tmp_no[3]; + + int tot_rays, done_rays = 0; + float poly_area_2d_inv, done_area = 0.0f; + + const float zvec[3] = {0.0f, 0.0f, 1.0f}; + float pcent_dst[3]; + float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3]; + float poly_dst_2d_min[2], poly_dst_2d_max[2], poly_dst_2d_z; + float poly_dst_2d_size[2]; + + float totweights = 0.0f; + float hit_dist_accum = 0.0f; + int sources_num = 0; + const int tris_num = mp->totloop - 2; + int j; + + BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, pcent_dst); + copy_v3_v3(tmp_no, poly_nors_dst[i]); + /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */ + if (space_transform) { + BLI_space_transform_apply(space_transform, pcent_dst); + BLI_space_transform_apply_normal(space_transform, tmp_no); + } + + fill_vn_fl(weights, (int)numpolys_src, 0.0f); + + if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) { + tmp_poly_size = (size_t)mp->totloop; + poly_vcos_2d = MEM_reallocN(poly_vcos_2d, sizeof(*poly_vcos_2d) * tmp_poly_size); + tri_vidx_2d = MEM_reallocN(tri_vidx_2d, sizeof(*tri_vidx_2d) * (tmp_poly_size - 2)); + } + + rotation_between_vecs_to_mat3(to_pnor_2d_mat, tmp_no, zvec); + invert_m3_m3(from_pnor_2d_mat, to_pnor_2d_mat); + + mul_m3_v3(to_pnor_2d_mat, pcent_dst); + poly_dst_2d_z = pcent_dst[2]; + + /* Get (2D) bounding square of our poly. */ + INIT_MINMAX2(poly_dst_2d_min, poly_dst_2d_max); + + for (j = 0; j < mp->totloop; j++) { + MLoop *ml = &loops_dst[j + mp->loopstart]; + copy_v3_v3(tmp_co, verts_dst[ml->v].co); + if (space_transform) { + BLI_space_transform_apply(space_transform, tmp_co); + } + mul_v2_m3v3(poly_vcos_2d[j], to_pnor_2d_mat, tmp_co); + minmax_v2v2_v2(poly_dst_2d_min, poly_dst_2d_max, poly_vcos_2d[j]); + } + + /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), + * with lower/upper bounds. */ + sub_v2_v2v2(poly_dst_2d_size, poly_dst_2d_max, poly_dst_2d_min); + + if (ray_radius) { + tot_rays = (int)((max_ff(poly_dst_2d_size[0], poly_dst_2d_size[1]) / ray_radius) + 0.5f); + CLAMP(tot_rays, MREMAP_RAYCAST_TRI_SAMPLES_MIN, MREMAP_RAYCAST_TRI_SAMPLES_MAX); + } + else { + /* If no radius (pure rays), give max number of rays! */ + tot_rays = MREMAP_RAYCAST_TRI_SAMPLES_MIN; + } + tot_rays *= tot_rays; + + poly_area_2d_inv = 1.0f / area_poly_v2((const float(*)[2])poly_vcos_2d, (unsigned int)mp->totloop); + + /* Tessellate our poly. */ + if (mp->totloop == 3) { + tri_vidx_2d[0][0] = 0; + tri_vidx_2d[0][1] = 1; + tri_vidx_2d[0][2] = 2; + } + if (mp->totloop == 4) { + tri_vidx_2d[0][0] = 0; + tri_vidx_2d[0][1] = 1; + tri_vidx_2d[0][2] = 2; + tri_vidx_2d[1][0] = 0; + tri_vidx_2d[1][1] = 2; + tri_vidx_2d[1][2] = 3; + } + else { + BLI_polyfill_calc((const float(*)[2])poly_vcos_2d, (unsigned int)mp->totloop, -1, + (unsigned int (*)[3])tri_vidx_2d); + } + + for (j = 0; j < tris_num; j++) { + float *v1 = poly_vcos_2d[tri_vidx_2d[j][0]]; + float *v2 = poly_vcos_2d[tri_vidx_2d[j][1]]; + float *v3 = poly_vcos_2d[tri_vidx_2d[j][2]]; + int rays_num; + + /* All this allows us to get 'absolute' number of rays for each tri, avoiding accumulating + * errors over iterations, and helping better even distribution. */ + done_area += area_tri_v2(v1, v2, v3); + rays_num = (int)((float)tot_rays * done_area * poly_area_2d_inv + 0.5f) - done_rays; + done_rays += rays_num; + + while (rays_num--) { + int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1; + float w = 1.0f; + + BLI_rng_get_tri_sample_float_v2(rng, v1, v2, v3, tmp_co); + + tmp_co[2] = poly_dst_2d_z; + mul_m3_v3(from_pnor_2d_mat, tmp_co); + + /* At this point, tmp_co is a point on our poly surface, in mesh_src space! */ + while (n--) { + /* Note we handle dest to src space conversion ourself, here! */ + + if (mesh_remap_bvhtree_query_raycast( + &treedata, &rayhit, NULL, + tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) + { + weights[tessface_to_poly_map_src[rayhit.index]] += w; + totweights += w; + hit_dist_accum += hit_dist; + break; + } + /* Next iteration will get bigger radius but smaller weight! */ + w /= MREMAP_RAYCAST_APPROXIMATE_FAC; + } + } + } + + if (totweights > 0.0f) { + for (j = 0; j < (int)numpolys_src; j++) { + if (!weights[j]) { + continue; + } + /* Note: sources_num is always <= j! */ + weights[sources_num] = weights[j] / totweights; + indices[sources_num] = j; + sources_num++; + } + mesh_remap_item_define(r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights); + } + else { + /* No source for this dest poly! */ + BKE_mesh_remap_item_define_invalid(r_map, i); + } + } + + MEM_freeN(tri_vidx_2d); + MEM_freeN(poly_vcos_2d); + MEM_freeN(indices); + MEM_freeN(weights); + BLI_rng_free(rng); + } + else { + printf("WARNING! Unsupported mesh-to-mesh poly mapping mode (%d)!\n", mode); + memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numpolys_dst); + } + + free_bvhtree_from_mesh(&treedata); + } +} + +#undef MREMAP_RAYCAST_APPROXIMATE_NR +#undef MREMAP_RAYCAST_APPROXIMATE_FAC +#undef MREMAP_RAYCAST_APPROXIMATE_BVHEPSILON +#undef MREMAP_RAYCAST_TRI_SAMPLES_MIN +#undef MREMAP_RAYCAST_TRI_SAMPLES_MAX +#undef MREMAP_DEFAULT_BUFSIZE + +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index f3a9e894eb3..3a6c949fe9c 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -755,7 +755,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, MDeformWeight *dw; for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) { - /* note, greater then max defgroups is accounted for in our code, but not < 0 */ + /* note, greater than max defgroups is accounted for in our code, but not < 0 */ if (!finite(dw->weight)) { PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight); if (do_fixes) { diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index a9e853c873e..021e564ef95 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -47,7 +47,6 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" -#include "DNA_meshdata_types.h" #include "BLI_utildefines.h" #include "BLI_path_util.h" @@ -57,6 +56,7 @@ #include "BLF_translation.h" +#include "BKE_appdir.h" #include "BKE_key.h" #include "BKE_multires.h" #include "BKE_DerivedMesh.h" @@ -262,8 +262,8 @@ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst) { ModifierTypeInfo *mti = modifierType_getInfo(md_src->type); const size_t data_size = sizeof(ModifierData); - const char *md_src_data = ((char *)md_src) + data_size; - char *md_dst_data = ((char *)md_dst) + data_size; + const char *md_src_data = ((const char *)md_src) + data_size; + char *md_dst_data = ((char *)md_dst) + data_size; BLI_assert(data_size <= (size_t)mti->structSize); memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size); } @@ -713,7 +713,7 @@ const char *modifier_path_relbase(Object *ob) else { /* last resort, better then using "" which resolves to the current * working directory */ - return BLI_temp_dir_session(); + return BKE_tempdir_session(); } } @@ -723,7 +723,7 @@ void modifier_path_init(char *path, int path_maxlen, const char *name) /* elubie: changed this to default to the same dir as the render output * to prevent saving to C:\ on Windows */ BLI_join_dirfile(path, path_maxlen, - G.relbase_valid ? "//" : BLI_temp_dir_session(), + G.relbase_valid ? "//" : BKE_tempdir_session(), name); } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index b387c7d2d1b..fe38fedd7aa 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -69,7 +69,6 @@ #include "BKE_image.h" /* openanim */ #include "BKE_tracking.h" -#include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_moviecache.h" @@ -78,8 +77,6 @@ # include "intern/openexr/openexr_multi.h" #endif -#include "NOD_composite.h" - /*********************** movieclip buffer loaders *************************/ static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen) @@ -391,7 +388,7 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr) static void moviecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags) { - MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)userkey; + const MovieClipImBufCacheKey *key = userkey; *framenr = key->framenr; *proxy = key->proxy; @@ -400,7 +397,7 @@ static void moviecache_keydata(void *userkey, int *framenr, int *proxy, int *ren static unsigned int moviecache_hashhash(const void *keyv) { - MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)keyv; + const MovieClipImBufCacheKey *key = keyv; int rval = key->framenr; return rval; @@ -408,8 +405,8 @@ static unsigned int moviecache_hashhash(const void *keyv) static bool moviecache_hashcmp(const void *av, const void *bv) { - const MovieClipImBufCacheKey *a = (MovieClipImBufCacheKey *)av; - const MovieClipImBufCacheKey *b = (MovieClipImBufCacheKey *)bv; + const MovieClipImBufCacheKey *a = av; + const MovieClipImBufCacheKey *b = bv; return ((a->framenr != b->framenr) || (a->proxy != b->proxy) || @@ -528,6 +525,15 @@ static bool put_imbuf_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, i } } +static bool moviecache_check_free_proxy(ImBuf *UNUSED(ibuf), + void *userkey, + void *UNUSED(userdata)) +{ + MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)userkey; + + return !(key->proxy == IMB_PROXY_NONE && key->render_flag == 0); +} + /*********************** common functions *************************/ /* only image block itself */ @@ -1170,6 +1176,15 @@ void BKE_movieclip_clear_cache(MovieClip *clip) free_buffers(clip); } +void BKE_movieclip_clear_proxy_cache(MovieClip *clip) +{ + if (clip->cache && clip->cache->moviecache) { + IMB_moviecache_cleanup(clip->cache->moviecache, + moviecache_check_free_proxy, + NULL); + } +} + void BKE_movieclip_reload(MovieClip *clip) { /* clear cache */ diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index d89c4877dea..8e9f86d7c19 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -567,7 +567,7 @@ bool BKE_nlastrips_has_space(ListBase *strips, float start, float end) /* sanity checks */ if ((strips == NULL) || IS_EQF(start, end)) - return 0; + return false; if (start > end) { puts("BKE_nlastrips_has_space() error... start and end arguments swapped"); SWAP(float, start, end); @@ -579,17 +579,17 @@ bool BKE_nlastrips_has_space(ListBase *strips, float start, float end) * we've gone past the window we need to check for, so things are fine */ if (strip->start >= end) - return 1; + return true; /* if the end of the strip is greater than either of the boundaries, the range * must fall within the extents of the strip */ if ((strip->end > start) || (strip->end > end)) - return 0; + return false; } /* if we are still here, we haven't encountered any overlapping strips */ - return 1; + return true; } /* Rearrange the strips in the track so that they are always in order @@ -646,11 +646,11 @@ bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip) /* sanity checks */ if (ELEM(NULL, strips, strip)) - return 0; + return false; /* check if any space to add */ if (BKE_nlastrips_has_space(strips, strip->start, strip->end) == 0) - return 0; + return false; /* find the right place to add the strip to the nominated track */ for (ns = strips->first; ns; ns = ns->next) { @@ -667,7 +667,7 @@ bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip) } /* added... */ - return 1; + return true; } @@ -785,11 +785,11 @@ bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip) { /* sanity checks */ if (ELEM(NULL, mstrip, strip)) - return 0; + return false; /* firstly, check if the meta-strip has space for this */ if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0) - return 0; + return false; /* check if this would need to be added to the ends of the meta, * and subsequently, if the neighboring strips allow us enough room @@ -803,10 +803,10 @@ bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip) BLI_addhead(&mstrip->strips, strip); mstrip->start = strip->start; - return 1; + return true; } else /* failed... no room before */ - return 0; + return false; } else if (strip->end > mstrip->end) { /* check if strip to the right (if it exists) starts before the @@ -817,10 +817,10 @@ bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip) BLI_addtail(&mstrip->strips, strip); mstrip->end = strip->end; - return 1; + return true; } else /* failed... no room after */ - return 0; + return false; } else { /* just try to add to the meta-strip (no dimension changes needed) */ @@ -988,7 +988,7 @@ bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end) * - bounds cannot be equal (0-length is nasty) */ if ((nlt == NULL) || (nlt->flag & NLATRACK_PROTECTED) || IS_EQF(start, end)) - return 0; + return false; if (start > end) { puts("BKE_nlatrack_has_space() error... start and end arguments swapped"); @@ -1019,7 +1019,7 @@ bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip) { /* sanity checks */ if (ELEM(NULL, nlt, strip)) - return 0; + return false; /* try to add the strip to the track using a more generic function */ return BKE_nlastrips_add_strip(&nlt->strips, strip); @@ -1036,11 +1036,11 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2]) if (bounds) bounds[0] = bounds[1] = 0.0f; else - return 0; + return false; /* sanity checks */ if (ELEM(NULL, nlt, nlt->strips.first)) - return 0; + return false; /* lower bound is first strip's start frame */ strip = nlt->strips.first; @@ -1051,7 +1051,7 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2]) bounds[1] = strip->end; /* done */ - return 1; + return true; } /* NLA Strips -------------------------------------- */ @@ -1105,7 +1105,7 @@ bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max) /* sanity checks */ if ((strip == NULL) || IS_EQF(stripLen, 0.0f) || IS_EQF(boundsLen, 0.0f)) - return 0; + return false; /* only ok if at least part of the strip is within the bounding window * - first 2 cases cover when the strip length is less than the bounding area @@ -1115,17 +1115,17 @@ bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max) !(IN_RANGE(strip->start, min, max) || IN_RANGE(strip->end, min, max))) { - return 0; + return false; } if ((stripLen > boundsLen) && !(IN_RANGE(min, strip->start, strip->end) || IN_RANGE(max, strip->start, strip->end)) ) { - return 0; + return false; } /* should be ok! */ - return 1; + return true; } @@ -1209,11 +1209,11 @@ static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip) /* sanity checks */ if (ELEM(NULL, adt, strip)) - return 0; + return false; /* check if strip has any strips before it */ if (strip->prev) - return 0; + return false; /* check other tracks to see if they have a strip that's earlier */ /* TODO: or should we check that the strip's track is also the first? */ @@ -1222,12 +1222,12 @@ static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip) ns = nlt->strips.first; if (ns) { if (ns->start < strip->start) - return 0; + return false; } } /* should be first now */ - return 1; + return true; } /* Animated Strips ------------------------------------------- */ @@ -1239,16 +1239,16 @@ bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt) /* sanity checks */ if (ELEM(NULL, nlt, nlt->strips.first)) - return 0; + return false; /* check each strip for F-Curves only (don't care about whether the flags are set) */ for (strip = nlt->strips.first; strip; strip = strip->next) { if (strip->fcurves.first) - return 1; + return true; } /* none found */ - return 0; + return false; } /* Check if given NLA-Tracks have any strips with own F-Curves */ @@ -1258,16 +1258,16 @@ bool BKE_nlatracks_have_animated_strips(ListBase *tracks) /* sanity checks */ if (ELEM(NULL, tracks, tracks->first)) - return 0; + return false; /* check each track, stopping on the first hit */ for (nlt = tracks->first; nlt; nlt = nlt->next) { if (BKE_nlatrack_has_animated_strips(nlt)) - return 1; + return true; } /* none found */ - return 0; + return false; } /* Validate the NLA-Strips 'control' F-Curves based on the flags set*/ @@ -1326,7 +1326,7 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) static bool nla_editbone_name_check(void *arg, const char *name) { - return BLI_ghash_haskey((GHash *)arg, (void *)name); + return BLI_ghash_haskey((GHash *)arg, (const void *)name); } /* Find (and set) a unique name for a strip from the whole AnimData block @@ -1587,13 +1587,13 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) /* verify that data is valid */ if (ELEM(NULL, adt, adt->nla_tracks.first)) - return 0; + return false; /* if block is already in tweakmode, just leave, but we should report * that this block is in tweakmode (as our returncode) */ if (adt->flag & ADT_NLA_EDIT_ON) - return 1; + return true; /* go over the tracks, finding the active one, and its active strip * - if we cannot find both, then there's nothing to do @@ -1642,7 +1642,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) printf("NLA tweakmode enter - neither active requirement found\n"); printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip); } - return 0; + return false; } /* go over all the tracks up to the active one, tagging each strip that uses the same @@ -1677,7 +1677,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) adt->flag |= ADT_NLA_EDIT_ON; /* done! */ - return 1; + return true; } /* Exit tweakmode for this AnimData block */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index db27e559a4f..039af949d81 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1202,6 +1202,10 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_ /* node tree will generate its own interface type */ newtree->interface_type = NULL; + if (ntree->id.lib) { + BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id); + } + return newtree; } @@ -2293,8 +2297,8 @@ bool ntreeHasType(const bNodeTree *ntree, int type) if (ntree) for (node = ntree->nodes.first; node; node = node->next) if (node->type == type) - return 1; - return 0; + return true; + return false; } bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) @@ -2877,7 +2881,7 @@ static void ntree_update_node_level(bNodeTree *ntree) } } -static void ntree_update_link_pointers(bNodeTree *ntree) +void ntreeTagUsedSockets(bNodeTree *ntree) { bNode *node; bNodeSocket *sock; @@ -2886,22 +2890,43 @@ static void ntree_update_link_pointers(bNodeTree *ntree) /* first clear data */ for (node = ntree->nodes.first; node; node = node->next) { for (sock = node->inputs.first; sock; sock = sock->next) { - sock->link = NULL; sock->flag &= ~SOCK_IN_USE; } for (sock = node->outputs.first; sock; sock = sock->next) { sock->flag &= ~SOCK_IN_USE; } } - + for (link = ntree->links.first; link; link = link->next) { - link->tosock->link = link; + /* link is unused if either side is disabled */ + if ((link->fromsock->flag & SOCK_UNAVAIL) || (link->tosock->flag & SOCK_UNAVAIL)) + continue; link->fromsock->flag |= SOCK_IN_USE; link->tosock->flag |= SOCK_IN_USE; } } +static void ntree_update_link_pointers(bNodeTree *ntree) +{ + bNode *node; + bNodeSocket *sock; + bNodeLink *link; + + /* first clear data */ + for (node = ntree->nodes.first; node; node = node->next) { + for (sock = node->inputs.first; sock; sock = sock->next) { + sock->link = NULL; + } + } + + for (link = ntree->links.first; link; link = link->next) { + link->tosock->link = link; + } + + ntreeTagUsedSockets(ntree); +} + static void ntree_validate_links(bNodeTree *ntree) { bNodeLink *link; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index f8e883b03dd..41f7721d59f 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1137,7 +1137,7 @@ static LodLevel *lod_level_select(Object *ob, const float camera_position[3]) bool BKE_object_lod_is_usable(Object *ob, Scene *scene) { - bool active = (scene) ? ob == OBACT : 0; + bool active = (scene) ? ob == OBACT : false; return (ob->mode == OB_MODE_OBJECT || !active); } @@ -1403,10 +1403,10 @@ bool BKE_object_pose_context_check(Object *ob) (ob->pose) && (ob->mode & OB_MODE_POSE)) { - return 1; + return true; } else { - return 0; + return false; } } @@ -1519,6 +1519,10 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) /* Copy runtime surve data. */ obn->curve_cache = NULL; + if (ob->id.lib) { + BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id); + } + return obn; } @@ -2020,12 +2024,16 @@ void BKE_object_to_mat4(Object *ob, float mat[4][4]) add_v3_v3v3(mat[3], ob->loc, ob->dloc); } +static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]); + void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]) { if (ob->parent) { - float invmat[4][4]; /* for inverse of parent's matrix */ - invert_m4_m4(invmat, ob->parent->obmat); - mul_m4_m4m4(mat, invmat, ob->obmat); + float par_imat[4][4]; + + ob_get_parent_matrix(NULL, ob, ob->parent, par_imat); + invert_m4(par_imat); + mul_m4_m4m4(mat, par_imat, ob->obmat); } else { copy_m4_m4(mat, ob->obmat); @@ -2402,7 +2410,7 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat /* include framerate */ fac1 = (1.0f / (1.0f + fabsf(ob->sf))); - if (fac1 >= 1.0f) return 0; + if (fac1 >= 1.0f) return false; fac2 = 1.0f - fac1; fp1 = obmat[0]; @@ -2411,7 +2419,7 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat fp1[0] = fac1 * fp1[0] + fac2 * fp2[0]; } - return 1; + return true; } /* note, scene is the active scene while actual_scene is the scene the object resides in */ @@ -2535,17 +2543,16 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv); invert_m4_m4(imat, diff_mat); mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */ - BKE_object_apply_mat4(ob, rmat, use_compat, false); /* same as below, use rmat rather than mat */ mat4_to_loc_rot_size(ob->loc, rot, ob->size, rmat); - BKE_object_mat3_to_rot(ob, rot, use_compat); } else { mat4_to_loc_rot_size(ob->loc, rot, ob->size, mat); - BKE_object_mat3_to_rot(ob, rot, use_compat); } + BKE_object_mat3_to_rot(ob, rot, use_compat); + sub_v3_v3(ob->loc, ob->dloc); if (ob->dscale[0] != 0.0f) ob->size[0] /= ob->dscale[0]; @@ -3345,7 +3352,7 @@ void BKE_object_delete_ptcache(Object *ob, int index) /* shape key utility function */ /************************* Mesh ************************/ -static KeyBlock *insert_meshkey(Scene *scene, Object *ob, const char *name, const bool from_mix) +static KeyBlock *insert_meshkey(Object *ob, const char *name, const bool from_mix) { Mesh *me = ob->data; Key *key = me->key; @@ -3366,7 +3373,7 @@ static KeyBlock *insert_meshkey(Scene *scene, Object *ob, const char *name, cons else { /* copy from current values */ int totelem; - float *data = BKE_key_evaluate_object(scene, ob, &totelem); + float *data = BKE_key_evaluate_object(ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, false); @@ -3377,7 +3384,7 @@ static KeyBlock *insert_meshkey(Scene *scene, Object *ob, const char *name, cons return kb; } /************************* Lattice ************************/ -static KeyBlock *insert_lattkey(Scene *scene, Object *ob, const char *name, const bool from_mix) +static KeyBlock *insert_lattkey(Object *ob, const char *name, const bool from_mix) { Lattice *lt = ob->data; Key *key = lt->key; @@ -3404,7 +3411,7 @@ static KeyBlock *insert_lattkey(Scene *scene, Object *ob, const char *name, cons else { /* copy from current values */ int totelem; - float *data = BKE_key_evaluate_object(scene, ob, &totelem); + float *data = BKE_key_evaluate_object(ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, false); @@ -3415,7 +3422,7 @@ static KeyBlock *insert_lattkey(Scene *scene, Object *ob, const char *name, cons return kb; } /************************* Curve ************************/ -static KeyBlock *insert_curvekey(Scene *scene, Object *ob, const char *name, const bool from_mix) +static KeyBlock *insert_curvekey(Object *ob, const char *name, const bool from_mix) { Curve *cu = ob->data; Key *key = cu->key; @@ -3444,7 +3451,7 @@ static KeyBlock *insert_curvekey(Scene *scene, Object *ob, const char *name, con else { /* copy from current values */ int totelem; - float *data = BKE_key_evaluate_object(scene, ob, &totelem); + float *data = BKE_key_evaluate_object(ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, false); @@ -3455,16 +3462,16 @@ static KeyBlock *insert_curvekey(Scene *scene, Object *ob, const char *name, con return kb; } -KeyBlock *BKE_object_insert_shape_key(Scene *scene, Object *ob, const char *name, const bool from_mix) +KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool from_mix) { switch (ob->type) { case OB_MESH: - return insert_meshkey(scene, ob, name, from_mix); + return insert_meshkey(ob, name, from_mix); case OB_CURVE: case OB_SURF: - return insert_curvekey(scene, ob, name, from_mix); + return insert_curvekey(ob, name, from_mix); case OB_LATTICE: - return insert_lattkey(scene, ob, name, from_mix); + return insert_lattkey(ob, name, from_mix); default: return NULL; } @@ -3509,6 +3516,88 @@ int BKE_object_is_modified(Scene *scene, Object *ob) return flag; } +/* Check of objects moves in time. */ +/* NOTE: This function is currently optimized for usage in combination + * with mti->canDeform, so modifiers can quickly check if their target + * objects moves (causing deformation motion blur) or not. + * + * This makes it possible to give some degree of false-positives here, + * but it's currently an acceptable tradeoff between complexity and check + * speed. In combination with checks of modifier stack and real life usage + * percentage of false-positives shouldn't be that hight. + */ +static bool object_moves_in_time(Object *object) +{ + AnimData *adt = object->adt; + if (adt != NULL) { + /* If object has any sort of animation data assume it is moving. */ + if (adt->action != NULL || + !BLI_listbase_is_empty(&adt->nla_tracks) || + !BLI_listbase_is_empty(&adt->drivers) || + !BLI_listbase_is_empty(&adt->overrides)) + { + return true; + } + } + if (!BLI_listbase_is_empty(&object->constraints)) { + return true; + } + if (object->parent != NULL) { + /* TODO(sergey): Do recursive check here? */ + return true; + } + return false; +} + +static bool constructive_modifier_is_deform_modified(ModifierData *md) +{ + /* TODO(sergey): Consider generalizing this a bit so all modifier logic + * is concentrated in MOD_{modifier}.c file, + */ + if (md->type == eModifierType_Array) { + ArrayModifierData *amd = (ArrayModifierData *)md; + /* TODO(sergey): Check if curve is deformed. */ + return (amd->start_cap != NULL && object_moves_in_time(amd->start_cap)) || + (amd->end_cap != NULL && object_moves_in_time(amd->end_cap)) || + (amd->curve_ob != NULL && object_moves_in_time(amd->curve_ob)) || + (amd->offset_ob != NULL && object_moves_in_time(amd->offset_ob)); + } + else if (md->type == eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData *)md; + return mmd->mirror_ob != NULL && object_moves_in_time(mmd->mirror_ob); + } + else if (md->type == eModifierType_Screw) { + ScrewModifierData *smd = (ScrewModifierData *)md; + return smd->ob_axis != NULL && object_moves_in_time(smd->ob_axis); + } + return false; +} + +static bool modifiers_has_animation_check(Object *ob) +{ + /* TODO(sergey): This is a bit code duplication with depsgraph, but + * would be nicer to solve this as a part of new dependency graph + * work, so we avoid conflicts and so. + */ + if (ob->adt != NULL) { + AnimData *adt = ob->adt; + FCurve *fcu; + if (adt->action != NULL) { + for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) { + return true; + } + } + } + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) { + return true; + } + } + } + return false; +} + /* test if object is affected by deforming modifiers (for motion blur). again * most important is to avoid false positives, this is to skip computations * and we can still if there was actual deformation afterwards */ @@ -3517,6 +3606,7 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob) ModifierData *md; VirtualModifierData virtualModifierData; int flag = 0; + const bool is_modifier_animated = modifiers_has_animation_check(ob); if (BKE_key_from_object(ob)) flag |= eModifierMode_Realtime | eModifierMode_Render; @@ -3527,8 +3617,14 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob) md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + bool can_deform = mti->type == eModifierTypeType_OnlyDeform || + is_modifier_animated; + + if (!can_deform) { + can_deform = constructive_modifier_is_deform_modified(md); + } - if (mti->type == eModifierTypeType_OnlyDeform) { + if (can_deform) { if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render)) flag |= eModifierMode_Render; diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index a3f5e56f4dc..e46929dde4a 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -27,18 +27,457 @@ #include "MEM_guardedalloc.h" +#include "BLF_translation.h" + #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_listbase.h" +#include "DNA_armature_types.h" +#include "DNA_cloth_types.h" +#include "DNA_curve_types.h" +#include "DNA_lattice_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" + #include "BKE_action.h" +#include "BKE_deform.h" +#include "BKE_editmesh.h" #include "BKE_object_deform.h" /* own include */ #include "BKE_object.h" #include "BKE_modifier.h" -#include "DNA_armature_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" +/** \name Misc helpers + * \{ */ + +static Lattice *object_defgroup_lattice_get(ID *id) +{ + Lattice *lt = (Lattice *)id; + BLI_assert(GS(id->name) == ID_LT); + return (lt->editlatt) ? lt->editlatt->latt : lt; +} + +/** + * Update users of vgroups from this object, according to given map. + * + * Use it when you remove or reorder vgroups in the object. + * + * \param map an array mapping old indices to new indices. + */ +void BKE_object_defgroup_remap_update_users(Object *ob, int *map) +{ + ModifierData *md; + ParticleSystem *psys; + int a; + + /* these cases don't use names to refer to vertex groups, so when + * they get removed the numbers get out of sync, this corrects that */ + + if (ob->soft) { + ob->soft->vertgroup = map[ob->soft->vertgroup]; + } + + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Explode) { + ExplodeModifierData *emd = (ExplodeModifierData *)md; + emd->vgroup = map[emd->vgroup]; + } + else if (md->type == eModifierType_Cloth) { + ClothModifierData *clmd = (ClothModifierData *)md; + ClothSimSettings *clsim = clmd->sim_parms; + + if (clsim) { + clsim->vgroup_mass = map[clsim->vgroup_mass]; + clsim->vgroup_bend = map[clsim->vgroup_bend]; + clsim->vgroup_struct = map[clsim->vgroup_struct]; + } + } + } + + for (psys = ob->particlesystem.first; psys; psys = psys->next) { + for (a = 0; a < PSYS_TOT_VG; a++) { + psys->vgroup[a] = map[psys->vgroup[a]]; + } + } +} +/** \} */ + + +/** \name Group creation + * \{ */ + +/** + * Add a vgroup of given name to object. *Does not* handle MDeformVert data at all! + */ +bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name) +{ + bDeformGroup *defgroup; + + if (!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type)) + return NULL; + + defgroup = BKE_defgroup_new(ob, name); + + ob->actdef = BLI_listbase_count(&ob->defbase); + + return defgroup; +} + +/** + * Add a vgroup of default name to object. *Does not* handle MDeformVert data at all! + */ +bDeformGroup *BKE_object_defgroup_add(Object *ob) +{ + return BKE_object_defgroup_add_name(ob, DATA_("Group")); +} + +/** + * Create MDeformVert data for given ID. Work in Object mode only. + */ +MDeformVert *BKE_object_defgroup_data_create(ID *id) +{ + if (GS(id->name) == ID_ME) { + Mesh *me = (Mesh *)id; + me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert); + return me->dvert; + } + else if (GS(id->name) == ID_LT) { + Lattice *lt = (Lattice *)id; + lt->dvert = MEM_callocN(sizeof(MDeformVert) * lt->pntsu * lt->pntsv * lt->pntsw, "lattice deformVert"); + return lt->dvert; + } + + return NULL; +} +/** \} */ + + +/** \name Group clearing + * \{ */ + +/** + * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes. + * + * \param allverts If true, remove all vertices, else only selected ones. + * \return True if any vertex was removed, false otherwise. + */ +bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection) +{ + MDeformVert *dv; + const int def_nr = BLI_findindex(&ob->defbase, dg); + bool changed = false; + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + if (cd_dvert_offset != -1) { + BMVert *eve; + BMIter iter; + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + + if (dv && dv->dw && (!use_selection || BM_elem_flag_test(eve, BM_ELEM_SELECT))) { + MDeformWeight *dw = defvert_find_index(dv, def_nr); + defvert_remove_group(dv, dw); /* dw can be NULL */ + changed = true; + } + } + } + } + else { + if (me->dvert) { + MVert *mv; + int i; + + mv = me->mvert; + dv = me->dvert; + + for (i = 0; i < me->totvert; i++, mv++, dv++) { + if (mv->flag & SELECT) { + if (dv->dw && (!use_selection || (mv->flag & SELECT))) { + MDeformWeight *dw = defvert_find_index(dv, def_nr); + defvert_remove_group(dv, dw); /* dw can be NULL */ + changed = true; + } + } + } + } + } + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data)); + + if (lt->dvert) { + BPoint *bp; + int i, tot = lt->pntsu * lt->pntsv * lt->pntsw; + + for (i = 0, bp = lt->def; i < tot; i++, bp++) { + if (!use_selection || (bp->f1 & SELECT)) { + MDeformWeight *dw; + + dv = <->dvert[i]; + + dw = defvert_find_index(dv, def_nr); + defvert_remove_group(dv, dw); /* dw can be NULL */ + changed = true; + } + } + } + } + + return changed; +} + +/** + * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes. + * + * \param allverts If true, remove all vertices, else only selected ones. + * \return True if any vertex was removed, false otherwise. + */ +bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection) +{ + bDeformGroup *dg; + bool changed = false; + + for (dg = ob->defbase.first; dg; dg = dg->next) { + if (BKE_object_defgroup_clear(ob, dg, use_selection)) { + changed = true; + } + } + + return changed; +} +/** \} */ + + +/** \name Group removal + * \{ */ + +static void object_defgroup_remove_update_users(Object *ob, const int idx) +{ + int i, defbase_tot = BLI_listbase_count(&ob->defbase) + 1; + int *map = MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del"); + + map[idx] = map[0] = 0; + for (i = 1; i < idx; i++) { + map[i] = i; + } + for (i = idx + 1; i < defbase_tot; i++) { + map[i] = i - 1; + } + + BKE_object_defgroup_remap_update_users(ob, map); + MEM_freeN(map); +} + +static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const int def_nr) +{ + object_defgroup_remove_update_users(ob, def_nr + 1); + + /* Remove the group */ + BLI_freelinkN(&ob->defbase, dg); + + /* Update the active deform index if necessary */ + if (ob->actdef > def_nr) + ob->actdef--; + + /* remove all dverts */ + if (BLI_listbase_is_empty(&ob->defbase)) { + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); + me->dvert = NULL; + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data)); + if (lt->dvert) { + MEM_freeN(lt->dvert); + lt->dvert = NULL; + } + } + } + else if (ob->actdef < 1) { /* Keep a valid active index if we still have some vgroups. */ + ob->actdef = 1; + } +} + +static void object_defgroup_remove_object_mode(Object *ob, bDeformGroup *dg) +{ + MDeformVert *dvert_array = NULL; + int dvert_tot = 0; + const int def_nr = BLI_findindex(&ob->defbase, dg); + + BLI_assert(def_nr != -1); + + BKE_object_defgroup_array_get(ob->data, &dvert_array, &dvert_tot); + + if (dvert_array) { + int i, j; + MDeformVert *dv; + for (i = 0, dv = dvert_array; i < dvert_tot; i++, dv++) { + MDeformWeight *dw; + + dw = defvert_find_index(dv, def_nr); + defvert_remove_group(dv, dw); /* dw can be NULL */ + + /* inline, make into a function if anything else needs to do this */ + for (j = 0; j < dv->totweight; j++) { + if (dv->dw[j].def_nr > def_nr) { + dv->dw[j].def_nr--; + } + } + /* done */ + } + } + + object_defgroup_remove_common(ob, dg, def_nr); +} + +static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg) +{ + int i; + const int def_nr = BLI_findindex(&ob->defbase, dg); + + BLI_assert(def_nr != -1); + + /* Make sure that no verts are using this group - if none were removed, we can skip next per-vert update. */ + if (!BKE_object_defgroup_clear(ob, dg, false)) { + /* Nothing to do. */ + } + /* Else, make sure that any groups with higher indices are adjusted accordingly */ + else if (ob->type == OB_MESH) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + BMIter iter; + BMVert *eve; + MDeformVert *dvert; + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + + if (dvert) { + for (i = 0; i < dvert->totweight; i++) { + if (dvert->dw[i].def_nr > def_nr) { + dvert->dw[i].def_nr--; + } + } + } + } + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = ((Lattice *)(ob->data))->editlatt->latt; + BPoint *bp; + MDeformVert *dvert = lt->dvert; + int a, tot; + + if (dvert) { + tot = lt->pntsu * lt->pntsv * lt->pntsw; + for (a = 0, bp = lt->def; a < tot; a++, bp++, dvert++) { + for (i = 0; i < dvert->totweight; i++) { + if (dvert->dw[i].def_nr > def_nr) { + dvert->dw[i].def_nr--; + } + } + } + } + } + + object_defgroup_remove_common(ob, dg, def_nr); +} + +/** + * Remove given vgroup from object. Work in Object and Edit modes. + */ +void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) +{ + if (BKE_object_is_in_editmode_vgroup(ob)) + object_defgroup_remove_edit_mode(ob, defgroup); + else + object_defgroup_remove_object_mode(ob, defgroup); +} + +/** + * Remove all vgroups from object. Work in Object and Edit modes. + */ +void BKE_object_defgroup_remove_all(Object *ob) +{ + bDeformGroup *dg = (bDeformGroup *)ob->defbase.first; + const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob); + + if (dg) { + while (dg) { + bDeformGroup *next_dg = dg->next; + + if (edit_mode) + object_defgroup_remove_edit_mode(ob, dg); + else + object_defgroup_remove_object_mode(ob, dg); + + dg = next_dg; + } + } + else { /* ob->defbase is empty... */ + /* remove all dverts */ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); + me->dvert = NULL; + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data)); + if (lt->dvert) { + MEM_freeN(lt->dvert); + lt->dvert = NULL; + } + } + /* Fix counters/indices */ + ob->actdef = 0; + } +} + +/** + * Get MDeformVert vgroup data from given object. Should only be used in Object mode. + * + * \return True if the id type supports weights. + */ +bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot) +{ + if (id) { + switch (GS(id->name)) { + case ID_ME: + { + Mesh *me = (Mesh *)id; + *dvert_arr = me->dvert; + *dvert_tot = me->totvert; + return true; + } + case ID_LT: + { + Lattice *lt = object_defgroup_lattice_get(id); + *dvert_arr = lt->dvert; + *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw; + return true; + } + } + } + + *dvert_arr = NULL; + *dvert_tot = 0; + return false; +} +/** \} */ /* --- functions for getting vgroup aligned maps --- */ @@ -46,7 +485,7 @@ * gets the status of "flag" for each bDeformGroup * in ob->defbase and returns an array containing them */ -bool *BKE_objdef_lock_flags_get(Object *ob, const int defbase_tot) +bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot) { bool is_locked = false; int i; @@ -66,11 +505,11 @@ bool *BKE_objdef_lock_flags_get(Object *ob, const int defbase_tot) return NULL; } -bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot) +bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot) { bDeformGroup *dg; ModifierData *md; - bool *vgroup_validmap; + bool *defgroup_validmap; GHash *gh; int i, step1 = 1; //int defbase_tot = BLI_listbase_count(&ob->defbase); @@ -80,7 +519,7 @@ bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot) return NULL; } - gh = BLI_ghash_str_new_ex("BKE_objdef_validmap_get gh", defbase_tot); + gh = BLI_ghash_str_new_ex(__func__, defbase_tot); /* add all names to a hash table */ for (dg = ob->defbase.first; dg; dg = dg->next) { @@ -115,23 +554,23 @@ bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot) } } - vgroup_validmap = MEM_mallocN(sizeof(*vgroup_validmap) * defbase_tot, "wpaint valid map"); + defgroup_validmap = MEM_mallocN(sizeof(*defgroup_validmap) * defbase_tot, "wpaint valid map"); /* add all names to a hash table */ for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) { - vgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL); + defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL); } BLI_assert(i == BLI_ghash_size(gh)); BLI_ghash_free(gh, NULL, NULL); - return vgroup_validmap; + return defgroup_validmap; } /* Returns total selected vgroups, * wpi.defbase_sel is assumed malloc'd, all values are set */ -bool *BKE_objdef_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot) +bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot) { bool *dg_selection = MEM_mallocN(defbase_tot * sizeof(bool), __func__); bDeformGroup *defgroup; @@ -158,3 +597,86 @@ bool *BKE_objdef_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_t return dg_selection; } + + +/** + * Return the subset type of the Vertex Group Selection + */ +bool *BKE_object_defgroup_subset_from_select_type( + Object *ob, eVGroupSelect subset_type, int *r_defgroup_tot, int *r_subset_count) +{ + bool *defgroup_validmap = NULL; + *r_defgroup_tot = BLI_listbase_count(&ob->defbase); + + switch (subset_type) { + case WT_VGROUP_ACTIVE: + { + const int def_nr_active = ob->actdef - 1; + defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__); + memset(defgroup_validmap, false, *r_defgroup_tot * sizeof(*defgroup_validmap)); + if ((def_nr_active >= 0) && (def_nr_active < *r_defgroup_tot)) { + *r_subset_count = 1; + defgroup_validmap[def_nr_active] = true; + } + else { + *r_subset_count = 0; + } + break; + } + case WT_VGROUP_BONE_SELECT: + { + defgroup_validmap = BKE_object_defgroup_selected_get(ob, *r_defgroup_tot, r_subset_count); + break; + } + case WT_VGROUP_BONE_DEFORM: + { + int i; + defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot); + *r_subset_count = 0; + for (i = 0; i < *r_defgroup_tot; i++) { + if (defgroup_validmap[i] == true) { + *r_subset_count += 1; + } + } + break; + } + case WT_VGROUP_BONE_DEFORM_OFF: + { + int i; + defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot); + *r_subset_count = 0; + for (i = 0; i < *r_defgroup_tot; i++) { + defgroup_validmap[i] = !defgroup_validmap[i]; + if (defgroup_validmap[i] == true) { + *r_subset_count += 1; + } + } + break; + } + case WT_VGROUP_ALL: + default: + { + defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__); + memset(defgroup_validmap, true, *r_defgroup_tot * sizeof(*defgroup_validmap)); + *r_subset_count = *r_defgroup_tot; + break; + } + } + + return defgroup_validmap; +} + +/** + * store indices from the defgroup_validmap (faster lookups in some cases) + */ +void BKE_object_defgroup_subset_to_index_array( + const bool *defgroup_validmap, const int defgroup_tot, int *r_defgroup_subset_map) +{ + int i, j = 0; + for (i = 0; i < defgroup_tot; i++) { + if (defgroup_validmap[i]) { + r_defgroup_subset_map[j++] = i; + } + } +} + diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index ea81d1609d9..58591242e5b 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -395,7 +395,7 @@ bool BKE_paint_select_elem_test(Object *ob) BKE_paint_select_face_test(ob)); } -void BKE_paint_init(Paint *p, const char col[3]) +void BKE_paint_init(UnifiedPaintSettings *ups, Paint *p, const char col[3]) { Brush *brush; @@ -407,6 +407,9 @@ void BKE_paint_init(Paint *p, const char col[3]) memcpy(p->paint_cursor_col, col, 3); p->paint_cursor_col[3] = 128; + ups->last_stroke_valid = false; + zero_v3(ups->average_stroke_accum); + ups->average_stroke_counter = 0; } void BKE_paint_free(Paint *paint) @@ -426,6 +429,18 @@ void BKE_paint_copy(Paint *src, Paint *tar) id_us_plus((ID *)tar->palette); } +void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3]) +{ + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + if (ups->last_stroke_valid && ups->average_stroke_counter > 0) { + float fac = 1.0f / ups->average_stroke_counter; + mul_v3_v3fl(stroke, ups->average_stroke_accum, fac); + } + else { + copy_v3_v3(stroke, ob->obmat[3]); + } +} + /* returns non-zero if any of the face's vertices * are hidden, zero otherwise */ bool paint_is_face_hidden(const MFace *f, const MVert *mvert) @@ -477,19 +492,48 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, /* threshold to move before updating the brush rotation */ #define RAKE_THRESHHOLD 20 -void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, const float mouse_pos[2]) +static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation) +{ + if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) + ups->brush_rotation = rotation; + else + ups->brush_rotation = 0.0f; + + if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE) + /* here, translation contains the mouse coordinates. */ + ups->brush_rotation_sec = rotation; + else + ups->brush_rotation_sec = 0.0f; +} + +void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) { - const float u = 0.5f; - const float r = RAKE_THRESHHOLD; + if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { + const float u = 0.5f; + const float r = RAKE_THRESHHOLD; + float rotation; + + float dpos[2]; + sub_v2_v2v2(dpos, ups->last_rake, mouse_pos); + + if (len_squared_v2(dpos) >= r * r) { + rotation = atan2f(dpos[0], dpos[1]); - float dpos[2]; - sub_v2_v2v2(dpos, ups->last_rake, mouse_pos); + interp_v2_v2v2(ups->last_rake, ups->last_rake, + mouse_pos, u); - if (len_squared_v2(dpos) >= r * r) { - ups->brush_rotation = atan2f(dpos[0], dpos[1]); + ups->last_rake_angle = rotation; - interp_v2_v2v2(ups->last_rake, ups->last_rake, - mouse_pos, u); + update_brush_rake_rotation(ups, brush, rotation); + } + /* make sure we reset here to the last rotation to avoid accumulating + * values in case a random rotation is also added */ + else { + update_brush_rake_rotation(ups, brush, ups->last_rake_angle); + } + } + else { + ups->brush_rotation = ups->brush_rotation_sec = 0.0f; } } @@ -644,11 +688,11 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) VirtualModifierData virtualModifierData; if (mmd || ob->sculpt->bm) - return 0; + return false; /* non-locked shape keys could be handled in the same way as deformed mesh */ if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr) - return 1; + return true; md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -658,11 +702,11 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) continue; - if (mti->type == eModifierTypeType_OnlyDeform) return 1; - else if ((sd->flags & SCULPT_ONLY_DEFORM) == 0) return 1; + if (mti->type == eModifierTypeType_OnlyDeform) return true; + else if ((sd->flags & SCULPT_ONLY_DEFORM) == 0) return true; } - return 0; + return false; } /** diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 0b108210929..78a54e5c6ac 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -981,14 +981,14 @@ bool psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float int b; if (!(psys->renderdata && (psys->part->simplify_flag & PART_SIMPLIFY_ENABLE))) - return 0; + return false; data = psys->renderdata; if (!data->do_simplify) - return 0; + return false; b = (data->index_mf_to_mpoly) ? DM_origindex_mface_mpoly(data->index_mf_to_mpoly, data->index_mp_to_orig, cpa->num) : cpa->num; if (b == ORIGINDEX_NONE) { - return 0; + return false; } elem = &data->elems[b]; @@ -1568,12 +1568,13 @@ void psys_interpolate_uvs(const MTFace *tface, int quad, const float w[4], float void psys_interpolate_mcol(const MCol *mcol, int quad, const float w[4], MCol *mc) { - char *cp, *cp1, *cp2, *cp3, *cp4; + const char *cp1, *cp2, *cp3, *cp4; + char *cp; cp = (char *)mc; - cp1 = (char *)&mcol[0]; - cp2 = (char *)&mcol[1]; - cp3 = (char *)&mcol[2]; + cp1 = (const char *)&mcol[0]; + cp2 = (const char *)&mcol[1]; + cp3 = (const char *)&mcol[2]; if (quad) { cp4 = (char *)&mcol[3]; @@ -2999,7 +3000,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) } /*---first main loop: create all actual particles' paths---*/ - LOOP_SHOWN_PARTICLES { + LOOP_PARTICLES { if (!psys->totchild) { psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f); pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p)); @@ -3700,6 +3701,10 @@ ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part) BLI_duplicatelist(&partn->dupliweights, &part->dupliweights); + if (part->id.lib) { + BKE_id_lib_local_paths(G.main, part->id.lib, &partn->id); + } + return partn; } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 9fe5ba6707f..2a71cf2780f 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -1667,7 +1667,7 @@ static void get_angular_velocity_vector(short avemode, ParticleKey *state, float } } -void psys_get_birth_coordinates(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, float dtime, float cfra) +void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, float dtime, float cfra) { Object *ob = sim->ob; ParticleSystem *psys = sim->psys; @@ -1999,7 +1999,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, psys->flag |= PSYS_OB_ANIM_RESTORE; } - psys_get_birth_coordinates(sim, pa, &pa->state, dtime, cfra); + psys_get_birth_coords(sim, pa, &pa->state, dtime, cfra); /* Initialize particle settings which depends on texture. * diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index ff6fae08460..bd953890443 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -943,7 +943,7 @@ static bool update_search_cb(PBVHNode *node, void *data_v) if (node->flag & PBVH_Leaf) return (node->flag & flag) != 0; - return 1; + return true; } static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, @@ -1474,10 +1474,10 @@ bool ray_face_intersection(const float ray_start[3], (t3 && isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &dist, NULL, 0.1f) && dist < *fdist)) { *fdist = dist; - return 1; + return true; } else { - return 0; + return false; } } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index c2f71d729bb..75301471fca 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -50,7 +50,6 @@ #include "BLI_threads.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_system.h" #include "BLF_translation.h" @@ -58,6 +57,7 @@ #include "WM_api.h" +#include "BKE_appdir.h" #include "BKE_anim.h" #include "BKE_blender.h" #include "BKE_cloth.h" @@ -1461,7 +1461,7 @@ static int ptcache_path(PointCache *cache, Object *ob, char *filename) /* use the temp path. this is weak but better then not using point cache at all */ /* temporary directory is assumed to exist and ALWAYS has a trailing slash */ - BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH, BLI_temp_dir_session()); + BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH, BKE_tempdir_session()); return BLI_add_slash(filename); /* new strlen() */ } @@ -2495,11 +2495,18 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) case PTCACHE_CLEAR_AFTER: ptcache_path(pid->cache, pid->ob, path); - len = ptcache_filename(pid, filename, cfra, 0, 0); /* no path */ - dir = opendir(path); if (dir==NULL) return; + + len = ptcache_filename(pid, filename, cfra, 0, 0); /* no path */ + /* append underscore terminator to ensure we don't match similar names + * from objects whose names start with the same prefix + */ + if (len < sizeof(filename) - 2) { + BLI_strncpy(filename + len, "_", sizeof(filename) - 2 - len); + len += 1; + } BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 9b5d6699cb1..4bd3b6bd8dd 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -62,8 +62,6 @@ #include "BKE_pointcache.h" #include "BKE_rigidbody.h" -#include "RNA_access.h" - #ifdef WITH_BULLET /* ************************************** */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 168fa9ad120..13e9b7fb0c4 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -70,6 +70,7 @@ #include "BKE_fcurve.h" #include "BKE_freestyle.h" #include "BKE_global.h" +#include "BKE_gpencil.h" #include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_image.h" @@ -308,6 +309,19 @@ Scene *BKE_scene_copy(Scene *sce, int type) BKE_sequence_base_dupli_recursive(sce, scen, &scen->ed->seqbase, &sce->ed->seqbase, SEQ_DUPE_ALL); } } + + /* grease pencil */ + if (scen->gpd) { + if (type == SCE_COPY_FULL) { + scen->gpd = gpencil_data_duplicate(scen->gpd, false); + } + else if (type == SCE_COPY_EMPTY) { + scen->gpd = NULL; + } + else { + id_us_plus((ID *)scen->gpd); + } + } return scen; } @@ -1102,7 +1116,7 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce) Scene *sce_iter; int a, totscene; - if (sce->set == NULL) return 1; + if (sce->set == NULL) return true; totscene = BLI_listbase_count(&bmain->scene); for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) { @@ -1110,11 +1124,11 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce) if (a > totscene) { /* the tested scene gets zero'ed, that's typically current scene */ sce->set = NULL; - return 0; + return false; } } - return 1; + return true; } /* This function is needed to cope with fractional frames - including two Blender rendering features @@ -1838,13 +1852,13 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer * Scene *sce; if (act == -1) { - return 0; + return false; } else if ( (scene->r.layers.first == scene->r.layers.last) && (scene->r.layers.first == srl)) { /* ensure 1 layer is kept */ - return 0; + return false; } BLI_remlink(&scene->r.layers, srl); @@ -1866,7 +1880,7 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer * } } - return 1; + return true; } /* render simplification */ diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index b2296151cf7..ad4ed5a0b99 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -402,6 +402,23 @@ ARegion *BKE_area_find_region_active_win(ScrArea *sa) return NULL; } +/** + * \note, ideally we can get the area from the context, + * there are a few places however where this isn't practical. + */ +ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl) +{ + ScrArea *sa; + + for (sa = sc->areabase.first; sa; sa = sa->next) { + if (BLI_findindex(&sa->spacedata, sl) != -1) { + break; + } + } + + return sa; +} + /* note, using this function is generally a last resort, you really want to be * using the context when you can - campbell * -1 for any type */ diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index 4268b33cb14..a1135bfc54b 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -95,10 +95,10 @@ static unsigned int seq_hash_render_data(const SeqRenderData *a) static unsigned int seqcache_hashhash(const void *key_) { - const SeqCacheKey *key = (SeqCacheKey *) key_; + const SeqCacheKey *key = key_; unsigned int rval = seq_hash_render_data(&key->context); - rval ^= *(unsigned int *) &key->cfra; + rval ^= *(const unsigned int *) &key->cfra; rval += key->type; rval ^= ((intptr_t) key->seq) << 6; @@ -107,8 +107,8 @@ static unsigned int seqcache_hashhash(const void *key_) static bool seqcache_hashcmp(const void *a_, const void *b_) { - const SeqCacheKey *a = (SeqCacheKey *) a_; - const SeqCacheKey *b = (SeqCacheKey *) b_; + const SeqCacheKey *a = a_; + const SeqCacheKey *b = b_; return ((a->seq != b->seq) || (a->cfra != b->cfra) || diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 9a144ec8e44..b43e481d97d 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -515,24 +515,22 @@ void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixe /*********************** sequencer pipeline functions *************************/ -SeqRenderData BKE_sequencer_new_render_data(EvaluationContext *eval_ctx, - Main *bmain, Scene *scene, int rectx, int recty, - int preview_render_size) -{ - SeqRenderData rval; - - rval.bmain = bmain; - rval.scene = scene; - rval.rectx = rectx; - rval.recty = recty; - rval.preview_render_size = preview_render_size; - rval.motion_blur_samples = 0; - rval.motion_blur_shutter = 0; - rval.eval_ctx = eval_ctx; - rval.skip_cache = false; - rval.is_proxy_render = false; - - return rval; +void BKE_sequencer_new_render_data( + EvaluationContext *eval_ctx, + Main *bmain, Scene *scene, int rectx, int recty, + int preview_render_size, + SeqRenderData *r_context) +{ + r_context->eval_ctx = eval_ctx; + r_context->bmain = bmain; + r_context->scene = scene; + r_context->rectx = rectx; + r_context->recty = recty; + r_context->preview_render_size = preview_render_size; + r_context->motion_blur_samples = 0; + r_context->motion_blur_shutter = 0; + r_context->skip_cache = false; + r_context->is_proxy_render = false; } /* ************************* iterator ************************** */ @@ -892,7 +890,6 @@ void BKE_sequencer_sort(Scene *scene) Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq, *seqt; - if (ed == NULL) return; @@ -1453,8 +1450,8 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c return NULL; } - /* proxies are generated in default color space */ - seq->strip->proxy->anim = openanim(name, IB_rect, 0, NULL); + seq->strip->proxy->anim = openanim(name, IB_rect, 0, + seq->strip->colorspace_settings.name); } if (seq->strip->proxy->anim == NULL) { return NULL; @@ -1490,20 +1487,25 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i int quality; int rectx, recty; int ok; - ImBuf *ibuf; + ImBuf *ibuf_tmp, *ibuf; if (!seq_proxy_get_fname(seq, cfra, proxy_render_size, name)) { return; } - ibuf = seq_render_strip(context, seq, cfra); + ibuf_tmp = seq_render_strip(context, seq, cfra); - rectx = (proxy_render_size * ibuf->x) / 100; - recty = (proxy_render_size * ibuf->y) / 100; + rectx = (proxy_render_size * ibuf_tmp->x) / 100; + recty = (proxy_render_size * ibuf_tmp->y) / 100; - if (ibuf->x != rectx || ibuf->y != recty) { + if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) { + ibuf = IMB_dupImBuf(ibuf_tmp); + IMB_freeImBuf(ibuf_tmp); IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty); } + else { + ibuf = ibuf_tmp; + } /* depth = 32 is intentionally left in, otherwise ALPHA channels * won't work... */ @@ -1589,9 +1591,12 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho /* fail safe code */ - render_context = BKE_sequencer_new_render_data(bmain->eval_ctx, bmain, context->scene, - (scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f, - (scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100); + BKE_sequencer_new_render_data( + bmain->eval_ctx, bmain, context->scene, + (scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f, + (scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100, + &render_context); + render_context.skip_cache = true; render_context.is_proxy_render = true; @@ -2525,6 +2530,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq int do_seq; // bool have_seq = false; /* UNUSED */ bool have_comp = false; + bool use_gpencil = true; Scene *scene; int is_thread_main = BLI_thread_is_main(); @@ -2549,6 +2555,10 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq BKE_scene_camera_switch_update(scene); camera = scene->camera; } + + if (seq->flag & SEQ_SCENE_NO_GPENCIL) { + use_gpencil = false; + } if (have_comp == false && camera == NULL) { scene->r.cfra = oldcfra; @@ -2582,7 +2592,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq ibuf = sequencer_view3d_cb(scene, camera, width, height, IB_rect, context->scene->r.seq_prev_type, (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0, - true, scene->r.alphamode, err_out); + use_gpencil, true, scene->r.alphamode, err_out); if (ibuf == NULL) { fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out); } @@ -3411,7 +3421,7 @@ static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *cha /* recurs downwards to see if this seq depends on the changed seq */ if (seq == NULL) - return 0; + return false; if (seq == changed_seq) free_imbuf = true; @@ -4675,3 +4685,70 @@ bool BKE_sequence_is_valid_check(Sequence *seq) return true; } +int BKE_sequencer_find_next_prev_edit( + Scene *scene, int cfra, const short side, + const bool do_skip_mute, const bool do_center, const bool do_unselected) +{ + Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq; + + int dist, best_dist, best_frame = cfra; + int seq_frames[2], seq_frames_tot; + + /* in case where both is passed, frame just finds the nearest end while frame_left the nearest start */ + + best_dist = MAXFRAME * 2; + + if (ed == NULL) return cfra; + + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + int i; + + if (do_skip_mute && (seq->flag & SEQ_MUTE)) { + continue; + } + + if (do_unselected && (seq->flag & SELECT)) + continue; + + if (do_center) { + seq_frames[0] = (seq->startdisp + seq->enddisp) / 2; + seq_frames_tot = 1; + } + else { + seq_frames[0] = seq->startdisp; + seq_frames[1] = seq->enddisp; + + seq_frames_tot = 2; + } + + for (i = 0; i < seq_frames_tot; i++) { + const int seq_frame = seq_frames[i]; + + dist = MAXFRAME * 2; + + switch (side) { + case SEQ_SIDE_LEFT: + if (seq_frame < cfra) { + dist = cfra - seq_frame; + } + break; + case SEQ_SIDE_RIGHT: + if (seq_frame > cfra) { + dist = seq_frame - cfra; + } + break; + case SEQ_SIDE_BOTH: + dist = abs(seq_frame - cfra); + break; + } + + if (dist < best_dist) { + best_frame = seq_frame; + best_dist = dist; + } + } + } + + return best_frame; +} diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index d2a4d15a2c6..d91818615f3 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -52,7 +52,6 @@ #include "BKE_deform.h" #include "BKE_mesh.h" /* for OMP limits. */ #include "BKE_subsurf.h" -#include "BKE_editmesh.h" #include "BLI_strict_flags.h" diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index cf3dc67e7bd..a996da5915e 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -62,6 +62,7 @@ #include "DNA_scene_types.h" #include "DNA_smoke_types.h" +#include "BKE_appdir.h" #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_bvhutils.h" @@ -207,7 +208,7 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[ /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */ BLI_lock_thread(LOCK_FFTW); - sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BLI_temp_dir_session(), use_fire, use_colors); + sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors); BLI_unlock_thread(LOCK_FFTW); @@ -953,7 +954,7 @@ static bool subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int /* if other is dynamic paint canvas, don't update */ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN)) - return 1; + return true; /* if object has parents, update them too */ if (parent_recursion) { @@ -965,7 +966,7 @@ static bool subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int /* skip subframe if object is parented * to vertex of a dynamic paint canvas */ if (is_domain && (ob->partype == PARVERT1 || ob->partype == PARVERT3)) - return 0; + return false; /* also update constraint targets */ for (con = ob->constraints.first; con; con = con->next) { @@ -1011,7 +1012,7 @@ static bool subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int BKE_pose_where_is(scene, ob); } - return 0; + return false; } /********************************************************** @@ -1424,7 +1425,7 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke static void sample_derivedmesh( SmokeFlowSettings *sfs, MVert *mvert, MTFace *tface, MFace *mface, - float *influence_map, float *velocity_map, int index, int base_res[3], float flow_center[3], + float *influence_map, float *velocity_map, int index, const int base_res[3], float flow_center[3], BVHTreeFromMesh *treeData, const float ray_start[3], const float *vert_vel, bool has_velocity, int defgrp_index, MDeformVert *dvert, float x, float y, float z) { diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index da6ead06d98..88720d5fcb7 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_threads.h" #include "DNA_anim_types.h" #include "DNA_object_types.h" @@ -116,6 +117,12 @@ void BKE_sound_free(bSound *sound) } sound_free_waveform(sound); + + if (sound->mutex) { + BLI_mutex_free(sound->mutex); + sound->mutex = NULL; + } + #endif /* WITH_AUDASPACE */ } @@ -296,12 +303,6 @@ void sound_cache(bSound *sound) sound->playback_handle = sound->handle; } -void sound_cache_notifying(struct Main *main, bSound *sound) -{ - sound_cache(sound); - sound_update_sequencer(main, sound); -} - void sound_delete_cache(bSound *sound) { sound->flags &= ~SOUND_FLAGS_CACHING; @@ -672,30 +673,55 @@ int sound_scene_playing(struct Scene *scene) void sound_free_waveform(bSound *sound) { - if (sound->waveform) { - MEM_freeN(((SoundWaveform *)sound->waveform)->data); - MEM_freeN(sound->waveform); + SoundWaveform *waveform = sound->waveform; + if (waveform) { + if (waveform->data) { + MEM_freeN(waveform->data); + } + MEM_freeN(waveform); } sound->waveform = NULL; } -void sound_read_waveform(bSound *sound) +void sound_read_waveform(bSound *sound, short *stop) { - AUD_SoundInfo info; - - info = AUD_getInfo(sound->playback_handle); + AUD_SoundInfo info = AUD_getInfo(sound->playback_handle); + SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), + "SoundWaveform"); if (info.length > 0) { - SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform"); int length = info.length * SOUND_WAVE_SAMPLES_PER_SECOND; - + waveform->data = MEM_mallocN(length * sizeof(float) * 3, "SoundWaveform.samples"); - waveform->length = AUD_readSound(sound->playback_handle, waveform->data, length, SOUND_WAVE_SAMPLES_PER_SECOND); + waveform->length = AUD_readSound(sound->playback_handle, waveform->data, length, SOUND_WAVE_SAMPLES_PER_SECOND, stop); + } + else { + /* Create an empty waveform here if the sound couldn't be + * read. This indicates that reading the waveform is "done", + * whereas just setting sound->waveform to NULL causes other + * code to think the waveform still needs to be created. */ + waveform->data = NULL; + waveform->length = 0; + } - sound_free_waveform(sound); - sound->waveform = waveform; + if (*stop) { + if (waveform->data) { + MEM_freeN(waveform->data); + } + MEM_freeN(waveform); + BLI_mutex_lock(sound->mutex); + sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + BLI_mutex_unlock(sound->mutex); + return; } + + sound_free_waveform(sound); + + BLI_mutex_lock(sound->mutex); + sound->waveform = waveform; + sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + BLI_mutex_unlock(sound->mutex); } void sound_update_scene(Main *bmain, struct Scene *scene) @@ -830,7 +856,7 @@ void sound_stop_scene(struct Scene *UNUSED(scene)) {} void sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {} float sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; } int sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; } -void sound_read_waveform(struct bSound *UNUSED(sound)) {} +void sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); } void sound_init_main(struct Main *UNUSED(bmain)) {} void sound_set_cfra(int UNUSED(cfra)) {} void sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {} diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index 08daa09cc85..b11d0ae03b0 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -67,6 +67,10 @@ Speaker *BKE_speaker_copy(Speaker *spk) if (spkn->sound) spkn->sound->id.us++; + if (spk->id.lib) { + BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id); + } + return spkn; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index f03e2eaff4a..961a66f853b 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -41,7 +41,6 @@ #include "MEM_guardedalloc.h" -#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -66,8 +65,6 @@ #include "BKE_scene.h" #include "BKE_subsurf.h" -#include "PIL_time.h" - #ifndef USE_DYNSIZE # include "BLI_array.h" #endif @@ -75,7 +72,6 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_glew.h" -#include "GPU_material.h" #include "CCGSubSurf.h" @@ -411,7 +407,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, CCGFace **faceMap; MTFace *tf; MLoopUV *mluv; - CCGFaceIterator *fi; + CCGFaceIterator fi; int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S; MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, n); /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with @@ -438,11 +434,10 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, /* make a map from original faces to CCGFaces */ faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv"); - for (fi = ccgSubSurf_getFaceIterator(uvss); !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(fi); + for (ccgSubSurf_initFaceIterator(uvss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(&fi); faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))] = f; } - ccgFaceIterator_free(fi); /* load coordinates from uvss into tface */ tf = tface; @@ -699,9 +694,9 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3]) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; - CCGVertIterator *vi; - CCGEdgeIterator *ei; - CCGFaceIterator *fi; + CCGVertIterator vi; + CCGEdgeIterator ei; + CCGFaceIterator fi; CCGKey key; int i, edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); @@ -711,25 +706,23 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3]) if (!ccgSubSurf_getNumVerts(ss)) r_min[0] = r_min[1] = r_min[2] = r_max[0] = r_max[1] = r_max[2] = 0.0; - for (vi = ccgSubSurf_getVertIterator(ss); !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { - CCGVert *v = ccgVertIterator_getCurrent(vi); + for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { + CCGVert *v = ccgVertIterator_getCurrent(&vi); float *co = ccgSubSurf_getVertData(ss, v); minmax_v3_v3v3(co, r_min, r_max); } - ccgVertIterator_free(vi); - for (ei = ccgSubSurf_getEdgeIterator(ss); !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); for (i = 0; i < edgeSize; i++) minmax_v3_v3v3(CCG_elem_offset_co(&key, edgeData, i), r_min, r_max); } - ccgEdgeIterator_free(ei); - for (fi = ccgSubSurf_getFaceIterator(ss); !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(fi); + for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(&fi); int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++) { @@ -740,7 +733,6 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3]) minmax_v3_v3v3(CCG_grid_elem_co(&key, faceGridData, x, y), r_min, r_max); } } - ccgFaceIterator_free(fi); } static int ccgDM_getNumVerts(DerivedMesh *dm) @@ -1067,8 +1059,9 @@ void subsurf_copy_grid_hidden(DerivedMesh *dm, const MPoly *mpoly, const MDisps *md = &mdisps[mpoly[i].loopstart + j]; int hidden_gridsize = BKE_ccg_gridsize(md->level); int factor = BKE_ccg_factor(level, md->level); + BLI_bitmap *hidden = md->hidden; - if (!md->hidden) + if (!hidden) continue; for (y = 0; y < gridSize; y++) { @@ -1077,7 +1070,7 @@ void subsurf_copy_grid_hidden(DerivedMesh *dm, const MPoly *mpoly, vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize); offset = (y * factor) * hidden_gridsize + (x * factor); - if (BLI_BITMAP_TEST(md->hidden, offset)) + if (BLI_BITMAP_TEST(hidden, offset)) mvert[vndx].flag |= ME_HIDE; } } @@ -1433,9 +1426,9 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) int edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); int i; - CCGVertIterator *vi; - CCGEdgeIterator *ei; - CCGFaceIterator *fi; + CCGVertIterator vi; + CCGEdgeIterator ei; + CCGFaceIterator fi; CCGFace **faceMap2; CCGEdge **edgeMap2; CCGVert **vertMap2; @@ -1443,30 +1436,27 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) totvert = ccgSubSurf_getNumVerts(ss); vertMap2 = MEM_mallocN(totvert * sizeof(*vertMap2), "vertmap"); - for (vi = ccgSubSurf_getVertIterator(ss); !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { - CCGVert *v = ccgVertIterator_getCurrent(vi); + for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { + CCGVert *v = ccgVertIterator_getCurrent(&vi); vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))] = v; } - ccgVertIterator_free(vi); totedge = ccgSubSurf_getNumEdges(ss); edgeMap2 = MEM_mallocN(totedge * sizeof(*edgeMap2), "edgemap"); - for (ei = ccgSubSurf_getEdgeIterator(ss), i = 0; !ccgEdgeIterator_isStopped(ei); i++, ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (ccgSubSurf_initEdgeIterator(ss, &ei), i = 0; !ccgEdgeIterator_isStopped(&ei); i++, ccgEdgeIterator_next(&ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e; } - ccgEdgeIterator_free(ei); totface = ccgSubSurf_getNumFaces(ss); faceMap2 = MEM_mallocN(totface * sizeof(*faceMap2), "facemap"); - for (fi = ccgSubSurf_getFaceIterator(ss); !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(fi); + for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(&fi); faceMap2[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))] = f; } - ccgFaceIterator_free(fi); i = 0; for (index = 0; index < totface; index++) { @@ -1516,12 +1506,12 @@ static void ccgDM_foreachMappedVert( DMForeachFlag flag) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGVertIterator *vi; + CCGVertIterator vi; CCGKey key; CCG_key_top_level(&key, ccgdm->ss); - for (vi = ccgSubSurf_getVertIterator(ccgdm->ss); !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { - CCGVert *v = ccgVertIterator_getCurrent(vi); + for (ccgSubSurf_initVertIterator(ccgdm->ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { + CCGVert *v = ccgVertIterator_getCurrent(&vi); const int index = ccgDM_getVertMapIndex(ccgdm->ss, v); if (index != -1) { @@ -1530,8 +1520,6 @@ static void ccgDM_foreachMappedVert( func(userData, index, CCG_elem_co(&key, vd), no, NULL); } } - - ccgVertIterator_free(vi); } static void ccgDM_foreachMappedEdge( @@ -1541,14 +1529,14 @@ static void ccgDM_foreachMappedEdge( { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; - CCGEdgeIterator *ei; + CCGEdgeIterator ei; CCGKey key; int i, edgeSize = ccgSubSurf_getEdgeSize(ss); CCG_key_top_level(&key, ss); - for (ei = ccgSubSurf_getEdgeIterator(ss); !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); const int index = ccgDM_getEdgeMapIndex(ss, e); if (index != -1) { @@ -1558,8 +1546,6 @@ static void ccgDM_foreachMappedEdge( } } } - - ccgEdgeIterator_free(ei); } static void ccgDM_foreachMappedLoop( @@ -1597,28 +1583,26 @@ static void ccgDM_drawVerts(DerivedMesh *dm) CCGSubSurf *ss = ccgdm->ss; int edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); - CCGVertIterator *vi; - CCGEdgeIterator *ei; - CCGFaceIterator *fi; + CCGVertIterator vi; + CCGEdgeIterator ei; + CCGFaceIterator fi; glBegin(GL_POINTS); - for (vi = ccgSubSurf_getVertIterator(ss); !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { - CCGVert *v = ccgVertIterator_getCurrent(vi); + for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { + CCGVert *v = ccgVertIterator_getCurrent(&vi); glVertex3fv(ccgSubSurf_getVertData(ss, v)); } - ccgVertIterator_free(vi); - for (ei = ccgSubSurf_getEdgeIterator(ss); !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); int x; for (x = 1; x < edgeSize - 1; x++) glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x)); } - ccgEdgeIterator_free(ei); - for (fi = ccgSubSurf_getFaceIterator(ss); !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(fi); + for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(&fi); int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); glVertex3fv(ccgSubSurf_getFaceCenterData(f)); @@ -1630,7 +1614,6 @@ static void ccgDM_drawVerts(DerivedMesh *dm) for (x = 1; x < gridSize - 1; x++) glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y)); } - ccgFaceIterator_free(fi); glEnd(); } @@ -2289,7 +2272,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm, static void ccgDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, - DMSetDrawOptions drawParamsMapped, + DMSetDrawOptionsMappedTex drawParamsMapped, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag flag) { @@ -2361,7 +2344,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, if (drawParams) draw_option = drawParams(tf, (mcol != NULL), mat_nr); else if (index != ORIGINDEX_NONE) - draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index) : DM_DRAW_OPTION_NORMAL; + draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL; else draw_option = GPU_enable_material(mat_nr, NULL) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP; @@ -2530,7 +2513,7 @@ static void ccgDM_drawFacesTex(DerivedMesh *dm, } static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, + DMSetDrawOptionsMappedTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag flag) { @@ -2586,6 +2569,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, DMFlagMat *faceFlags = ccgdm->faceFlags; int useColors = flag & DM_DRAW_USE_COLORS; int gridFaces = gridSize - 1, totface; + int prev_mat_nr = -1; CCG_key_top_level(&key, ss); @@ -2626,9 +2610,16 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, { DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - if (index == ORIGINDEX_NONE) - draw_option = setMaterial(faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1, NULL); /* XXX, no faceFlags no material */ - else if (setDrawOptions) + if (setMaterial) { + int mat_nr = faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1; + + if (mat_nr != prev_mat_nr) { + setMaterial(mat_nr, NULL); /* XXX, no faceFlags no material */ + prev_mat_nr = mat_nr; + } + } + + if (setDrawOptions && (index != ORIGINDEX_NONE)) draw_option = setDrawOptions(userData, index); if (draw_option != DM_DRAW_OPTION_SKIP) { @@ -2745,15 +2736,15 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm, { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; - CCGEdgeIterator *ei; + CCGEdgeIterator ei; CCGKey key; int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); CCG_key_top_level(&key, ss); ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); - for (ei = ccgSubSurf_getEdgeIterator(ss); !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); int index = ccgDM_getEdgeMapIndex(ss, e); @@ -2771,8 +2762,6 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm, } glEnd(); } - - ccgEdgeIterator_free(ei); } static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, @@ -2783,14 +2772,14 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; - CCGEdgeIterator *ei; + CCGEdgeIterator ei; int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); CCG_key_top_level(&key, ss); ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); - for (ei = ccgSubSurf_getEdgeIterator(ss); !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); int index = ccgDM_getEdgeMapIndex(ss, e); @@ -2809,8 +2798,6 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, } glEnd(); } - - ccgEdgeIterator_free(ei); } static void ccgDM_foreachMappedFaceCenter( @@ -2822,12 +2809,12 @@ static void ccgDM_foreachMappedFaceCenter( CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; - CCGFaceIterator *fi; + CCGFaceIterator fi; CCG_key_top_level(&key, ss); - for (fi = ccgSubSurf_getFaceIterator(ss); !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(fi); + for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(&fi); const int index = ccgDM_getFaceMapIndex(ss, f); if (index != -1) { @@ -2837,8 +2824,6 @@ static void ccgDM_foreachMappedFaceCenter( func(userData, index, CCG_elem_co(&key, vd), no); } } - - ccgFaceIterator_free(fi); } static void ccgDM_release(DerivedMesh *dm) @@ -3434,9 +3419,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, DerivedMesh *dm) { CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); - CCGVertIterator *vi; - CCGEdgeIterator *ei; - CCGFaceIterator *fi; + CCGVertIterator vi; + CCGEdgeIterator ei; + CCGFaceIterator fi; int index, totvert, totedge, totface; int i; int vertNum, edgeNum, faceNum; @@ -3569,30 +3554,27 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, totvert = ccgSubSurf_getNumVerts(ss); ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap"); - for (vi = ccgSubSurf_getVertIterator(ss); !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { - CCGVert *v = ccgVertIterator_getCurrent(vi); + for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { + CCGVert *v = ccgVertIterator_getCurrent(&vi); ccgdm->vertMap[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))].vert = v; } - ccgVertIterator_free(vi); totedge = ccgSubSurf_getNumEdges(ss); ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap"); - for (ei = ccgSubSurf_getEdgeIterator(ss); !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); ccgdm->edgeMap[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e; } - ccgEdgeIterator_free(ei); totface = ccgSubSurf_getNumFaces(ss); ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap"); - for (fi = ccgSubSurf_getFaceIterator(ss); !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(fi); + for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(&fi); ccgdm->faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))].face = f; } - ccgFaceIterator_free(fi); ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), "reverseFaceMap"); @@ -3997,13 +3979,13 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3]) */ CCGSubSurf *ss = _getSubSurf(NULL, 1, 3, CCG_USE_ARENA); float edge_sum[3], face_sum[3]; - CCGVertIterator *vi; + CCGVertIterator vi; DerivedMesh *dm = CDDM_from_mesh(me); ss_sync_from_derivedmesh(ss, dm, NULL, 0); - for (vi = ccgSubSurf_getVertIterator(ss); !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { - CCGVert *v = ccgVertIterator_getCurrent(vi); + for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { + CCGVert *v = ccgVertIterator_getCurrent(&vi); int idx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); int N = ccgSubSurf_getVertNumEdges(v); int numFaces = ccgSubSurf_getVertNumFaces(v); @@ -4032,7 +4014,6 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3]) r_positions[idx][1] = (co[1] * N * N + edge_sum[1] * 4 + face_sum[1]) / (N * (N + 5)); r_positions[idx][2] = (co[2] * N * N + edge_sum[2] * 4 + face_sum[2]) / (N * (N + 5)); } - ccgVertIterator_free(vi); ccgSubSurf_free(ss); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index b45d9b418ed..3a311bfb23b 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -369,8 +369,8 @@ int BKE_text_reload(Text *text) buffer = MEM_mallocN(len, "text_buffer"); - // under windows fread can return less then len bytes because - // of CR stripping + /* under windows fread can return less than len bytes because + * of CR stripping */ len = fread(buffer, 1, len, fp); fclose(fp); @@ -425,8 +425,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const fseek(fp, 0L, SEEK_SET); buffer = MEM_mallocN(len, "text_buffer"); - // under windows fread can return less then len bytes because - // of CR stripping + /* under windows fread can return less than len bytes because + * of CR stripping */ len = fread(buffer, 1, len, fp); fclose(fp); @@ -446,7 +446,7 @@ Text *BKE_text_load(Main *bmain, const char *file, const char *relpath) return BKE_text_load_ex(bmain, file, relpath, false); } -Text *BKE_text_copy(Text *ta) +Text *BKE_text_copy(Main *bmain, Text *ta) { Text *tan; TextLine *line, *tmp; @@ -455,8 +455,7 @@ Text *BKE_text_copy(Text *ta) /* file name can be NULL */ if (ta->name) { - tan->name = MEM_mallocN(strlen(ta->name) + 1, "text_name"); - strcpy(tan->name, ta->name); + tan->name = BLI_strdup(ta->name); } else { tan->name = NULL; @@ -490,6 +489,10 @@ Text *BKE_text_copy(Text *ta) init_undo_text(tan); + if (ta->id.lib) { + BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id); + } + return tan; } @@ -1515,7 +1518,7 @@ static bool max_undo_test(Text *text, int x) /* XXX error("Undo limit reached, buffer cleared\n"); */ MEM_freeN(text->undo_buf); init_undo_text(text); - return 0; + return false; } else { void *tmp = text->undo_buf; @@ -1526,7 +1529,7 @@ static bool max_undo_test(Text *text, int x) } } - return 1; + return true; } #if 0 /* UNUSED */ @@ -2550,13 +2553,13 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs) if (add == '\n') { txt_split_curline(text); - return 1; + return true; } /* insert spaces rather than tabs */ if (add == '\t' && replace_tabs) { txt_convert_tab_to_spaces(text); - return 1; + return true; } txt_delete_sel(text); @@ -2605,7 +2608,7 @@ bool txt_replace_char(Text *text, unsigned int add) size_t del_size = 0, add_size; char ch[BLI_UTF8_MAX]; - if (!text->curl) return 0; + if (!text->curl) return false; /* If text is selected or we're at the end of the line just use txt_add_char */ if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') { @@ -2644,7 +2647,7 @@ bool txt_replace_char(Text *text, unsigned int add) text->curc += add_size; txt_pop_sel(text); } - return 1; + return true; } void txt_indent(Text *text) @@ -2979,37 +2982,37 @@ bool text_check_delim(const char ch) for (a = 0; a < (sizeof(delims) - 1); a++) { if (ch == delims[a]) - return 1; + return true; } - return 0; + return false; } bool text_check_digit(const char ch) { - if (ch < '0') return 0; - if (ch <= '9') return 1; - return 0; + if (ch < '0') return false; + if (ch <= '9') return true; + return false; } bool text_check_identifier(const char ch) { - if (ch < '0') return 0; - if (ch <= '9') return 1; - if (ch < 'A') return 0; - if (ch <= 'Z' || ch == '_') return 1; - if (ch < 'a') return 0; - if (ch <= 'z') return 1; - return 0; + if (ch < '0') return false; + if (ch <= '9') return true; + if (ch < 'A') return false; + if (ch <= 'Z' || ch == '_') return true; + if (ch < 'a') return false; + if (ch <= 'z') return true; + return false; } bool text_check_identifier_nodigit(const char ch) { - if (ch <= '9') return 0; - if (ch < 'A') return 0; - if (ch <= 'Z' || ch == '_') return 1; - if (ch < 'a') return 0; - if (ch <= 'z') return 1; - return 0; + if (ch <= '9') return false; + if (ch < 'A') return false; + if (ch <= 'Z' || ch == '_') return true; + if (ch < 'a') return false; + if (ch <= 'z') return true; + return false; } #ifndef WITH_PYTHON @@ -3027,8 +3030,8 @@ int text_check_identifier_nodigit_unicode(const unsigned int ch) bool text_check_whitespace(const char ch) { if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') - return 1; - return 0; + return true; + return false; } int text_find_identifier_start(const char *str, int i) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index b1981a3a804..dce6584bdfe 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -37,7 +37,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_kdopbvh.h" #include "BLI_utildefines.h" @@ -328,7 +327,7 @@ bool do_colorband(const ColorBand *coba, float in, float out[4]) int ipotype; int a; - if (coba == NULL || coba->tot == 0) return 0; + if (coba == NULL || coba->tot == 0) return false; cbd1 = coba->data; @@ -464,7 +463,7 @@ bool do_colorband(const ColorBand *coba, float in, float out[4]) } } } - return 1; /* OK */ + return true; /* OK */ } void colorband_table_RGBA(ColorBand *coba, float **array, int *size) @@ -756,6 +755,8 @@ void default_mtex(MTex *mtex) mtex->fieldfac = 1.0f; mtex->normapspace = MTEX_NSPACE_TANGENT; mtex->brush_map_mode = MTEX_MAP_MODE_TILED; + mtex->random_angle = 2.0f * M_PI; + mtex->brush_angle_mode = 0; } @@ -843,6 +844,10 @@ Tex *BKE_texture_copy(Tex *tex) texn->nodetree = ntreeCopyTree(tex->nodetree); } + if (tex->id.lib) { + BKE_id_lib_local_paths(G.main, tex->id.lib, &texn->id); + } + return texn; } @@ -1305,7 +1310,7 @@ bool has_current_material_texture(Material *ma) node = nodeGetActiveID(ma->nodetree, ID_TE); if (node) - return 1; + return true; } return (ma != NULL); @@ -1599,17 +1604,17 @@ void BKE_free_oceantex(struct OceanTex *ot) bool BKE_texture_dependsOnTime(const struct Tex *texture) { if (texture->ima && BKE_image_is_animated(texture->ima)) { - return 1; + return true; } else if (texture->adt) { /* assume anything in adt means the texture is animated */ - return 1; + return true; } else if (texture->type == TEX_NOISE) { /* noise always varies with time */ - return 1; + return true; } - return 0; + return false; } /* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 1613b0c5a78..d580c184a8b 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -1456,6 +1456,35 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTra return plane_marker; } +void BKE_tracking_plane_marker_get_subframe_corners(MovieTrackingPlaneTrack *plane_track, + float framenr, + float corners[4][2]) +{ + MovieTrackingPlaneMarker *marker = BKE_tracking_plane_marker_get(plane_track, (int)framenr); + MovieTrackingPlaneMarker *marker_last = plane_track->markers + (plane_track->markersnr - 1); + int i; + if (marker != marker_last) { + MovieTrackingPlaneMarker *marker_next = marker + 1; + if (marker_next->framenr == marker->framenr + 1) { + float fac = (framenr - (int) framenr) / (marker_next->framenr - marker->framenr); + for (i = 0; i < 4; ++i) { + interp_v2_v2v2(corners[i], marker->corners[i], + marker_next->corners[i], fac); + } + } + else { + for (i = 0; i < 4; ++i) { + copy_v2_v2(corners[i], marker->corners[i]); + } + } + } + else { + for (i = 0; i < 4; ++i) { + copy_v2_v2(corners[i], marker->corners[i]); + } + } +} + /*********************** Object *************************/ MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char *name) diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 55b8f0bd3ab..22a380ea835 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -383,13 +383,17 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) int frame = BKE_movieclip_remap_scene_to_clip_frame( context->clips[options->clip_index], context->user.framenr); + bool has_marker; - if (libmv_autoTrackGetMarker(context->autotrack, - options->clip_index, - frame, - options->track_index, - &libmv_current_marker)) - { + BLI_spin_lock(&context->spin_lock); + has_marker = libmv_autoTrackGetMarker(context->autotrack, + options->clip_index, + frame, + options->track_index, + &libmv_current_marker); + BLI_spin_unlock(&context->spin_lock); + + if (has_marker) { if (!tracking_check_marker_margin(&libmv_current_marker, options->track->margin, context->frame_width, @@ -427,7 +431,7 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) } else { options->is_failed = true; - options->failed_frame = frame; + options->failed_frame = frame + frame_delta; } ok = true; } @@ -442,11 +446,11 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) void BKE_autotrack_context_sync(AutoTrackContext *context) { - int newframe = context->user.framenr, - frame_delta = context->backwards ? -1 : 1; + int newframe, frame_delta = context->backwards ? -1 : 1; int clip, frame; BLI_spin_lock(&context->spin_lock); + newframe = context->user.framenr; for (frame = context->sync_frame; frame != (context->backwards ? newframe - 1 : newframe + 1); frame += frame_delta) @@ -459,22 +463,18 @@ void BKE_autotrack_context_sync(AutoTrackContext *context) AutoTrackOptions *options = &context->options[track]; int track_frame = BKE_movieclip_remap_scene_to_clip_frame( context->clips[options->clip_index], frame); - if (options->is_failed) { - if (options->failed_frame == track_frame) { - MovieTrackingMarker *prev_marker = - BKE_tracking_marker_get_exact( - options->track, - frame); - if (prev_marker) { - marker = *prev_marker; - marker.framenr = context->backwards ? - track_frame - 1 : - track_frame + 1; - marker.flag |= MARKER_DISABLED; - BKE_tracking_marker_insert(options->track, &marker); - } + if (options->is_failed && options->failed_frame == track_frame) { + MovieTrackingMarker *prev_marker = + BKE_tracking_marker_get_exact(options->track, frame); + if (prev_marker) { + marker = *prev_marker; + marker.framenr = context->backwards ? + track_frame - 1 : + track_frame + 1; + marker.flag |= MARKER_DISABLED; + BKE_tracking_marker_insert(options->track, &marker); + continue; } - continue; } if (libmv_autoTrackGetMarker(context->autotrack, clip, diff --git a/source/blender/blenkernel/intern/tracking_detect.c b/source/blender/blenkernel/intern/tracking_detect.c index 62039b761e8..6df51b5441a 100644 --- a/source/blender/blenkernel/intern/tracking_detect.c +++ b/source/blender/blenkernel/intern/tracking_detect.c @@ -40,7 +40,6 @@ #include "BKE_tracking.h" #include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "libmv-capi.h" diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c index 09c95ae4321..dd7def16ca8 100644 --- a/source/blender/blenkernel/intern/tracking_region_tracker.c +++ b/source/blender/blenkernel/intern/tracking_region_tracker.c @@ -35,11 +35,8 @@ #include "MEM_guardedalloc.h" #include "DNA_movieclip_types.h" -#include "DNA_object_types.h" /* SELECT */ #include "BLI_utildefines.h" -#include "BLI_math.h" -#include "BLI_ghash.h" #include "BLI_threads.h" #include "BKE_tracking.h" @@ -116,7 +113,7 @@ static float *track_get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, return gray_pixels; } -/* Get image boffer for a given frame +/* Get image buffer for a given frame * * Frame is in clip space. */ diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c index 6d4e7efa815..d5e2f24e9ed 100644 --- a/source/blender/blenkernel/intern/tracking_solver.c +++ b/source/blender/blenkernel/intern/tracking_solver.c @@ -391,7 +391,7 @@ MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip last_marker--; } - if (first < track->markersnr - 1) + if (first <= track->markersnr - 1) sfra = min_ii(sfra, first_marker->framenr); if (last >= 0) @@ -509,6 +509,11 @@ bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieT MovieTrackingReconstruction *reconstruction; MovieTrackingObject *object; + if (!libmv_reconstructionIsValid(context->reconstruction)) { + printf("Failed solve the motion: most likely there are no good keyframes\n"); + return false; + } + tracks_map_merge(context->tracks_map, tracking); BKE_tracking_dopesheet_tag_update(tracking); diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 17e4a3c73c3..882a6fabef1 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -172,8 +172,7 @@ void tracks_map_merge(TracksMap *map, MovieTracking *tracking) MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track); /* Update old-new track mapping */ - BLI_ghash_remove(map->hash, track, NULL, NULL); - BLI_ghash_insert(map->hash, track, new_track); + BLI_ghash_reinsert(map->hash, track, new_track, NULL, NULL); BLI_addtail(&tracks, new_track); } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 8e3c92314e6..699e0d34161 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -38,8 +38,8 @@ #include "DNA_scene_types.h" #include "DNA_texture_types.h" -#include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "BKE_animsys.h" #include "BKE_global.h" @@ -49,6 +49,8 @@ #include "BKE_node.h" #include "BKE_world.h" +#include "GPU_material.h" + void BKE_world_free_ex(World *wrld, bool do_id_user) { MTex *mtex; @@ -69,6 +71,9 @@ void BKE_world_free_ex(World *wrld, bool do_id_user) MEM_freeN(wrld->nodetree); } + if (wrld->gpumaterial.first) + GPU_material_free(&wrld->gpumaterial); + BKE_icon_delete((struct ID *)wrld); wrld->id.icon_id = 0; } @@ -134,6 +139,12 @@ World *BKE_world_copy(World *wrld) if (wrld->preview) wrldn->preview = BKE_previewimg_copy(wrld->preview); + BLI_listbase_clear(&wrldn->gpumaterial); + + if (wrld->id.lib) { + BKE_id_lib_local_paths(G.main, wrld->id.lib, &wrldn->id); + } + return wrldn; } @@ -158,6 +169,8 @@ World *localize_world(World *wrld) wrldn->preview = NULL; + BLI_listbase_clear(&wrldn->gpumaterial); + return wrldn; } diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index aef44993912..8a6a0438b84 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -80,7 +80,9 @@ static void filepath_avi(char *string, RenderData *rd); # include "BKE_writeffmpeg.h" #endif -#include "BKE_writeframeserver.h" +#ifdef WITH_FRAMESERVER +# include "BKE_writeframeserver.h" +#endif bMovieHandle *BKE_movie_handle_get(const char imtype) { diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 1fe5d345621..9737ef429cb 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -57,7 +57,6 @@ #include "BKE_sound.h" #include "BKE_writeffmpeg.h" -#include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "ffmpeg_compat.h" @@ -494,7 +493,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char * * For as long we don't allow editing properties in the interface * it's all good. bug if we allow editing them, we'll need to - * repace it with some smarter code which would port settings + * replace it with some smarter code which would port settings * from deprecated to new one. */ ffmpeg_set_expert_options(rd); @@ -599,8 +598,12 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex /* Keep lossless encodes in the RGB domain. */ if (codec_id == AV_CODEC_ID_HUFFYUV) { - /* HUFFYUV was PIX_FMT_YUV422P before */ - c->pix_fmt = PIX_FMT_RGB32; + if (rd->im_format.planes == R_IMF_PLANES_RGBA) { + c->pix_fmt = PIX_FMT_BGRA; + } + else { + c->pix_fmt = PIX_FMT_RGB32; + } } if (codec_id == AV_CODEC_ID_FFV1) { @@ -1629,6 +1632,12 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd) if (codec == AV_CODEC_ID_PNG) return true; + if (codec == AV_CODEC_ID_PNG) + return true; + + if (codec == AV_CODEC_ID_HUFFYUV) + return true; + #ifdef FFMPEG_FFV1_ALPHA_SUPPORTED if (codec == AV_CODEC_ID_FFV1) return true; diff --git a/source/blender/blenlib/BLI_astar.h b/source/blender/blenlib/BLI_astar.h new file mode 100644 index 00000000000..b99a2534d33 --- /dev/null +++ b/source/blender/blenlib/BLI_astar.h @@ -0,0 +1,98 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_ASTAR_H__ +#define __BLI_ASTAR_H__ + +/** \file BLI_astar.h + * \ingroup bli + * \brief An implementation of the A* (AStar) algorithm to solve shortest path problem. + */ + +#include "BLI_utildefines.h" + +#include "BLI_bitmap.h" + +/* -------------------------------------------------------------------- */ + +typedef struct BLI_AStarGNLink { + int nodes[2]; + float cost; + + void *custom_data; +} BLI_AStarGNLink; + +typedef struct BLI_AStarGNode { + struct ListBase neighbor_links; + + void *custom_data; +} BLI_AStarGNode; + +typedef struct BLI_AStarSolution { + /* Final 'most useful' data. */ + int steps; /* Number of steps (i.e. walked links) in path (nodes num, including start and end, is steps + 1). */ + int *prev_nodes; /* Store the path, in reversed order (from destination to source node), as indices. */ + BLI_AStarGNLink **prev_links; /* Indices are nodes' ones, as prev_nodes, but they map to relevant link. */ + + void *custom_data; + + /* Mostly runtime data. */ + BLI_bitmap *done_nodes; + float *g_costs; + int *g_steps; + + struct MemArena *mem; /* Memory arena. */ +} BLI_AStarSolution; + +typedef struct BLI_AStarGraph { + int node_num; + BLI_AStarGNode *nodes; + + void *custom_data; + + struct MemArena *mem; /* Memory arena. */ +} BLI_AStarGraph; + +void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data); +void BLI_astar_node_link_add( + BLI_AStarGraph *as_graph, const int node1_index, const int node2_index, const float cost, void *custom_data); +int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx); + +void BLI_astar_solution_init(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, void *custom_data); +void BLI_astar_solution_clear(BLI_AStarSolution *as_solution); +void BLI_astar_solution_free(BLI_AStarSolution *as_solution); + +typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link, + const int node_idx_curr, const int node_idx_next, const int node_idx_dst); + +void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data); +void BLI_astar_graph_free(BLI_AStarGraph *as_graph); +bool BLI_astar_graph_solve( + BLI_AStarGraph *as_graph, const int node_index_src, const int node_index_dst, astar_f_cost f_cost_cb, + BLI_AStarSolution *r_solution, const int max_steps); + +#endif /* __BLI_ASTAR_H__ */ diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h index 594bf89b667..60fc143a447 100644 --- a/source/blender/blenlib/BLI_bitmap.h +++ b/source/blender/blenlib/BLI_bitmap.h @@ -47,7 +47,7 @@ typedef unsigned int BLI_bitmap; /* size (in bytes) used to hold '_tot' bits */ #define BLI_BITMAP_SIZE(_tot) \ - (_BITMAP_NUM_BLOCKS(_tot) * sizeof(BLI_bitmap)) + ((size_t)(_BITMAP_NUM_BLOCKS(_tot)) * sizeof(BLI_bitmap)) /* allocate memory for a bitmap with '_tot' bits; free * with MEM_freeN() */ @@ -59,25 +59,30 @@ typedef unsigned int BLI_bitmap; #define BLI_BITMAP_NEW_ALLOCA(_tot) \ ((BLI_bitmap *)memset(alloca(BLI_BITMAP_SIZE(_tot)), 0, BLI_BITMAP_SIZE(_tot))) +/* Allocate using given MemArena */ +#define BLI_BITMAP_NEW_MEMARENA(_mem, _tot) \ + (CHECK_TYPE_INLINE(_mem, MemArena *), \ + ((BLI_bitmap *)BLI_memarena_calloc(_mem, BLI_BITMAP_SIZE(_tot)))) + /* get the value of a single bit at '_index' */ #define BLI_BITMAP_TEST(_bitmap, _index) \ - (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \ + (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ ((_bitmap)[(_index) >> _BITMAP_POWER] & \ (1u << ((_index) & _BITMAP_MASK)))) #define BLI_BITMAP_TEST_BOOL(_bitmap, _index) \ - (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \ + (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ (BLI_BITMAP_TEST(_bitmap, _index) != 0)) /* set the value of a single bit at '_index' */ #define BLI_BITMAP_ENABLE(_bitmap, _index) \ - (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \ + (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ ((_bitmap)[(_index) >> _BITMAP_POWER] |= \ (1u << ((_index) & _BITMAP_MASK)))) /* clear the value of a single bit at '_index' */ #define BLI_BITMAP_DISABLE(_bitmap, _index) \ - (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \ + (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ ((_bitmap)[(_index) >> _BITMAP_POWER] &= \ ~(1u << ((_index) & _BITMAP_MASK)))) diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h index 2f963cfac51..7cf524749c2 100644 --- a/source/blender/blenlib/BLI_callbacks.h +++ b/source/blender/blenlib/BLI_callbacks.h @@ -41,6 +41,7 @@ typedef enum { BLI_CB_EVT_FRAME_CHANGE_POST, BLI_CB_EVT_RENDER_PRE, BLI_CB_EVT_RENDER_POST, + BLI_CB_EVT_RENDER_WRITE, BLI_CB_EVT_RENDER_STATS, BLI_CB_EVT_RENDER_INIT, BLI_CB_EVT_RENDER_COMPLETE, diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h index 551569b066d..46c57772f64 100644 --- a/source/blender/blenlib/BLI_compiler_typecheck.h +++ b/source/blender/blenlib/BLI_compiler_typecheck.h @@ -51,9 +51,9 @@ })) #else -# define CHECK_TYPE(var, type) -# define CHECK_TYPE_PAIR(var_a, var_b) -# define CHECK_TYPE_PAIR_INLINE(var_a, var_b) (void)0 +# define CHECK_TYPE(var, type) { EXPR_NOP(var); }(void)0 +# define CHECK_TYPE_PAIR(var_a, var_b) { (EXPR_NOP(var_a), EXPR_NOP(var_b)); }(void)0 +# define CHECK_TYPE_PAIR_INLINE(var_a, var_b) (EXPR_NOP(var_a), EXPR_NOP(var_b)) #endif /* can be used in simple macros */ @@ -66,10 +66,15 @@ ((void)(((type)0) != (0 ? (val) : ((type)0)))) #endif -#define CHECK_TYPE_NONCONST(var) { \ - void *non_const = 0 ? (var) : NULL; \ - (void)non_const; \ -} (void)0 +#if defined(__GNUC__) || defined(__clang__) +# define CHECK_TYPE_NONCONST(var) __extension__ ({ \ + void *non_const = 0 ? (var) : NULL; \ + (void)non_const; \ +}) +#else +# define CHECK_TYPE_NONCONST(var) EXPR_NOP(var) +#endif + /** * CHECK_TYPE_ANY: handy macro, eg: diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h index a0455489d24..ded4b163f71 100644 --- a/source/blender/blenlib/BLI_edgehash.h +++ b/source/blender/blenlib/BLI_edgehash.h @@ -26,7 +26,6 @@ /** \file BLI_edgehash.h * \ingroup bli * \author Daniel Dunbar - * \brief A general unordered 2-int pair hash table ADT. */ #include "BLI_compiler_attrs.h" @@ -55,6 +54,9 @@ bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned in void *BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT; void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val_default) ATTR_WARN_UNUSED_RESULT; void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT; +bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp); + +void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT; bool BLI_edgehash_haskey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT; int BLI_edgehash_size(EdgeHash *eh) ATTR_WARN_UNUSED_RESULT; void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP valfreefp, diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 4f451a6c741..86a8134376a 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -88,8 +88,13 @@ void BLI_dir_create_recursive(const char *dir); double BLI_dir_free_space(const char *dir); char *BLI_current_working_dir(char *dir, const size_t maxlen); -unsigned int BLI_dir_contents(const char *dir, struct direntry **filelist); -void BLI_free_filelist(struct direntry *filelist, unsigned int nrentries); +/* Filelist */ + +unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **filelist); +void BLI_filelist_duplicate( + struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries, + void *(*dup_poin)(void *)); +void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *)); /* Files */ diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index af2605894e3..bf2b4126453 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -30,7 +30,6 @@ /** \file BLI_ghash.h * \ingroup bli - * \brief A general (pointer -> pointer) hash table ADT */ #include "BLI_sys_types.h" /* for bool */ @@ -41,6 +40,7 @@ extern "C" { #endif typedef unsigned int (*GHashHashFP) (const void *key); +/** returns false when equal */ typedef bool (*GHashCmpFP) (const void *a, const void *b); typedef void (*GHashKeyFreeFP) (void *key); typedef void (*GHashValFreeFP) (void *val); @@ -124,17 +124,17 @@ bool BLI_ghashutil_ptrcmp(const void *a, const void *b); unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n); #define BLI_ghashutil_strhash(key) ( \ - CHECK_TYPE_INLINE(key, char *), \ + CHECK_TYPE_ANY(key, char *, const char *, const char * const), \ BLI_ghashutil_strhash_p(key)) unsigned int BLI_ghashutil_strhash_p(const void *key); bool BLI_ghashutil_strcmp(const void *a, const void *b); #define BLI_ghashutil_inthash(key) ( \ - CHECK_TYPE_INLINE(&(key), int *), \ + CHECK_TYPE_ANY(&(key), int *, const int *), \ BLI_ghashutil_uinthash((unsigned int)key)) unsigned int BLI_ghashutil_uinthash(unsigned int key); #define BLI_ghashutil_inthash_v4(key) ( \ - CHECK_TYPE_INLINE(key, int *), \ + CHECK_TYPE_ANY(key, int *, const int *), \ BLI_ghashutil_uinthash_v4((const unsigned int *)key)) unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]); #define BLI_ghashutil_inthash_v4_p \ diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h index ac9edfd46a2..ea361097b7b 100644 --- a/source/blender/blenlib/BLI_heap.h +++ b/source/blender/blenlib/BLI_heap.h @@ -37,6 +37,7 @@ typedef void (*HeapFreeFP)(void *ptr); * are recycled, so memory usage will not shrink. */ Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT; Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT; +void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1); void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1); /* Insert heap node with a value (often a 'cost') and pointer into the heap, diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h index 17d40e068b3..9ac233a8fa4 100644 --- a/source/blender/blenlib/BLI_linklist_stack.h +++ b/source/blender/blenlib/BLI_linklist_stack.h @@ -51,46 +51,46 @@ #define BLI_LINKSTACK_DECLARE(var, type) \ LinkNode *var; \ - BLI_mempool *_##var##_pool; \ - type _##var##_type + BLI_mempool *var##_pool_; \ + type var##_type_ #define BLI_LINKSTACK_INIT(var) { \ var = NULL; \ - _##var##_pool = BLI_mempool_create(sizeof(LinkNode), 0, 64, BLI_MEMPOOL_NOP); \ + var##_pool_ = BLI_mempool_create(sizeof(LinkNode), 0, 64, BLI_MEMPOOL_NOP); \ } (void)0 #define BLI_LINKSTACK_SIZE(var) \ - BLI_mempool_count(_##var##_pool) + BLI_mempool_count(var##_pool_) /* check for typeof() */ #ifdef __GNUC__ #define BLI_LINKSTACK_PUSH(var, ptr) ( \ - CHECK_TYPE_INLINE(ptr, typeof(_##var##_type)), \ - BLI_linklist_prepend_pool(&(var), ptr, _##var##_pool)) + CHECK_TYPE_INLINE(ptr, typeof(var##_type_)), \ + BLI_linklist_prepend_pool(&(var), ptr, var##_pool_)) #define BLI_LINKSTACK_POP(var) \ - (var ? (typeof(_##var##_type))BLI_linklist_pop_pool(&(var), _##var##_pool) : NULL) + (var ? (typeof(var##_type_))BLI_linklist_pop_pool(&(var), var##_pool_) : NULL) #define BLI_LINKSTACK_POP_DEFAULT(var, r) \ - (var ? (typeof(_##var##_type))BLI_linklist_pop_pool(&(var), _##var##_pool) : r) + (var ? (typeof(var##_type_))BLI_linklist_pop_pool(&(var), var##_pool_) : r) #else /* non gcc */ #define BLI_LINKSTACK_PUSH(var, ptr) ( \ - BLI_linklist_prepend_pool(&(var), ptr, _##var##_pool)) + BLI_linklist_prepend_pool(&(var), ptr, var##_pool_)) #define BLI_LINKSTACK_POP(var) \ - (var ? BLI_linklist_pop_pool(&(var), _##var##_pool) : NULL) + (var ? BLI_linklist_pop_pool(&(var), var##_pool_) : NULL) #define BLI_LINKSTACK_POP_DEFAULT(var, r) \ - (var ? BLI_linklist_pop_pool(&(var), _##var##_pool) : r) + (var ? BLI_linklist_pop_pool(&(var), var##_pool_) : r) #endif /* gcc check */ #define BLI_LINKSTACK_SWAP(var_a, var_b) { \ - CHECK_TYPE_PAIR(_##var_a##_type, _##var_b##_type); \ + CHECK_TYPE_PAIR(var_a##_type_, var_b##_type_); \ SWAP(LinkNode *, var_a, var_b); \ - SWAP(BLI_mempool *, _##var_a##_pool, _##var_b##_pool); \ + SWAP(BLI_mempool *, var_a##_pool_, var_b##_pool_); \ } (void)0 #define BLI_LINKSTACK_FREE(var) { \ - BLI_mempool_destroy(_##var##_pool); \ - _##var##_pool = NULL; (void)_##var##_pool; \ + BLI_mempool_destroy(var##_pool_); \ + var##_pool_ = NULL; (void)var##_pool_; \ var = NULL; (void)var; \ - (void)&(_##var##_type); \ + (void)&(var##_type_); \ } (void)0 #include "BLI_linklist.h" diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 5711d09b530..2bc23c8a72d 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -48,13 +48,16 @@ #define M_PI_2 1.57079632679489661923 #endif #ifndef M_SQRT2 -#define M_SQRT2 1.41421356237309504880 +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ #endif #ifndef M_SQRT1_2 -#define M_SQRT1_2 0.70710678118654752440 +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ #endif #ifndef M_SQRT3 -#define M_SQRT3 1.7320508075688772 +#define M_SQRT3 1.73205080756887729352 /* sqrt(3) */ +#endif +#ifndef M_SQRT1_3 +#define M_SQRT1_3 0.57735026918962576450 /* 1/sqrt(3) */ #endif #ifndef M_1_PI #define M_1_PI 0.318309886183790671538 @@ -191,6 +194,8 @@ MINLINE int min_iiii(int a, int b, int c, int d); MINLINE int max_iiii(int a, int b, int c, int d); MINLINE float signf(float f); +MINLINE int signum_i_ex(float a, float eps); +MINLINE int signum_i(float a); MINLINE float power_of_2(float f); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index ba32b29becc..495aa6b2465 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -52,15 +52,23 @@ float normal_quad_v3(float r[3], const float a[3], const float b[3], const float float normal_poly_v3(float r[3], const float verts[][3], unsigned int nr); MINLINE float area_tri_v2(const float a[2], const float b[2], const float c[2]); +MINLINE float area_squared_tri_v2(const float a[2], const float b[2], const float c[2]); MINLINE float area_tri_signed_v2(const float v1[2], const float v2[2], const float v3[2]); float area_tri_v3(const float a[3], const float b[3], const float c[3]); +float area_squared_tri_v3(const float a[3], const float b[3], const float c[3]); float area_tri_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float normal[3]); float area_quad_v3(const float a[3], const float b[3], const float c[3], const float d[3]); +float area_squared_quad_v3(const float a[3], const float b[3], const float c[3], const float d[3]); float area_poly_v3(const float verts[][3], unsigned int nr); float area_poly_v2(const float verts[][2], unsigned int nr); +float area_squared_poly_v3(const float verts[][3], unsigned int nr); +float area_squared_poly_v2(const float verts[][2], unsigned int nr); +float area_poly_signed_v2(const float verts[][2], unsigned int nr); float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3]); +void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]); MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2]); +void cross_poly_v3(float n[3], const float verts[][3], unsigned int nr); float cross_poly_v2(const float verts[][2], unsigned int nr); /********************************* Planes **********************************/ @@ -77,6 +85,7 @@ float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const f bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); bool is_poly_convex_v2(const float verts[][2], unsigned int nr); +int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); /********************************* Distance **********************************/ @@ -263,6 +272,9 @@ void orthographic_m4(float mat[4][4], const float left, const float right, void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y); +void planes_from_projmat(float mat[4][4], float left[4], float right[4], float top[4], float bottom[4], + float front[4], float back[4]); + int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4]); void box_minmax_bounds_m4(float min[3], float max[3], diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 6885a5aa351..4455e72cf45 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -148,6 +148,7 @@ MINLINE void negate_v3_short(short r[3]); MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_v3v3v3(const float p[3], const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT; MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 3d82480d050..bade390d056 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -40,40 +40,6 @@ extern "C" { struct ListBase; struct direntry; -const char *BLI_getDefaultDocumentFolder(void); - -const char *BLI_get_folder(int folder_id, const char *subfolder); -const char *BLI_get_folder_create(int folder_id, const char *subfolder); -const char *BLI_get_user_folder_notest(int folder_id, const char *subfolder); -const char *BLI_get_folder_version(const int id, const int ver, const bool do_check); - -/* folder_id */ - -/* general, will find based on user/local/system priority */ -#define BLENDER_DATAFILES 2 - -/* user-specific */ -#define BLENDER_USER_CONFIG 31 -#define BLENDER_USER_DATAFILES 32 -#define BLENDER_USER_SCRIPTS 33 -#define BLENDER_USER_AUTOSAVE 34 - -/* system */ -#define BLENDER_SYSTEM_DATAFILES 52 -#define BLENDER_SYSTEM_SCRIPTS 53 -#define BLENDER_SYSTEM_PYTHON 54 - -/* for BLI_get_folder_version only */ -#define BLENDER_RESOURCE_PATH_USER 0 -#define BLENDER_RESOURCE_PATH_LOCAL 1 -#define BLENDER_RESOURCE_PATH_SYSTEM 2 - -#define BLENDER_STARTUP_FILE "startup.blend" -#define BLENDER_USERPREF_FILE "userpref.blend" -#define BLENDER_QUIT_FILE "quit.blend" -#define BLENDER_BOOKMARK_FILE "bookmarks.txt" -#define BLENDER_HISTORY_FILE "recent-files.txt" - #ifdef WIN32 #define SEP '\\' #define ALTSEP '/' @@ -185,19 +151,6 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char void BLI_char_switch(char *string, char from, char to) ATTR_NONNULL(); -/* Initialize path to program executable */ -void BLI_init_program_path(const char *argv0); -/* Initialize path to temporary directory. - * NOTE: On Window userdir will be set to the temporary directory! */ -void BLI_temp_dir_init(char *userdir); - -const char *BLI_program_path(void); -const char *BLI_program_dir(void); -const char *BLI_temp_dir_session(void); -const char *BLI_temp_dir_base(void); -void BLI_system_temporary_dir(char *dir); -void BLI_temp_dir_session_purge(void); - #ifdef WITH_ICONV void BLI_string_to_utf8(char *original, char *utf_8, const char *code); #endif diff --git a/source/blender/blenlib/BLI_polyfill2d.h b/source/blender/blenlib/BLI_polyfill2d.h index 5c5cea8f67d..798055f9240 100644 --- a/source/blender/blenlib/BLI_polyfill2d.h +++ b/source/blender/blenlib/BLI_polyfill2d.h @@ -37,4 +37,7 @@ void BLI_polyfill_calc( const int coords_sign, unsigned int (*r_tris)[3]); +/* default size of polyfill arena */ +#define BLI_POLYFILL_ARENA_SIZE MEM_SIZE_OPTIMAL(1 << 14) + #endif /* __BLI_POLYFILL2D_H__ */ diff --git a/source/blender/blenlib/BLI_polyfill2d_beautify.h b/source/blender/blenlib/BLI_polyfill2d_beautify.h new file mode 100644 index 00000000000..20e53b080fe --- /dev/null +++ b/source/blender/blenlib/BLI_polyfill2d_beautify.h @@ -0,0 +1,42 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_POLYFILL2D_BEAUTIFY_H__ +#define __BLI_POLYFILL2D_BEAUTIFY_H__ + +struct EdgeHash; +struct Heap; +struct MemArena; + +void BLI_polyfill_beautify( + const float (*coords)[2], + const unsigned int coords_tot, + unsigned int (*tris)[3], + + /* structs for reuse */ + struct MemArena *arena, struct Heap *eheap, struct EdgeHash *eh); + +float BLI_polyfill_beautify_quad_rotate_calc( + const float v1[2], const float v2[2], const float v3[2], const float v4[2]); + +/* avoid realloc's when creating new structures for polyfill ngons */ +#define BLI_POLYFILL_ALLOC_NGON_RESERVE 64 + +#endif /* __BLI_POLYFILL2D_BEAUTIFY_H__ */ diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h index 879af446469..7b84dddcb68 100644 --- a/source/blender/blenlib/BLI_rand.h +++ b/source/blender/blenlib/BLI_rand.h @@ -55,6 +55,9 @@ double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NON float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2); void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2); +void BLI_rng_get_tri_sample_float_v2( + struct RNG *rng, const float v1[2], const float v2[2], const float v3[2], + float r_pt[2]) ATTR_NONNULL(); void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot) ATTR_NONNULL(1, 2); /** Note that skipping is as slow as generating n numbers! */ diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h index b80044bccff..e096354e5b1 100644 --- a/source/blender/blenlib/BLI_smallhash.h +++ b/source/blender/blenlib/BLI_smallhash.h @@ -52,7 +52,7 @@ typedef struct SmallHash { } SmallHash; typedef struct { - SmallHash *sh; + const SmallHash *sh; unsigned int i; } SmallHashIter; @@ -61,13 +61,16 @@ void BLI_smallhash_init_ex(SmallHash *sh, void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1); void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1); void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1); +bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1); bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1); -void *BLI_smallhash_lookup(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; -void **BLI_smallhash_lookup_p(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; -bool BLI_smallhash_haskey(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1); -int BLI_smallhash_count(SmallHash *sh) ATTR_NONNULL(1); +void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1); +int BLI_smallhash_count(const SmallHash *sh) ATTR_NONNULL(1); void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; -void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; /* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */ #ifdef DEBUG diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index b249bc720c6..c4853e37398 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -48,6 +48,8 @@ char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2) AT char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL(); +char *BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t maxncpy) ATTR_NONNULL(); + size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -71,6 +73,8 @@ char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT AT int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_natstrcmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BLI_timestr(double _time, char *str, size_t maxlen) ATTR_NONNULL(); @@ -81,6 +85,9 @@ int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL(); int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len) ATTR_NONNULL(); int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array) ATTR_NONNULL(); +bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(); +bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length) ATTR_NONNULL(); + size_t BLI_str_partition(const char *str, const char delim[], char **sep, char **suf) ATTR_NONNULL(); size_t BLI_str_rpartition(const char *str, const char delim[], char **sep, char **suf) ATTR_NONNULL(); size_t BLI_str_partition_ex(const char *str, const char delim[], char **sep, char **suf, const bool from_right) ATTR_NONNULL(); diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index 89754be25ba..3e599865416 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -34,6 +34,7 @@ extern "C" { #include "BLI_compiler_attrs.h" char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); +size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); int BLI_utf8_invalid_byte(const char *str, int length) ATTR_NONNULL(); int BLI_utf8_invalid_strip(char *str, int length) ATTR_NONNULL(); diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h index 8cdc9e4e6c5..cb8cb6f5a0d 100644 --- a/source/blender/blenlib/BLI_system.h +++ b/source/blender/blenlib/BLI_system.h @@ -27,6 +27,10 @@ int BLI_cpu_support_sse2(void); +#if defined(NDEBUG) || !defined(__BLI_UTILDEFINES_H__) +void BLI_system_backtrace(FILE *fp); +#endif + /* getpid */ #ifdef WIN32 # define BLI_SYSTEM_PID_H <process.h> @@ -35,4 +39,3 @@ int BLI_cpu_support_sse2(void); #endif #endif /* __BLI_SYSTEM_H__ */ - diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 28da673ea97..2eaec024ce2 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -73,7 +73,7 @@ typedef enum TaskPriority { } TaskPriority; typedef struct TaskPool TaskPool; -typedef void (*TaskRunFunction)(TaskPool *pool, void *taskdata, int threadid); +typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata, int threadid); TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata); void BLI_task_pool_free(TaskPool *pool); @@ -88,6 +88,9 @@ void BLI_task_pool_cancel(TaskPool *pool); /* stop all worker threads */ void BLI_task_pool_stop(TaskPool *pool); +/* set number of threads allowed to be used by this pool */ +void BLI_pool_set_num_threads(TaskPool *pool, int num_threads); + /* for worker threads, test if canceled */ bool BLI_task_pool_canceled(TaskPool *pool); diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 16d3c2f8a42..b1b225096a7 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -32,6 +32,10 @@ * \ingroup bli */ +#ifdef __cplusplus +extern "C" { +#endif + /* avoid many includes for now */ #include "BLI_sys_types.h" #include "BLI_compiler_compat.h" @@ -51,7 +55,8 @@ _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \ count, ...) count #define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args -#define _VA_NARGS_COUNT_MAX64(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ +/* 64 args max */ +#define _VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \ @@ -61,7 +66,7 @@ #define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) /* --- expose for re-use --- */ #define VA_NARGS_CALL_OVERLOAD(name, ...) \ - _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT_MAX64(__VA_ARGS__)), (__VA_ARGS__)) + _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__)) /* useful for finding bad use of min/max */ #if 0 @@ -215,6 +220,8 @@ /* reusable ELEM macro */ #define ELEM(...) VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__) +/* no-op for expressions we don't want to instansiate, but must remian valid */ +#define EXPR_NOP(expr) (void)(0 ? ((void)(expr), 1) : 0) /* shift around elements */ #define SHIFT3(type, a, b, c) { \ @@ -429,13 +436,51 @@ /* assuming a static array */ #if defined(__GNUC__) && !defined(__cplusplus) -# define ARRAY_SIZE(arr) \ - ((sizeof(struct {int isnt_array : ((void *)&(arr) == &(arr)[0]);}) * 0) + \ +# define ARRAY_SIZE(arr) \ + ((sizeof(struct {int isnt_array : ((const void *)&(arr) == &(arr)[0]);}) * 0) + \ (sizeof(arr) / sizeof(*(arr)))) #else # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr))) #endif +/* ELEM#(v, ...): is the first arg equal any others? */ +/* internal helpers*/ +#define _VA_ARRAY_SET_ITEMS2(v, a) \ + ((v)[0] = (a)) +#define _VA_ARRAY_SET_ITEMS3(v, a, b) \ + _VA_ARRAY_SET_ITEMS2(v, a); ((v)[1] = (b)) +#define _VA_ARRAY_SET_ITEMS4(v, a, b, c) \ + _VA_ARRAY_SET_ITEMS3(v, a, b); ((v)[2] = (c)) +#define _VA_ARRAY_SET_ITEMS5(v, a, b, c, d) \ + _VA_ARRAY_SET_ITEMS4(v, a, b, c); ((v)[3] = (d)) +#define _VA_ARRAY_SET_ITEMS6(v, a, b, c, d, e) \ + _VA_ARRAY_SET_ITEMS5(v, a, b, c, d); ((v)[4] = (e)) +#define _VA_ARRAY_SET_ITEMS7(v, a, b, c, d, e, f) \ + _VA_ARRAY_SET_ITEMS6(v, a, b, c, d, e); ((v)[5] = (f)) +#define _VA_ARRAY_SET_ITEMS8(v, a, b, c, d, e, f, g) \ + _VA_ARRAY_SET_ITEMS7(v, a, b, c, d, e, f); ((v)[6] = (g)) +#define _VA_ARRAY_SET_ITEMS9(v, a, b, c, d, e, f, g, h) \ + _VA_ARRAY_SET_ITEMS8(v, a, b, c, d, e, f, g); ((v)[7] = (h)) +#define _VA_ARRAY_SET_ITEMS10(v, a, b, c, d, e, f, g, h, i) \ + _VA_ARRAY_SET_ITEMS9(v, a, b, c, d, e, f, g, h); ((v)[8] = (i)) +#define _VA_ARRAY_SET_ITEMS11(v, a, b, c, d, e, f, g, h, i, j) \ + _VA_ARRAY_SET_ITEMS10(v, a, b, c, d, e, f, g, h, i); ((v)[9] = (j)) +#define _VA_ARRAY_SET_ITEMS12(v, a, b, c, d, e, f, g, h, i, j, k) \ + _VA_ARRAY_SET_ITEMS11(v, a, b, c, d, e, f, g, h, i, j); ((v)[10] = (k)) +#define _VA_ARRAY_SET_ITEMS13(v, a, b, c, d, e, f, g, h, i, j, k, l) \ + _VA_ARRAY_SET_ITEMS12(v, a, b, c, d, e, f, g, h, i, j, k); ((v)[11] = (l)) +#define _VA_ARRAY_SET_ITEMS14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \ + _VA_ARRAY_SET_ITEMS13(v, a, b, c, d, e, f, g, h, i, j, k, l); ((v)[12] = (m)) +#define _VA_ARRAY_SET_ITEMS15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \ + _VA_ARRAY_SET_ITEMS14(v, a, b, c, d, e, f, g, h, i, j, k, l, m); ((v)[13] = (n)) +#define _VA_ARRAY_SET_ITEMS16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \ + _VA_ARRAY_SET_ITEMS15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n); ((v)[14] = (o)) +#define _VA_ARRAY_SET_ITEMS17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + _VA_ARRAY_SET_ITEMS16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); ((v)[15] = (p)) + +/* reusable ELEM macro */ +#define ARRAY_SET_ITEMS(...) { VA_NARGS_CALL_OVERLOAD(_VA_ARRAY_SET_ITEMS, __VA_ARGS__); } (void)0 + /* Like offsetof(typeof(), member), for non-gcc compilers */ #define OFFSETOF_STRUCT(_struct, _member) \ ((((char *)&((_struct)->_member)) - ((char *)(_struct))) + sizeof((_struct)->_member)) @@ -493,6 +538,56 @@ # define UNUSED_FUNCTION(x) UNUSED_ ## x #endif +/** + * UNUSED_VARS#(a, ...): quiet unused warnings + * + * <pre> + * for i in range(16): + * args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)] + * print("#define _VA_UNUSED_VARS_%d(%s) \\" % (i + 1, ", ".join(args))) + * print("\t((void)(%s)%s)" % + * (args[0], ((", _VA_UNUSED_VARS_" + str(i) + "(%s)") if i else "%s") % ", ".join((args[1:])))) + * </pre> + * + */ + +#define _VA_UNUSED_VARS_1(a0) \ + ((void)(a0)) +#define _VA_UNUSED_VARS_2(a0, b0) \ + ((void)(a0), _VA_UNUSED_VARS_1(b0)) +#define _VA_UNUSED_VARS_3(a0, b0, c0) \ + ((void)(a0), _VA_UNUSED_VARS_2(b0, c0)) +#define _VA_UNUSED_VARS_4(a0, b0, c0, d0) \ + ((void)(a0), _VA_UNUSED_VARS_3(b0, c0, d0)) +#define _VA_UNUSED_VARS_5(a0, b0, c0, d0, e0) \ + ((void)(a0), _VA_UNUSED_VARS_4(b0, c0, d0, e0)) +#define _VA_UNUSED_VARS_6(a0, b0, c0, d0, e0, f0) \ + ((void)(a0), _VA_UNUSED_VARS_5(b0, c0, d0, e0, f0)) +#define _VA_UNUSED_VARS_7(a0, b0, c0, d0, e0, f0, g0) \ + ((void)(a0), _VA_UNUSED_VARS_6(b0, c0, d0, e0, f0, g0)) +#define _VA_UNUSED_VARS_8(a0, b0, c0, d0, e0, f0, g0, h0) \ + ((void)(a0), _VA_UNUSED_VARS_7(b0, c0, d0, e0, f0, g0, h0)) +#define _VA_UNUSED_VARS_9(a0, b0, c0, d0, e0, f0, g0, h0, i0) \ + ((void)(a0), _VA_UNUSED_VARS_8(b0, c0, d0, e0, f0, g0, h0, i0)) +#define _VA_UNUSED_VARS_10(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) \ + ((void)(a0), _VA_UNUSED_VARS_9(b0, c0, d0, e0, f0, g0, h0, i0, j0)) +#define _VA_UNUSED_VARS_11(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) \ + ((void)(a0), _VA_UNUSED_VARS_10(b0, c0, d0, e0, f0, g0, h0, i0, j0, k0)) +#define _VA_UNUSED_VARS_12(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) \ + ((void)(a0), _VA_UNUSED_VARS_11(b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0)) +#define _VA_UNUSED_VARS_13(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) \ + ((void)(a0), _VA_UNUSED_VARS_12(b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0)) +#define _VA_UNUSED_VARS_14(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) \ + ((void)(a0), _VA_UNUSED_VARS_13(b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0)) +#define _VA_UNUSED_VARS_15(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) \ + ((void)(a0), _VA_UNUSED_VARS_14(b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0)) +#define _VA_UNUSED_VARS_16(a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) \ + ((void)(a0), _VA_UNUSED_VARS_15(b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0)) + + +/* reusable ELEM macro */ +#define UNUSED_VARS(...) VA_NARGS_CALL_OVERLOAD(_VA_UNUSED_VARS_, __VA_ARGS__) + /*little macro so inline keyword works*/ #if defined(_MSC_VER) # define BLI_INLINE static __forceinline @@ -510,6 +605,7 @@ * for aborting need to define WITH_ASSERT_ABORT */ #ifndef NDEBUG +extern void BLI_system_backtrace(FILE *fp); # ifdef WITH_ASSERT_ABORT # define _BLI_DUMMY_ABORT abort # else @@ -519,6 +615,7 @@ # define BLI_assert(a) \ (void)((!(a)) ? ( \ ( \ + BLI_system_backtrace(stderr), \ fprintf(stderr, \ "BLI_assert failed: %s:%d, %s(), at \'%s\'\n", \ __FILE__, __LINE__, __func__, STRINGIFY(a)), \ @@ -558,4 +655,8 @@ # define UNLIKELY(x) (x) #endif +#ifdef __cplusplus +} +#endif + #endif /* __BLI_UTILDEFINES_H__ */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index ba166b11960..fa08856517a 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -29,8 +29,8 @@ set(INC . # ../blenkernel # dont add this back! ../makesdna - ../../../intern/ghost ../../../intern/guardedalloc + ../../../intern/atomic ../../../extern/wcwidth ) @@ -52,6 +52,7 @@ set(SRC intern/BLI_memarena.c intern/BLI_mempool.c intern/DLRB_tree.c + intern/astar.c intern/boxpack2d.c intern/buffer.c intern/callbacks.c @@ -85,6 +86,7 @@ set(SRC intern/noise.c intern/path_util.c intern/polyfill2d.c + intern/polyfill2d_beautify.c intern/quadric.c intern/rand.c intern/rct.c @@ -112,6 +114,7 @@ set(SRC BLI_alloca.h BLI_args.h BLI_array.h + BLI_astar.h BLI_bitmap.h BLI_blenlib.h BLI_boxpack2d.h @@ -161,6 +164,7 @@ set(SRC BLI_noise.h BLI_path_util.h BLI_polyfill2d.h + BLI_polyfill2d_beautify.h BLI_quadric.h BLI_rand.h BLI_rect.h @@ -189,13 +193,6 @@ set(SRC PIL_time_utildefines.h ) -if(WITH_BINRELOC) - list(APPEND INC_SYS - ${BINRELOC_INCLUDE_DIRS} - ) - add_definitions(-DWITH_BINRELOC) -endif() - if(WITH_MEM_VALGRIND) add_definitions(-DWITH_MEM_VALGRIND) endif() diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript index b712d2032bf..8b4054e00b5 100644 --- a/source/blender/blenlib/SConscript +++ b/source/blender/blenlib/SConscript @@ -34,8 +34,8 @@ cflags='' incs = [ '.', '#/extern/wcwidth', - '#/intern/ghost', '#/intern/guardedalloc', + '#/intern/atomic', '../makesdna', env['BF_FREETYPE_INC'], env['BF_ZLIB_INC'], @@ -44,10 +44,6 @@ incs = ' '.join(incs) defs = [] -if env['WITH_BF_BINRELOC']: - incs += ' ../../../extern/binreloc/include' - defs.append('WITH_BINRELOC') - if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] incs += ' ../../../intern/utfconv' diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 6747e5c4e7e..c87b60f08db 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -28,7 +28,8 @@ /** \file blender/blenlib/intern/BLI_ghash.c * \ingroup bli * - * A general (pointer -> pointer) hash table ADT + * A general (pointer -> pointer) chaining hash table + * for 'Abstract Data Types' (known as an ADT Hash Table). * * \note edgehash.c is based on this, make sure they stay in sync. */ diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c index 55dee4e8677..66dfa87b7b9 100644 --- a/source/blender/blenlib/intern/BLI_heap.c +++ b/source/blender/blenlib/intern/BLI_heap.c @@ -49,7 +49,6 @@ struct Heap { unsigned int bufsize; MemArena *arena; HeapNode *freenodes; - HeapNode *nodes; HeapNode **tree; }; @@ -139,9 +138,9 @@ Heap *BLI_heap_new(void) void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) { - unsigned int i; - if (ptrfreefp) { + unsigned int i; + for (i = 0; i < heap->size; i++) { ptrfreefp(heap->tree[i]->ptr); } @@ -152,6 +151,21 @@ void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) MEM_freeN(heap); } +void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) +{ + if (ptrfreefp) { + unsigned int i; + + for (i = 0; i < heap->size; i++) { + ptrfreefp(heap->tree[i]->ptr); + } + } + + heap->size = 0; + BLI_memarena_clear(heap->arena); + heap->freenodes = NULL; +} + HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) { HeapNode *node; @@ -163,7 +177,7 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) if (heap->freenodes) { node = heap->freenodes; - heap->freenodes = (HeapNode *)(((HeapNode *)heap->freenodes)->ptr); + heap->freenodes = heap->freenodes->ptr; } else { node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof(*node)); @@ -206,13 +220,8 @@ void *BLI_heap_popmin(Heap *heap) heap->tree[0]->ptr = heap->freenodes; heap->freenodes = heap->tree[0]; - if (UNLIKELY(heap->size == 1)) { - heap->size--; - } - else { - heap_swap(heap, 0, heap->size - 1); - heap->size--; - + if (--heap->size) { + heap_swap(heap, 0, heap->size); heap_down(heap, 0); } diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index d28215ee8ed..b76b925e6cc 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -986,7 +986,7 @@ bool BLI_bvhtree_update_node(BVHTree *tree, int index, const float co[3], const /* check if index exists */ if (index > tree->totleaf) - return 0; + return false; node = tree->nodearray + index; @@ -1001,7 +1001,7 @@ bool BLI_bvhtree_update_node(BVHTree *tree, int index, const float co[3], const node->bv[(2 * axis_iter) + 1] += tree->epsilon; /* maximum */ } - return 1; + return true; } /* call BLI_bvhtree_update_node() first for every node/point/triangle */ diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index a0b61e7945c..6b79cf97e86 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -32,6 +32,8 @@ #include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" #include "BLI_linklist.h" #include "BLI_memarena.h" #include "BLI_mempool.h" @@ -96,7 +98,7 @@ void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) void BLI_linklist_prepend(LinkNode **listp, void *ptr) { - LinkNode *nlink = MEM_mallocN(sizeof(*nlink), "nlink"); + LinkNode *nlink = MEM_mallocN(sizeof(*nlink), __func__); BLI_linklist_prepend_nlink(listp, ptr, nlink); } @@ -135,7 +137,7 @@ void BLI_linklist_append_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) void BLI_linklist_append(LinkNode **listp, void *ptr) { - LinkNode *nlink = MEM_mallocN(sizeof(*nlink), "nlink"); + LinkNode *nlink = MEM_mallocN(sizeof(*nlink), __func__); BLI_linklist_append_nlink(listp, ptr, nlink); } @@ -177,7 +179,7 @@ void *BLI_linklist_pop_pool(struct LinkNode **listp, struct BLI_mempool *mempool void BLI_linklist_insert_after(LinkNode **listp, void *ptr) { - LinkNode *nlink = MEM_mallocN(sizeof(*nlink), "nlink"); + LinkNode *nlink = MEM_mallocN(sizeof(*nlink), __func__); LinkNode *node = *listp; nlink->link = ptr; diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c new file mode 100644 index 00000000000..b7b41d2497e --- /dev/null +++ b/source/blender/blenlib/intern/astar.c @@ -0,0 +1,294 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/astar.c + * \ingroup bli + * \brief An implementation of the A* (AStar) algorithm to solve shortest path problem. + * + * This library implements the simple A* (AStar) algorithm, an optimized version of + * classical dijkstra shortest path solver. The difference is that each future possible + * path is weighted from its 'shortest' (smallest) possible distance to destination, + * in addition to distance already walked. This heuristic allows more efficiency + * in finding optimal path. + * + * Implementation based on Wikipedia A* page [http://en.wikipedia.org/wiki/A*_search_algorithm]. + * + * Note that most memory handling here is done through two different MemArena's. Those should also be used to allocate + * custom data needed to a specific use of A*. + * The first one, owned by BLI_AStarGraph, is for 'static' data that will live as long as the graph. + * The second one, owned by BLI_AStarSolution, is for data used during a single path solve. It will be cleared + * much more often than graph's one. + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_sys_types.h" +#include "BLI_compiler_attrs.h" + +#include "BLI_alloca.h" +#include "BLI_heap.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_memarena.h" + +#include "BLI_astar.h" + +/** + * Init a node in A* graph. + * + * \param custom_data an opaque pointer attached to this link, available e.g. to cost callback function. + */ +void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data) +{ + as_graph->nodes[node_index].custom_data = custom_data; +} + +/** + * Add a link between two nodes of our A* graph. + * + * \param cost the 'length' of the link (actual distance between two vertices or face centers e.g.). + * \param custom_data an opaque pointer attached to this link, available e.g. to cost callback function. + */ +void BLI_astar_node_link_add( + BLI_AStarGraph *as_graph, const int node1_index, const int node2_index, const float cost, void *custom_data) +{ + MemArena *mem = as_graph->mem; + BLI_AStarGNLink *link = BLI_memarena_alloc(mem, sizeof(*link)); + LinkData *ld = BLI_memarena_alloc(mem, sizeof(*ld) * 2); + + link->nodes[0] = node1_index; + link->nodes[1] = node2_index; + link->cost = cost; + link->custom_data = custom_data; + + ld[0].data = ld[1].data = link; + + BLI_addtail(&(as_graph->nodes[node1_index].neighbor_links), &ld[0]); + BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]); +} + +/** + * \return The index of the other node of given link. + */ +int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx) +{ + return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0]; +} + +/** + * Initialize a solution data for given A* graph. Does not compute anything! + * + * \param custom_data an opaque pointer attached to this link, available e.g. to cost callback function. + * + * \note BLI_AStarSolution stores nearly all data needed during solution compute. + */ +void BLI_astar_solution_init(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, void *custom_data) +{ + MemArena *mem = as_solution->mem; + size_t node_num = (size_t)as_graph->node_num; + + if (mem == NULL) { + mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + as_solution->mem = mem; + } + /* else memarena should be cleared */ + + as_solution->steps = 0; + as_solution->prev_nodes = BLI_memarena_alloc(mem, sizeof(*as_solution->prev_nodes) * node_num); + as_solution->prev_links = BLI_memarena_alloc(mem, sizeof(*as_solution->prev_links) * node_num); + + as_solution->custom_data = custom_data; + + as_solution->done_nodes = BLI_BITMAP_NEW_MEMARENA(mem, node_num); + as_solution->g_costs = BLI_memarena_alloc(mem, sizeof(*as_solution->g_costs) * node_num); + as_solution->g_steps = BLI_memarena_alloc(mem, sizeof(*as_solution->g_steps) * node_num); +} + +/** + * Clear given solution's data, but does not release its memory. Avoids having to recreate/allocate + * a memarena in loops, e.g. + * + * \note This *has to be called* between each path solving. + */ +void BLI_astar_solution_clear(BLI_AStarSolution *as_solution) +{ + if (as_solution->mem) { + BLI_memarena_clear(as_solution->mem); + } + + as_solution->steps = 0; + as_solution->prev_nodes = NULL; + as_solution->prev_links = NULL; + + as_solution->custom_data = NULL; + + as_solution->done_nodes = NULL; + as_solution->g_costs = NULL; + as_solution->g_steps = NULL; +} + +/** + * Release the memory allocated for this solution. + */ +void BLI_astar_solution_free(BLI_AStarSolution *as_solution) +{ + if (as_solution->mem) { + BLI_memarena_free(as_solution->mem); + as_solution->mem = NULL; + } +} + +/** + * Callback computing the current cost (distance) to next node, and the estimated overall cost to destination node + * (A* expects this estimation to always be less or equal than actual shortest path from next node to destination one). + * + * \param link the graph link between current node and next one. + * \param node_idx_curr current node index. + * \param node_idx_next next node index. + * \param node_idx_dst destination node index. + */ +typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link, + const int node_idx_curr, const int node_idx_next, const int node_idx_dst); + +/** + * Init an A* graph. Total number of nodes must be known. + * + * Nodes might be e.g. vertices, faces, ... + * + * \param custom_data an opaque pointer attached to this link, available e.g. to cost callback function. + */ +void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data) +{ + MemArena *mem = as_graph->mem; + + if (mem == NULL) { + mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + as_graph->mem = mem; + } + /* else memarena should be cleared */ + + as_graph->node_num = node_num; + as_graph->nodes = BLI_memarena_calloc(mem, sizeof(*as_graph->nodes) * (size_t)node_num); + + as_graph->custom_data = custom_data; +} + +void BLI_astar_graph_free(BLI_AStarGraph *as_graph) +{ + if (as_graph->mem) { + BLI_memarena_free(as_graph->mem); + as_graph->mem = NULL; + } +} + +/** + * Solve a path in given graph, using given 'cost' callback function. + * + * \param max_steps maximum number of nodes the found path may have. Useful in performance-critical usages. + * If no path is found within given steps, returns false too. + * \return true if a path was found, false otherwise. + */ +bool BLI_astar_graph_solve( + BLI_AStarGraph *as_graph, const int node_index_src, const int node_index_dst, astar_f_cost f_cost_cb, + BLI_AStarSolution *r_solution, const int max_steps) +{ + Heap *todo_nodes; + + BLI_bitmap *done_nodes = r_solution->done_nodes; + int *prev_nodes = r_solution->prev_nodes; + BLI_AStarGNLink **prev_links = r_solution->prev_links; + float *g_costs = r_solution->g_costs; + int *g_steps = r_solution->g_steps; + + r_solution->steps = 0; + prev_nodes[node_index_src] = -1; + BLI_BITMAP_SET_ALL(done_nodes, false, as_graph->node_num); + fill_vn_fl(g_costs, as_graph->node_num, FLT_MAX); + g_costs[node_index_src] = 0.0f; + g_steps[node_index_src] = 0; + + if (node_index_src == node_index_dst) { + return true; + } + + todo_nodes = BLI_heap_new(); + BLI_heap_insert(todo_nodes, + f_cost_cb(as_graph, r_solution, NULL, -1, node_index_src, node_index_dst), + SET_INT_IN_POINTER(node_index_src)); + + while (!BLI_heap_is_empty(todo_nodes)) { + const int node_curr_idx = GET_INT_FROM_POINTER(BLI_heap_popmin(todo_nodes)); + BLI_AStarGNode *node_curr = &as_graph->nodes[node_curr_idx]; + LinkData *ld; + + if (BLI_BITMAP_TEST(done_nodes, node_curr_idx)) { + /* Might happen, because we always add nodes to heap when evaluating them, without ever removing them. */ + continue; + } + + /* If we are limited in amount of steps to find a path, skip if we reached limit. */ + if (max_steps && g_steps[node_curr_idx] > max_steps) { + continue; + } + + if (node_curr_idx == node_index_dst) { + /* Success! Path found... */ + r_solution->steps = g_steps[node_curr_idx] + 1; + + BLI_heap_free(todo_nodes, NULL); + return true; + } + + BLI_BITMAP_ENABLE(done_nodes, node_curr_idx); + + for (ld = node_curr->neighbor_links.first; ld; ld = ld->next) { + BLI_AStarGNLink *link = ld->data; + const int node_next_idx = BLI_astar_node_link_other_node(link, node_curr_idx); + + if (!BLI_BITMAP_TEST(done_nodes, node_next_idx)) { + float g_cst = g_costs[node_curr_idx] + link->cost; + + if (g_cst < g_costs[node_next_idx]) { + prev_nodes[node_next_idx] = node_curr_idx; + prev_links[node_next_idx] = link; + g_costs[node_next_idx] = g_cst; + g_steps[node_next_idx] = g_steps[node_curr_idx] + 1; + /* We might have this node already in heap, but since this 'instance' will be evaluated first, + * no problem. */ + BLI_heap_insert(todo_nodes, + f_cost_cb(as_graph, r_solution, link, node_curr_idx, node_next_idx, node_index_dst), + SET_INT_IN_POINTER(node_next_idx)); + } + } + } + } + + BLI_heap_free(todo_nodes, NULL); + return false; +} diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c index 91495ce3c9c..bae56444f37 100644 --- a/source/blender/blenlib/intern/boxpack2d.c +++ b/source/blender/blenlib/intern/boxpack2d.c @@ -236,8 +236,8 @@ static int vertex_sort(const void *p1, const void *p2) BoxVert *v1, *v2; float a1, a2; - v1 = vertarray + ((int *)p1)[0]; - v2 = vertarray + ((int *)p2)[0]; + v1 = vertarray + ((const int *)p1)[0]; + v2 = vertarray + ((const int *)p2)[0]; #ifdef USE_FREE_STRIP /* push free verts to the end so we can strip */ diff --git a/source/blender/blenlib/intern/convexhull2d.c b/source/blender/blenlib/intern/convexhull2d.c index 361e4b4eadb..5f64088f433 100644 --- a/source/blender/blenlib/intern/convexhull2d.c +++ b/source/blender/blenlib/intern/convexhull2d.c @@ -187,8 +187,8 @@ static int pointref_cmp_yx(const void *a_, const void *b_) * \param points An array of 2D points. * \param n The number of points in points. * \param r_points An array of the convex hull vertex indices (max is n). - * _must_ be allocated as ``n * 2`` because of how its used internally, - * even though the final result will be no more then \a n in size. + * _must_ be allocated as ``n * 2`` because of how its used internally, + * even though the final result will be no more than \a n in size. * \returns the number of points in r_points. */ int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]) diff --git a/source/blender/blenlib/intern/easing.c b/source/blender/blenlib/intern/easing.c index 80f02d54eaa..90c8528338e 100644 --- a/source/blender/blenlib/intern/easing.c +++ b/source/blender/blenlib/intern/easing.c @@ -139,7 +139,7 @@ float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float #ifdef USE_ELASTIC_BLEND /** - * When the amplitude is less then the change, we need to blend + * When the amplitude is less than the change, we need to blend * \a f when we're close to the crossing point (int time), else we get an ugly sharp falloff. */ static float elastic_blend(float time, float change, float duration, float amplitude, float s, float f) diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c index 4ed82f8a473..82d57dad753 100644 --- a/source/blender/blenlib/intern/edgehash.c +++ b/source/blender/blenlib/intern/edgehash.c @@ -23,12 +23,13 @@ /** \file blender/blenlib/intern/edgehash.c * \ingroup bli * - * A general (pointer -> pointer) hash table ADT + * An (edge -> pointer) chaining hash table. + * Using unordered int-pairs as keys. * - * \note Based on 'BLI_ghash.c', make sure these stay in sync. + * \note Based on 'BLI_ghash.c', which is a more generalized hash-table + * make sure these stay in sync. */ - #include <stdlib.h> #include <string.h> #include <limits.h> @@ -146,7 +147,7 @@ BLI_INLINE void edgehash_buckets_reserve(EdgeHash *eh, const unsigned int nentri /** * Internal lookup function. - * Takes a hash argument to avoid calling #ghash_keyhash multiple times. + * Takes a hash argument to avoid calling #edgehash_keyhash multiple times. */ BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, const unsigned int hash) @@ -256,6 +257,35 @@ BLI_INLINE void edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, } /** + * Remove the entry and return it, caller must free from eh->epool. + */ +static EdgeEntry *edgehash_remove_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp, + unsigned int hash) +{ + EdgeEntry *e; + EdgeEntry *e_prev = NULL; + + BLI_assert(v0 < v1); + + for (e = eh->buckets[hash]; e; e = e->next) { + if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) { + EdgeEntry *e_next = e->next; + + if (valfreefp) valfreefp(e->val); + + if (e_prev) e_prev->next = e_next; + else eh->buckets[hash] = e_next; + + eh->nentries--; + return e; + } + e_prev = e; + } + + return NULL; +} + +/** * Run free callbacks for freeing entries. */ static void edgehash_free_cb(EdgeHash *eh, EdgeHashFreeFP valfreefp) @@ -366,6 +396,57 @@ void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1 } /** + * Remove \a key from \a eh, or return false if the key wasn't found. + * + * \param key The key to remove. + * \param valfreefp Optional callback to free the value. + * \return true if \a key was removed from \a eh. + */ +bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp) +{ + unsigned int hash; + EdgeEntry *e; + + EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + hash = edgehash_keyhash(eh, v0, v1); + e = edgehash_remove_ex(eh, v0, v1, valfreefp, hash); + if (e) { + BLI_mempool_free(eh->epool, e); + return true; + } + else { + return false; + } +} + +/* same as above but return the value, + * no free value argument since it will be returned */ +/** + * Remove \a key from \a eh, returning the value or NULL if the key wasn't found. + * + * \param key The key to remove. + * \return the value of \a key int \a eh or NULL. + */ +void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) +{ + unsigned int hash; + EdgeEntry *e; + + EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + hash = edgehash_keyhash(eh, v0, v1); + e = edgehash_remove_ex(eh, v0, v1, NULL, hash); + IS_EDGEHASH_ASSERT(eh); + if (e) { + void *val = e->val; + BLI_mempool_free(eh->epool, e); + return val; + } + else { + return NULL; + } +} + +/** * Return boolean true/false if edge (v0,v1) in hash. */ bool BLI_edgehash_haskey(EdgeHash *eh, unsigned int v0, unsigned int v1) @@ -404,6 +485,14 @@ void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP valfreefp, BLI_mempool_clear_ex(eh->epool, nentries_reserve ? (int)nentries_reserve : -1); } +/** + * Wraps #BLI_edgehash_clear_ex with zero entries reserved. + */ +void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) +{ + BLI_edgehash_clear_ex(eh, valfreefp, 0); +} + void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) { BLI_assert((int)eh->nentries == BLI_mempool_count(eh->epool)); @@ -440,7 +529,7 @@ void BLI_edgehash_flag_clear(EdgeHash *eh, unsigned int flag) /** * Create a new EdgeHashIterator. The hash table must not be mutated * while the iterator is in use, and the iterator will step exactly - * BLI_edgehash_size(gh) times before becoming done. + * BLI_edgehash_size(eh) times before becoming done. */ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) { diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index f6bbd3273f9..62e1b6e4cbf 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -311,7 +311,7 @@ static bool delete_recursive(const char *dir) bool err = false; unsigned int nbr, i; - i = nbr = BLI_dir_contents(dir, &filelist); + i = nbr = BLI_filelist_dir_contents(dir, &filelist); fl = filelist; while (i--) { char file[8]; @@ -336,7 +336,7 @@ static bool delete_recursive(const char *dir) err = true; } - BLI_free_filelist(filelist, nbr); + BLI_filelist_free(filelist, nbr, NULL); return err; } @@ -896,7 +896,7 @@ int BLI_move(const char *file, const char *to) } #endif -static char *check_destination(const char *file, const char *to) +static const char *check_destination(const char *file, const char *to) { struct stat st; @@ -927,18 +927,18 @@ static char *check_destination(const char *file, const char *to) } } - return (char *)to; + return to; } int BLI_copy(const char *file, const char *to) { - char *actual_to = check_destination(file, to); + const char *actual_to = check_destination(file, to); int ret; ret = recursive_operation(file, actual_to, copy_callback_pre, copy_single_file, NULL); if (actual_to != to) - MEM_freeN(actual_to); + MEM_freeN((void *)actual_to); return ret; } diff --git a/source/blender/blenlib/intern/graph.c b/source/blender/blenlib/intern/graph.c index d4d87dfdbf6..81cc9fde01f 100644 --- a/source/blender/blenlib/intern/graph.c +++ b/source/blender/blenlib/intern/graph.c @@ -170,11 +170,11 @@ bool BLI_hasAdjacencyList(BGraph *graph) for (node = graph->nodes.first; node; node = node->next) { if (node->arcs == NULL) { - return 0; + return false; } } - return 1; + return true; } void BLI_replaceNodeInArc(BGraph *graph, BArc *arc, BNode *node_src, BNode *node_replaced) @@ -337,7 +337,7 @@ static bool detectCycle(BNode *node, BArc *src_arc) } } else { - value = 1; + value = true; } return value; @@ -354,7 +354,7 @@ bool BLI_isGraphCyclic(BGraph *graph) BLI_flagNodes(graph, 0); /* detectCycles in subgraphs */ - for (node = graph->nodes.first; node && value == 0; node = node->next) { + for (node = graph->nodes.first; node && value == false; node = node->next) { /* only for nodes in subgraphs that haven't been visited yet */ if (node->flag == 0) { value = value || detectCycle(node, NULL); diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c index bc7a495f213..4eec38278e9 100644 --- a/source/blender/blenlib/intern/hash_md5.c +++ b/source/blender/blenlib/intern/hash_md5.c @@ -22,7 +22,7 @@ * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */ -/** \file blender/blenlib/intern/md5.c +/** \file blender/blenlib/intern/hash_md5.c * \ingroup bli * * Functions to compute MD5 message digest of files or memory blocks diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c index 8b4242fa5be..bae098ae96b 100644 --- a/source/blender/blenlib/intern/hash_mm2a.c +++ b/source/blender/blenlib/intern/hash_mm2a.c @@ -81,7 +81,7 @@ void BLI_hash_mm2a_add(BLI_HashMurmur2A *mm2, const unsigned char *data, size_t mm2a_mix_tail(mm2, &data, &len); for (; len >= 4; data += 4, len -= 4) { - uint32_t k = *(uint32_t *)data; + uint32_t k = *(const uint32_t *)data; MM2A_MIX(mm2->hash, k); } diff --git a/source/blender/blenlib/intern/lasso.c b/source/blender/blenlib/intern/lasso.c index e89f7fd795b..23704538413 100644 --- a/source/blender/blenlib/intern/lasso.c +++ b/source/blender/blenlib/intern/lasso.c @@ -33,7 +33,6 @@ #include "DNA_vec_types.h" #include "BLI_math.h" -#include "BLI_rect.h" #include "BLI_strict_flags.h" #include "BLI_lasso.h" /* own include */ diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 39116d6f30f..f5713824296 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -276,5 +276,18 @@ MINLINE float signf(float f) return (f < 0.f) ? -1.f : 1.f; } +MINLINE int signum_i_ex(float a, float eps) +{ + if (a > eps) return 1; + if (a < -eps) return -1; + else return 0; +} + +MINLINE int signum_i(float a) +{ + if (a > 0.0f) return 1; + if (a < 0.0f) return -1; + else return 0; +} #endif /* __MATH_BASE_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 015313431cb..05a527c4f7a 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -50,6 +50,21 @@ void cent_quad_v3(float cent[3], const float v1[3], const float v2[3], const flo cent[2] = 0.25f * (v1[2] + v2[2] + v3[2] + v4[2]); } +void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]) +{ + float n1[3], n2[3]; + + n1[0] = v1[0] - v2[0]; + n2[0] = v2[0] - v3[0]; + n1[1] = v1[1] - v2[1]; + n2[1] = v2[1] - v3[1]; + n1[2] = v1[2] - v2[2]; + n2[2] = v2[2] - v3[2]; + n[0] = n1[1] * n2[2] - n1[2] * n2[1]; + n[1] = n1[2] * n2[0] - n1[0] * n2[2]; + n[2] = n1[0] * n2[1] - n1[1] * n2[0]; +} + float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]) { float n1[3], n2[3]; @@ -94,58 +109,44 @@ float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const flo */ float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr) { - const float *v_prev = verts[nr - 1]; - const float *v_curr = verts[0]; - unsigned int i; - - zero_v3(n); - - /* Newell's Method */ - for (i = 0; i < nr; v_prev = v_curr, v_curr = verts[++i]) { - add_newell_cross_v3_v3v3(n, v_prev, v_curr); - } - + cross_poly_v3(n, verts, nr); return normalize_v3(n); } -/* only convex Quadrilaterals */ float area_quad_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) { - float len, vec1[3], vec2[3], n[3]; - - sub_v3_v3v3(vec1, v2, v1); - sub_v3_v3v3(vec2, v4, v1); - cross_v3_v3v3(n, vec1, vec2); - len = len_v3(n); - - sub_v3_v3v3(vec1, v4, v3); - sub_v3_v3v3(vec2, v2, v3); - cross_v3_v3v3(n, vec1, vec2); - len += len_v3(n); + const float verts[4][3] = {{UNPACK3(v1)}, {UNPACK3(v2)}, {UNPACK3(v3)}, {UNPACK3(v4)}}; + return area_poly_v3(verts, 4); +} - return (len / 2.0f); +float area_squared_quad_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) +{ + const float verts[4][3] = {{UNPACK3(v1)}, {UNPACK3(v2)}, {UNPACK3(v3)}, {UNPACK3(v4)}}; + return area_squared_poly_v3(verts, 4); } /* Triangles */ float area_tri_v3(const float v1[3], const float v2[3], const float v3[3]) { - float vec1[3], vec2[3], n[3]; - - sub_v3_v3v3(vec1, v3, v2); - sub_v3_v3v3(vec2, v1, v2); - cross_v3_v3v3(n, vec1, vec2); + float n[3]; + cross_tri_v3(n, v1, v2, v3); + return len_v3(n) * 0.5f; +} - return len_v3(n) / 2.0f; +float area_squared_tri_v3(const float v1[3], const float v2[3], const float v3[3]) +{ + float n[3]; + cross_tri_v3(n, v1, v2, v3); + mul_v3_fl(n, 0.5f); + return len_squared_v3(n); } float area_tri_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float normal[3]) { - float area, vec1[3], vec2[3], n[3]; + float area, n[3]; - sub_v3_v3v3(vec1, v3, v2); - sub_v3_v3v3(vec2, v1, v2); - cross_v3_v3v3(n, vec1, vec2); - area = len_v3(n) / 2.0f; + cross_tri_v3(n, v1, v2, v3); + area = len_v3(n) * 0.5f; /* negate area for flipped triangles */ if (dot_v3v3(n, normal) < 0.0f) @@ -157,7 +158,17 @@ float area_tri_signed_v3(const float v1[3], const float v2[3], const float v3[3] float area_poly_v3(const float verts[][3], unsigned int nr) { float n[3]; - return normal_poly_v3(n, verts, nr) * 0.5f; + cross_poly_v3(n, verts, nr); + return len_v3(n) * 0.5f; +} + +float area_squared_poly_v3(const float verts[][3], unsigned int nr) +{ + float n[3]; + + cross_poly_v3(n, verts, nr); + mul_v3_fl(n, 0.5f); + return len_squared_v3(n); } /** @@ -185,11 +196,36 @@ float cross_poly_v2(const float verts[][2], unsigned int nr) return cross; } +void cross_poly_v3(float n[3], const float verts[][3], unsigned int nr) +{ + const float *v_prev = verts[nr - 1]; + const float *v_curr = verts[0]; + unsigned int i; + + zero_v3(n); + + /* Newell's Method */ + for (i = 0; i < nr; v_prev = v_curr, v_curr = verts[++i]) { + add_newell_cross_v3_v3v3(n, v_prev, v_curr); + } +} + float area_poly_v2(const float verts[][2], unsigned int nr) { return fabsf(0.5f * cross_poly_v2(verts, nr)); } +float area_poly_signed_v2(const float verts[][2], unsigned int nr) +{ + return (0.5f * cross_poly_v2(verts, nr)); +} + +float area_squared_poly_v2(const float verts[][2], unsigned int nr) +{ + float area = area_poly_signed_v2(verts, nr); + return area * area; +} + float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3]) { float a[3], b[3], c[3], c_len; @@ -912,12 +948,12 @@ bool isect_point_tri_v2_cw(const float pt[2], const float v1[2], const float v2[ if (line_point_side_v2(v1, v2, pt) >= 0.0f) { if (line_point_side_v2(v2, v3, pt) >= 0.0f) { if (line_point_side_v2(v3, v1, pt) >= 0.0f) { - return 1; + return true; } } } - return 0; + return false; } int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2]) @@ -983,28 +1019,28 @@ bool isect_line_tri_v3(const float p1[3], const float p2[3], cross_v3_v3v3(p, d, e2); a = dot_v3v3(e1, p); - if (a == 0.0f) return 0; + if (a == 0.0f) return false; f = 1.0f / a; sub_v3_v3v3(s, p1, v0); u = f * dot_v3v3(s, p); - if ((u < 0.0f) || (u > 1.0f)) return 0; + if ((u < 0.0f) || (u > 1.0f)) return false; cross_v3_v3v3(q, s, e1); v = f * dot_v3v3(d, q); - if ((v < 0.0f) || ((u + v) > 1.0f)) return 0; + if ((v < 0.0f) || ((u + v) > 1.0f)) return false; *r_lambda = f * dot_v3v3(e2, q); - if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return 0; + if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return false; if (r_uv) { r_uv[0] = u; r_uv[1] = v; } - return 1; + return true; } /* like isect_line_tri_v3, but allows epsilon tolerance around triangle */ @@ -1022,28 +1058,28 @@ bool isect_line_tri_epsilon_v3(const float p1[3], const float p2[3], cross_v3_v3v3(p, d, e2); a = dot_v3v3(e1, p); - if (a == 0.0f) return 0; + if (a == 0.0f) return false; f = 1.0f / a; sub_v3_v3v3(s, p1, v0); u = f * dot_v3v3(s, p); - if ((u < -epsilon) || (u > 1.0f + epsilon)) return 0; + if ((u < -epsilon) || (u > 1.0f + epsilon)) return false; cross_v3_v3v3(q, s, e1); v = f * dot_v3v3(d, q); - if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) return 0; + if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) return false; *r_lambda = f * dot_v3v3(e2, q); - if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return 0; + if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return false; if (r_uv) { r_uv[0] = u; r_uv[1] = v; } - return 1; + return true; } /* moved from effect.c @@ -1064,28 +1100,28 @@ bool isect_ray_tri_v3(const float p1[3], const float d[3], a = dot_v3v3(e1, p); /* note: these values were 0.000001 in 2.4x but for projection snapping on * a human head (1BU == 1m), subsurf level 2, this gave many errors - campbell */ - if ((a > -0.00000001f) && (a < 0.00000001f)) return 0; + if ((a > -0.00000001f) && (a < 0.00000001f)) return false; f = 1.0f / a; sub_v3_v3v3(s, p1, v0); u = f * dot_v3v3(s, p); - if ((u < 0.0f) || (u > 1.0f)) return 0; + if ((u < 0.0f) || (u > 1.0f)) return false; cross_v3_v3v3(q, s, e1); v = f * dot_v3v3(d, q); - if ((v < 0.0f) || ((u + v) > 1.0f)) return 0; + if ((v < 0.0f) || ((u + v) > 1.0f)) return false; *r_lambda = f * dot_v3v3(e2, q); - if ((*r_lambda < 0.0f)) return 0; + if ((*r_lambda < 0.0f)) return false; if (r_uv) { r_uv[0] = u; r_uv[1] = v; } - return 1; + return true; } /** @@ -1107,7 +1143,7 @@ bool isect_ray_plane_v3(const float p1[3], const float d[3], a = dot_v3v3(e1, p); /* note: these values were 0.000001 in 2.4x but for projection snapping on * a human head (1BU == 1m), subsurf level 2, this gave many errors - campbell */ - if ((a > -0.00000001f) && (a < 0.00000001f)) return 0; + if ((a > -0.00000001f) && (a < 0.00000001f)) return false; f = 1.0f / a; sub_v3_v3v3(s, p1, v0); @@ -1119,9 +1155,9 @@ bool isect_ray_plane_v3(const float p1[3], const float d[3], /* v = f * dot_v3v3(d, q); */ /*UNUSED*/ *r_lambda = f * dot_v3v3(e2, q); - if (clip && (*r_lambda < 0.0f)) return 0; + if (clip && (*r_lambda < 0.0f)) return false; - return 1; + return true; } bool isect_ray_tri_epsilon_v3(const float p1[3], const float d[3], @@ -1142,22 +1178,22 @@ bool isect_ray_tri_epsilon_v3(const float p1[3], const float d[3], sub_v3_v3v3(s, p1, v0); u = f * dot_v3v3(s, p); - if ((u < -epsilon) || (u > 1.0f + epsilon)) return 0; + if ((u < -epsilon) || (u > 1.0f + epsilon)) return false; cross_v3_v3v3(q, s, e1); v = f * dot_v3v3(d, q); - if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) return 0; + if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) return false; *r_lambda = f * dot_v3v3(e2, q); - if ((*r_lambda < 0.0f)) return 0; + if ((*r_lambda < 0.0f)) return false; if (uv) { uv[0] = u; uv[1] = v; } - return 1; + return true; } bool isect_ray_tri_threshold_v3(const float p1[3], const float d[3], @@ -1173,14 +1209,14 @@ bool isect_ray_tri_threshold_v3(const float p1[3], const float d[3], cross_v3_v3v3(p, d, e2); a = dot_v3v3(e1, p); - if ((a > -0.000001f) && (a < 0.000001f)) return 0; + if ((a > -0.000001f) && (a < 0.000001f)) return false; f = 1.0f / a; sub_v3_v3v3(s, p1, v0); cross_v3_v3v3(q, s, e1); *r_lambda = f * dot_v3v3(e2, q); - if ((*r_lambda < 0.0f)) return 0; + if ((*r_lambda < 0.0f)) return false; u = f * dot_v3v3(s, p); v = f * dot_v3v3(d, q); @@ -1204,7 +1240,7 @@ bool isect_ray_tri_threshold_v3(const float p1[3], const float d[3], mul_v3_fl(e2, dv); if (len_squared_v3(e1) + len_squared_v3(e2) > threshold * threshold) { - return 0; + return false; } if (r_uv) { @@ -1212,7 +1248,7 @@ bool isect_ray_tri_threshold_v3(const float p1[3], const float d[3], r_uv[1] = v; } - return 1; + return true; } /** @@ -1363,7 +1399,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (t0 > t1) SWAP(float, t0, t1); - if (t0 > 1.0f || t1 < 0.0f) return 0; + if (t0 > 1.0f || t1 < 0.0f) return false; /* clamp to [0, 1] */ CLAMP(t0, 0.0f, 1.0f); @@ -1542,7 +1578,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 if ((f > -0.000001f) && (f < 0.000001f)) return false; v = (p[a2] * e1[a1] - p[a1] * e1[a2]) / f; - if ((v < 0.0f) || (v > 1.0f)) return 0; + if ((v < 0.0f) || (v > 1.0f)) return false; f = e1[a1]; if ((f > -0.000001f) && (f < 0.000001f)) { @@ -1553,7 +1589,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 else u = (-p[a1] - v * e2[a1]) / f; - if ((u < 0.0f) || ((u + v) > 1.0f)) return 0; + if ((u < 0.0f) || ((u + v) > 1.0f)) return false; *r_lambda = (p[a0] + u * e1[a0] + v * e2[a0]) / (p2[a0] - p1[a0]); @@ -1840,7 +1876,7 @@ float line_plane_factor_v3(const float plane_co[3], const float plane_no[3], return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f; } -/** Ensure the distance between these points is no greater then 'dist'. +/** Ensure the distance between these points is no greater than 'dist'. * If it is, scale then both into the center. */ void limit_dist_v3(float v1[3], float v2[3], const float dist) @@ -2350,15 +2386,15 @@ bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[ } /** - * \note: using #area_tri_signed_v2 means locations outside the triangle are correctly weighted + * \note: using #cross_tri_v2 means locations outside the triangle are correctly weighted */ void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) { float wtot; - w[0] = area_tri_signed_v2(v2, v3, co); - w[1] = area_tri_signed_v2(v3, v1, co); - w[2] = area_tri_signed_v2(v1, v2, co); + w[0] = cross_tri_v2(v2, v3, co); + w[1] = cross_tri_v2(v3, v1, co); + w[2] = cross_tri_v2(v1, v2, co); wtot = w[0] + w[1] + w[2]; if (wtot != 0.0f) { @@ -2377,9 +2413,9 @@ void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const fl { float wtot; - w[0] = area_tri_signed_v2(v2, v3, co) / v1[3]; - w[1] = area_tri_signed_v2(v3, v1, co) / v2[3]; - w[2] = area_tri_signed_v2(v1, v2, co) / v3[3]; + w[0] = cross_tri_v2(v2, v3, co) / v1[3]; + w[1] = cross_tri_v2(v3, v1, co) / v2[3]; + w[2] = cross_tri_v2(v1, v2, co) / v3[3]; wtot = w[0] + w[1] + w[2]; if (wtot != 0.0f) { @@ -2602,38 +2638,55 @@ int interp_sparse_array(float *array, const int list_size, const float skipval) return 1; } +/** \name interp_weights_poly_v2, v3 + * \{ */ + +#define IS_POINT_IX (1 << 0) +#define IS_SEGMENT_IX (1 << 1) + +#define DIR_V3_SET(d_len, va, vb) { \ + sub_v3_v3v3((d_len)->dir, va, vb); \ + (d_len)->len = len_v3((d_len)->dir); \ +} (void)0 + +#define DIR_V2_SET(d_len, va, vb) { \ + sub_v2_v2v2((d_len)->dir, va, vb); \ + (d_len)->len = len_v2((d_len)->dir); \ +} (void)0 + +struct Float3_Len { + float dir[3], len; +}; + +struct Float2_Len { + float dir[2], len; +}; + /* Mean value weights - smooth interpolation weights for polygons with * more than 3 vertices */ -static float mean_value_half_tan_v3(const float v1[3], const float v2[3], const float v3[3]) +static float mean_value_half_tan_v3(const struct Float3_Len *d_curr, const struct Float3_Len *d_next) { - float d2[3], d3[3], cross[3], area; - - sub_v3_v3v3(d2, v2, v1); - sub_v3_v3v3(d3, v3, v1); - cross_v3_v3v3(cross, d2, d3); - + float cross[3], area; + cross_v3_v3v3(cross, d_curr->dir, d_next->dir); area = len_v3(cross); if (LIKELY(area != 0.0f)) { - const float dot = dot_v3v3(d2, d3); - const float len = len_v3(d2) * len_v3(d3); + const float dot = dot_v3v3(d_curr->dir, d_next->dir); + const float len = d_curr->len * d_next->len; return (len - dot) / area; } else { return 0.0f; } } -static float mean_value_half_tan_v2(const float v1[2], const float v2[2], const float v3[2]) -{ - float d2[2], d3[2], area; - - sub_v2_v2v2(d2, v2, v1); - sub_v2_v2v2(d3, v3, v1); +static float mean_value_half_tan_v2(const struct Float2_Len *d_curr, const struct Float2_Len *d_next) +{ + float area; /* different from the 3d version but still correct */ - area = cross_v2v2(d2, d3); + area = cross_v2v2(d_curr->dir, d_next->dir); if (LIKELY(area != 0.0f)) { - const float dot = dot_v2v2(d2, d3); - const float len = len_v2(d2) * len_v2(d3); + const float dot = dot_v2v2(d_curr->dir, d_next->dir); + const float len = d_curr->len * d_next->len; return (len - dot) / area; } else { @@ -2649,30 +2702,34 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ float ht_prev, ht; /* half tangents */ float totweight = 0.0f; int i = 0; - bool vert_interp = false; - bool edge_interp = false; + char ix_flag = 0; + struct Float3_Len d_curr, d_next; v_curr = v[0]; v_next = v[1]; - ht_prev = mean_value_half_tan_v3(co, v[n - 1], v_curr); + DIR_V3_SET(&d_curr, v[n - 1], co); + DIR_V3_SET(&d_next, v_curr, co); + ht_prev = mean_value_half_tan_v3(&d_curr, &d_next); while (i < n) { - const float len_sq = len_squared_v3v3(co, v_curr); - /* Mark Mayer et al algorithm that is used here does not operate well if vertex is close * to borders of face. In that case, do simple linear interpolation between the two edge vertices */ - if (len_sq < eps_sq) { - vert_interp = true; + + /* 'd_next.len' is infact 'd_curr.len', just avoid copy to begin with */ + if (UNLIKELY(d_next.len < eps)) { + ix_flag = IS_POINT_IX; break; } - else if (dist_squared_to_line_segment_v3(co, v_curr, v_next) < eps_sq) { - edge_interp = true; + else if (UNLIKELY(dist_squared_to_line_segment_v3(co, v_curr, v_next) < eps_sq)) { + ix_flag = IS_SEGMENT_IX; break; } - ht = mean_value_half_tan_v3(co, v_curr, v_next); - w[i] = (ht_prev + ht) / sqrtf(len_sq); + d_curr = d_next; + DIR_V3_SET(&d_next, v_next, co); + ht = mean_value_half_tan_v3(&d_curr, &d_next); + w[i] = (ht_prev + ht) / d_curr.len; totweight += w[i]; /* step */ @@ -2683,22 +2740,21 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ ht_prev = ht; } - if (vert_interp) { + if (ix_flag) { const int i_curr = i; - for (i = 0; i < n; i++) - w[i] = 0.0; - w[i_curr] = 1.0f; - } - else if (edge_interp) { - const int i_curr = i; - float len_curr = len_v3v3(co, v_curr); - float len_next = len_v3v3(co, v_next); - float edge_len = len_curr + len_next; - for (i = 0; i < n; i++) - w[i] = 0.0; + for (i = 0; i < n; i++) { + w[i] = 0.0f; + } - w[i_curr] = len_next / edge_len; - w[(i_curr + 1) % n] = len_curr / edge_len; + if (ix_flag & IS_POINT_IX) { + w[i_curr] = 1.0f; + } + else { + float fac = line_point_factor_v3(co, v_curr, v_next); + CLAMP(fac, 0.0f, 1.0f); + w[i_curr] = 1.0f - fac; + w[(i_curr + 1) % n] = fac; + } } else { if (totweight != 0.0f) { @@ -2718,30 +2774,34 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ float ht_prev, ht; /* half tangents */ float totweight = 0.0f; int i = 0; - bool vert_interp = false; - bool edge_interp = false; + char ix_flag = 0; + struct Float2_Len d_curr, d_next; v_curr = v[0]; v_next = v[1]; - ht_prev = mean_value_half_tan_v2(co, v[n - 1], v_curr); + DIR_V2_SET(&d_curr, v[n - 1], co); + DIR_V2_SET(&d_next, v_curr, co); + ht_prev = mean_value_half_tan_v2(&d_curr, &d_next); while (i < n) { - const float len_sq = len_squared_v2v2(co, v_curr); - /* Mark Mayer et al algorithm that is used here does not operate well if vertex is close * to borders of face. In that case, do simple linear interpolation between the two edge vertices */ - if (len_sq < eps_sq) { - vert_interp = true; + + /* 'd_next.len' is infact 'd_curr.len', just avoid copy to begin with */ + if (UNLIKELY(d_next.len < eps)) { + ix_flag = IS_POINT_IX; break; } - else if (dist_squared_to_line_segment_v2(co, v_curr, v_next) < eps_sq) { - edge_interp = true; + else if (UNLIKELY(dist_squared_to_line_segment_v2(co, v_curr, v_next) < eps_sq)) { + ix_flag = IS_SEGMENT_IX; break; } - ht = mean_value_half_tan_v2(co, v_curr, v_next); - w[i] = (ht_prev + ht) / sqrtf(len_sq); + d_curr = d_next; + DIR_V2_SET(&d_next, v_next, co); + ht = mean_value_half_tan_v2(&d_curr, &d_next); + w[i] = (ht_prev + ht) / d_curr.len; totweight += w[i]; /* step */ @@ -2752,22 +2812,21 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ ht_prev = ht; } - if (vert_interp) { - const int i_curr = i; - for (i = 0; i < n; i++) - w[i] = 0.0; - w[i_curr] = 1.0f; - } - else if (edge_interp) { + if (ix_flag) { const int i_curr = i; - float len_curr = len_v2v2(co, v_curr); - float len_next = len_v2v2(co, v_next); - float edge_len = len_curr + len_next; - for (i = 0; i < n; i++) - w[i] = 0.0; + for (i = 0; i < n; i++) { + w[i] = 0.0f; + } - w[i_curr] = len_next / edge_len; - w[(i_curr + 1) % n] = len_curr / edge_len; + if (ix_flag & IS_POINT_IX) { + w[i_curr] = 1.0f; + } + else { + float fac = line_point_factor_v2(co, v_curr, v_next); + CLAMP(fac, 0.0f, 1.0f); + w[i_curr] = 1.0f - fac; + w[(i_curr + 1) % n] = fac; + } } else { if (totweight != 0.0f) { @@ -2778,6 +2837,15 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ } } +#undef IS_POINT_IX +#undef IS_SEGMENT_IX + +#undef DIR_V3_SET +#undef DIR_V2_SET + +/** \} */ + + /* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */ void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t) { @@ -3057,6 +3125,59 @@ void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x } } +/** + * Frustum planes extraction from a projection matrix (homogeneous 4d vector representations of planes). + * + * plane parameters can be NULL if you do not need them. + */ +void planes_from_projmat(float mat[4][4], float left[4], float right[4], float top[4], float bottom[4], + float near[4], float far[4]) +{ + /* References: + * + * https://fgiesen.wordpress.com/2012/08/31/frustum-planes-from-the-projection-matrix/ + * http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf + */ + + int i; + + if (left) { + for (i = 4; i--; ) { + left[i] = mat[i][3] + mat[i][0]; + } + } + + if (right) { + for (i = 4; i--; ) { + right[i] = mat[i][3] - mat[i][0]; + } + } + + if (bottom) { + for (i = 4; i--; ) { + bottom[i] = mat[i][3] + mat[i][1]; + } + } + + if (top) { + for (i = 4; i--; ) { + top[i] = mat[i][3] - mat[i][1]; + } + } + + if (near) { + for (i = 4; i--; ) { + near[i] = mat[i][3] + mat[i][2]; + } + } + + if (far) { + for (i = 4; i--; ) { + far[i] = mat[i][3] - mat[i][2]; + } + } +} + static void i_multmatrix(float icand[4][4], float Vm[4][4]) { int row, col; @@ -4016,3 +4137,31 @@ bool is_poly_convex_v2(const float verts[][2], unsigned int nr) return true; } + +/** + * Check if either of the diagonals along this quad create flipped triangles + * (normals pointing away from eachother). + * - (1 << 0): (v1-v3) is flipped. + * - (1 << 1): (v2-v4) is flipped. + */ +int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) +{ + float d_12[3], d_23[3], d_34[3], d_41[3]; + float cross_a[3], cross_b[3]; + int ret = 0; + + sub_v3_v3v3(d_12, v1, v2); + sub_v3_v3v3(d_23, v2, v3); + sub_v3_v3v3(d_34, v3, v4); + sub_v3_v3v3(d_41, v4, v1); + + cross_v3_v3v3(cross_a, d_12, d_23); + cross_v3_v3v3(cross_b, d_34, d_41); + ret |= ((dot_v3v3(cross_a, cross_b) < 0.0f) << 0); + + cross_v3_v3v3(cross_a, d_23, d_34); + cross_v3_v3v3(cross_b, d_41, d_12); + ret |= ((dot_v3v3(cross_a, cross_b) < 0.0f) << 1); + + return ret; +} diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c index 5a64ed63ecf..44b17681540 100644 --- a/source/blender/blenlib/intern/math_geom_inline.c +++ b/source/blender/blenlib/intern/math_geom_inline.c @@ -54,6 +54,12 @@ MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2 return fabsf(area_tri_signed_v2(v1, v2, v3)); } +MINLINE float area_squared_tri_v2(const float v1[2], const float v2[2], const float v3[2]) +{ + float area = area_tri_signed_v2(v1, v2, v3); + return area * area; +} + /****************************** Spherical Harmonics **************************/ MINLINE void zero_sh(float r[9]) diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 0204c3bc86c..1b4bbafdb04 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -848,9 +848,10 @@ bool invert_m4_m4(float inverse[4][4], float mat[4][4]) } } - temp = tempmat[i][i]; - if (temp == 0) - return 0; /* No non-zero pivot */ + if (UNLIKELY(tempmat[i][i] == 0.0f)) { + return false; /* No non-zero pivot */ + } + temp = (double)tempmat[i][i]; for (k = 0; k < 4; k++) { tempmat[i][k] = (float)((double)tempmat[i][k] / temp); inverse[i][k] = (float)((double)inverse[i][k] / temp); @@ -865,7 +866,7 @@ bool invert_m4_m4(float inverse[4][4], float mat[4][4]) } } } - return 1; + return true; } /****************************** Linear Algebra *******************************/ @@ -1149,11 +1150,11 @@ bool is_orthogonal_m3(float m[3][3]) for (i = 0; i < 3; i++) { for (j = 0; j < i; j++) { if (fabsf(dot_v3v3(m[i], m[j])) > 1.5f * FLT_EPSILON) - return 0; + return false; } } - return 1; + return true; } bool is_orthogonal_m4(float m[4][4]) @@ -1163,12 +1164,12 @@ bool is_orthogonal_m4(float m[4][4]) for (i = 0; i < 4; i++) { for (j = 0; j < i; j++) { if (fabsf(dot_v4v4(m[i], m[j])) > 1.5f * FLT_EPSILON) - return 0; + return false; } } - return 1; + return true; } bool is_orthonormal_m3(float m[3][3]) @@ -1178,12 +1179,12 @@ bool is_orthonormal_m3(float m[3][3]) for (i = 0; i < 3; i++) if (fabsf(dot_v3v3(m[i], m[i]) - 1) > 1.5f * FLT_EPSILON) - return 0; + return false; - return 1; + return true; } - return 0; + return false; } bool is_orthonormal_m4(float m[4][4]) @@ -1193,12 +1194,12 @@ bool is_orthonormal_m4(float m[4][4]) for (i = 0; i < 4; i++) if (fabsf(dot_v4v4(m[i], m[i]) - 1) > 1.5f * FLT_EPSILON) - return 0; + return false; - return 1; + return true; } - return 0; + return false; } bool is_uniform_scaled_m3(float m[3][3]) @@ -1448,7 +1449,7 @@ float mat3_to_scale(float mat[3][3]) { /* unit length vector */ float unit_vec[3]; - copy_v3_fl(unit_vec, (float)(1.0 / M_SQRT3)); + copy_v3_fl(unit_vec, (float)M_SQRT1_3); mul_m3_v3(mat, unit_vec); return len_v3(unit_vec); } @@ -1457,7 +1458,7 @@ float mat4_to_scale(float mat[4][4]) { /* unit length vector */ float unit_vec[3]; - copy_v3_fl(unit_vec, (float)(1.0 / M_SQRT3)); + copy_v3_fl(unit_vec, (float)M_SQRT1_3); mul_mat3_m4_v3(mat, unit_vec); return len_v3(unit_vec); } diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index 9a6515daf68..3ac031d7b90 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -1867,7 +1867,7 @@ float angle_wrap_deg(float angle) /* returns an angle compatible with angle_compat */ float angle_compat_rad(float angle, float angle_compat) { - return angle + (floorf(((angle_compat - angle) / (float)M_PI) + 0.5f)) * (float)M_PI; + return angle_compat + angle_wrap_rad(angle - angle_compat); } /* axis conversion */ diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index da9d5bd3f49..6b6a3113e0b 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -621,6 +621,18 @@ MINLINE float dot_v3v3(const float a[3], const float b[3]) return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } +MINLINE float dot_v3v3v3(const float p[3], const float a[3], const float b[3]) +{ + float vec1[3], vec2[3]; + + sub_v3_v3v3(vec1, a, p); + sub_v3_v3v3(vec2, b, p); + if (is_zero_v3(vec1) || is_zero_v3(vec2)) { + return 0.0f; + } + return dot_v3v3(vec1, vec2); +} + MINLINE float dot_v4v4(const float a[4], const float b[4]) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index e3e13b0bcac..3fff22218e2 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -45,12 +45,6 @@ #include "BLI_string_utf8.h" #include "BLI_fnmatch.h" -#include "../blenkernel/BKE_blender.h" /* BLENDER_VERSION, bad level include (no function call) */ - -#include "GHOST_Path-api.h" - -#include "MEM_guardedalloc.h" - #ifdef WIN32 # include "utf_winfunc.h" # include "utfconv.h" @@ -62,21 +56,12 @@ # include <windows.h> # include <shlobj.h> # include "BLI_winstuff.h" -#else /* non windows */ -# ifdef WITH_BINRELOC -# include "binreloc.h" -# endif -# include <unistd.h> /* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */ +# include "MEM_guardedalloc.h" #endif /* WIN32 */ /* local */ #define UNIQUE_NAME_MAX 128 -static char bprogname[FILE_MAX]; /* full path to program executable */ -static char bprogdir[FILE_MAX]; /* full path to directory in which executable is located */ -static char btempdir_base[FILE_MAX]; /* persistent temporary directory */ -static char btempdir_session[FILE_MAX] = ""; /* volatile temporary directory */ - /* implementation */ /** @@ -243,7 +228,8 @@ bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name), int number; int len = BLI_split_name_num(left, &number, name, delim); do { - const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number); + /* add 1 to account for \0 */ + const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1; /* highly unlikely the string only has enough room for the number * but support anyway */ @@ -253,9 +239,8 @@ bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name), } else { char *tempname_buf; - tempname[0] = '\0'; - tempname_buf = BLI_strncat_utf8(tempname, left, name_len - numlen); - memcpy(tempname_buf, numstr, numlen + 1); + tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen); + memcpy(tempname_buf, numstr, numlen); } } while (unique_check(arg, tempname)); @@ -954,8 +939,6 @@ bool BLI_path_abs(char *path, const char *basepath) BLI_strncpy(path, tmp, FILE_MAX); } - BLI_cleanup_path(NULL, path); - #ifdef WIN32 /* skip first two chars, which in case of * absolute path will be drive:/blabla and @@ -965,7 +948,10 @@ bool BLI_path_abs(char *path, const char *basepath) */ BLI_char_switch(path + 2, '/', '\\'); #endif - + + /* ensure this is after correcting for path switch */ + BLI_cleanup_path(NULL, path); + return wasrelative; } @@ -1038,446 +1024,6 @@ void BLI_getlastdir(const char *dir, char *last, const size_t maxlen) } } -/* This is now only used to really get the user's default document folder */ -/* On Windows I chose the 'Users/<MyUserName>/Documents' since it's used - * as default location to save documents */ -const char *BLI_getDefaultDocumentFolder(void) -{ -#ifndef WIN32 - const char * const xdg_documents_dir = getenv("XDG_DOCUMENTS_DIR"); - - if (xdg_documents_dir) - return xdg_documents_dir; - - return getenv("HOME"); -#else /* Windows */ - static char documentfolder[MAXPATHLEN]; - HRESULT hResult; - - /* Check for %HOME% env var */ - if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) { - if (BLI_is_dir(documentfolder)) return documentfolder; - } - - /* add user profile support for WIN 2K / NT. - * This is %APPDATA%, which translates to either - * %USERPROFILE%\Application Data or since Vista - * to %USERPROFILE%\AppData\Roaming - */ - hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder); - - if (hResult == S_OK) { - if (BLI_is_dir(documentfolder)) return documentfolder; - } - - return NULL; -#endif /* WIN32 */ -} - -/* NEW stuff, to be cleaned up when fully migrated */ -/* ************************************************************* */ -/* ************************************************************* */ - -// #define PATH_DEBUG - -/* returns a formatted representation of the specified version number. Non-reentrant! */ -static char *blender_version_decimal(const int ver) -{ - static char version_str[5]; - sprintf(version_str, "%d.%02d", ver / 100, ver % 100); - return version_str; -} - -/** - * Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath, - * returning true if result points to a directory. - */ -static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name) -{ - char tmppath[FILE_MAX]; - - if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep); - else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); - - /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */ - if (folder_name) - BLI_make_file_string("/", targetpath, tmppath, folder_name); - else - BLI_strncpy(targetpath, tmppath, sizeof(tmppath)); - /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile) - * if folder_name is specified but not otherwise? */ - - if (BLI_is_dir(targetpath)) { -#ifdef PATH_DEBUG - printf("\t%s found: %s\n", __func__, targetpath); -#endif - return true; - } - else { -#ifdef PATH_DEBUG - printf("\t%s missing: %s\n", __func__, targetpath); -#endif - //targetpath[0] = '\0'; - return false; - } -} - -/** - * Puts the value of the specified environment variable into *path if it exists - * and points at a directory. Returns true if this was done. - */ -static bool test_env_path(char *path, const char *envvar) -{ - const char *env = envvar ? getenv(envvar) : NULL; - if (!env) return false; - - if (BLI_is_dir(env)) { - BLI_strncpy(path, env, FILE_MAX); -#ifdef PATH_DEBUG - printf("\t%s env %s found: %s\n", __func__, envvar, env); -#endif - return true; - } - else { - path[0] = '\0'; -#ifdef PATH_DEBUG - printf("\t%s env %s missing: %s\n", __func__, envvar, env); -#endif - return false; - } -} - -/** - * Constructs in \a targetpath the name of a directory relative to a version-specific - * subdirectory in the parent directory of the Blender executable. - * - * \param targetpath String to return path - * \param folder_name Optional folder name within version-specific directory - * \param subfolder_name Optional subfolder name within folder_name - * \param ver To construct name of version-specific directory within bprogdir - * \return true if such a directory exists. - */ -static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver) -{ - char relfolder[FILE_MAX]; - -#ifdef PATH_DEBUG - printf("%s...\n", __func__); -#endif - - if (folder_name) { - if (subfolder_name) { - BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name); - } - else { - BLI_strncpy(relfolder, folder_name, sizeof(relfolder)); - } - } - else { - relfolder[0] = '\0'; - } - - /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ -#ifdef __APPLE__ - static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */ - sprintf(osx_resourses, "%s../Resources", bprogdir); - return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder); -#else - return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder); -#endif -} - -/** - * Is this an install with user files kept together with the Blender executable and its - * installation files. - */ -static bool is_portable_install(void) -{ - /* detect portable install by the existence of config folder */ - const int ver = BLENDER_VERSION; - char path[FILE_MAX]; - - return get_path_local(path, "config", NULL, ver); -} - -/** - * Returns the path of a folder within the user-files area. - * - * - * \param targetpath String to return path - * \param folder_name default name of folder within user area - * \param subfolder_name optional name of subfolder within folder - * \param envvar name of environment variable which, if defined, overrides folder_name - * \param ver Blender version, used to construct a subdirectory name - * \return true if it was able to construct such a path. - */ -static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) -{ - char user_path[FILE_MAX]; - const char *user_base_path; - - /* for portable install, user path is always local */ - if (is_portable_install()) - return get_path_local(targetpath, folder_name, subfolder_name, ver); - - user_path[0] = '\0'; - - if (test_env_path(user_path, envvar)) { - if (subfolder_name) { - return test_path(targetpath, user_path, NULL, subfolder_name); - } - else { - BLI_strncpy(targetpath, user_path, FILE_MAX); - return true; - } - } - - user_base_path = (const char *)GHOST_getUserDir(ver, blender_version_decimal(ver)); - if (user_base_path) - BLI_strncpy(user_path, user_base_path, FILE_MAX); - - if (!user_path[0]) - return false; - -#ifdef PATH_DEBUG - printf("%s: %s\n", __func__, user_path); -#endif - - if (subfolder_name) { - return test_path(targetpath, user_path, folder_name, subfolder_name); - } - else { - return test_path(targetpath, user_path, NULL, folder_name); - } -} - -/** - * Returns the path of a folder within the Blender installation directory. - * - * \param targetpath String to return path - * \param folder_name default name of folder within installation area - * \param subfolder_name optional name of subfolder within folder - * \param envvar name of environment variable which, if defined, overrides folder_name - * \param ver Blender version, used to construct a subdirectory name - * \return true if it was able to construct such a path. - */ -static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) -{ - char system_path[FILE_MAX]; - const char *system_base_path; - char cwd[FILE_MAX]; - char relfolder[FILE_MAX]; - - if (folder_name) { - if (subfolder_name) { - BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name); - } - else { - BLI_strncpy(relfolder, folder_name, sizeof(relfolder)); - } - } - else { - relfolder[0] = '\0'; - } - - /* first allow developer only overrides to the system path - * these are only used when running blender from source */ - - /* try CWD/release/folder_name */ - if (BLI_current_working_dir(cwd, sizeof(cwd))) { - if (test_path(targetpath, cwd, "release", relfolder)) { - return true; - } - } - - /* try EXECUTABLE_DIR/release/folder_name */ - if (test_path(targetpath, bprogdir, "release", relfolder)) - return true; - - /* end developer overrides */ - - - - system_path[0] = '\0'; - - if (test_env_path(system_path, envvar)) { - if (subfolder_name) { - return test_path(targetpath, system_path, NULL, subfolder_name); - } - else { - BLI_strncpy(targetpath, system_path, FILE_MAX); - return true; - } - } - - system_base_path = (const char *)GHOST_getSystemDir(ver, blender_version_decimal(ver)); - if (system_base_path) - BLI_strncpy(system_path, system_base_path, FILE_MAX); - - if (!system_path[0]) - return false; - -#ifdef PATH_DEBUG - printf("%s: %s\n", __func__, system_path); -#endif - - if (subfolder_name) { - /* try $BLENDERPATH/folder_name/subfolder_name */ - return test_path(targetpath, system_path, folder_name, subfolder_name); - } - else { - /* try $BLENDERPATH/folder_name */ - return test_path(targetpath, system_path, NULL, folder_name); - } -} - -/* get a folder out of the 'folder_id' presets for paths */ -/* returns the path if found, NULL string if not */ -const char *BLI_get_folder(int folder_id, const char *subfolder) -{ - const int ver = BLENDER_VERSION; - static char path[FILE_MAX] = ""; - - switch (folder_id) { - case BLENDER_DATAFILES: /* general case */ - if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; - if (get_path_local(path, "datafiles", subfolder, ver)) break; - if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; - return NULL; - - case BLENDER_USER_DATAFILES: - if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; - return NULL; - - case BLENDER_SYSTEM_DATAFILES: - if (get_path_local(path, "datafiles", subfolder, ver)) break; - if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; - return NULL; - - case BLENDER_USER_AUTOSAVE: - if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break; - return NULL; - - case BLENDER_USER_CONFIG: - if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break; - return NULL; - - case BLENDER_USER_SCRIPTS: - if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break; - return NULL; - - case BLENDER_SYSTEM_SCRIPTS: - if (get_path_local(path, "scripts", subfolder, ver)) break; - if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break; - return NULL; - - case BLENDER_SYSTEM_PYTHON: - if (get_path_local(path, "python", subfolder, ver)) break; - if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break; - return NULL; - - default: - BLI_assert(0); - break; - } - - return path; -} - -/** - * Returns the path to a folder in the user area without checking that it actually exists first. - */ -const char *BLI_get_user_folder_notest(int folder_id, const char *subfolder) -{ - const int ver = BLENDER_VERSION; - static char path[FILE_MAX] = ""; - - switch (folder_id) { - case BLENDER_USER_DATAFILES: - get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver); - break; - case BLENDER_USER_CONFIG: - get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver); - break; - case BLENDER_USER_AUTOSAVE: - get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver); - break; - case BLENDER_USER_SCRIPTS: - get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver); - break; - default: - BLI_assert(0); - break; - } - - if ('\0' == path[0]) { - return NULL; - } - return path; -} - -/** - * Returns the path to a folder in the user area, creating it if it doesn't exist. - */ -const char *BLI_get_folder_create(int folder_id, const char *subfolder) -{ - const char *path; - - /* only for user folders */ - if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) - return NULL; - - path = BLI_get_folder(folder_id, subfolder); - - if (!path) { - path = BLI_get_user_folder_notest(folder_id, subfolder); - if (path) BLI_dir_create_recursive(path); - } - - return path; -} - -/** - * Returns the path of the top-level version-specific local, user or system directory. - * If do_check, then the result will be NULL if the directory doesn't exist. - */ -const char *BLI_get_folder_version(const int id, const int ver, const bool do_check) -{ - static char path[FILE_MAX] = ""; - bool ok; - switch (id) { - case BLENDER_RESOURCE_PATH_USER: - ok = get_path_user(path, NULL, NULL, NULL, ver); - break; - case BLENDER_RESOURCE_PATH_LOCAL: - ok = get_path_local(path, NULL, NULL, ver); - break; - case BLENDER_RESOURCE_PATH_SYSTEM: - ok = get_path_system(path, NULL, NULL, NULL, ver); - break; - default: - path[0] = '\0'; /* in case do_check is false */ - ok = false; - BLI_assert(!"incorrect ID"); - break; - } - - if (!ok && do_check) { - return NULL; - } - - return path; -} - -/* End new stuff */ -/* ************************************************************* */ -/* ************************************************************* */ - - - -#ifdef PATH_DEBUG -# undef PATH_DEBUG -#endif /** * Sets the specified environment variable to the specified value, @@ -1541,18 +1087,22 @@ void BLI_char_switch(char *string, char from, char to) } /** - * Strips off nonexistent subdirectories from the end of *dir, leaving the path of - * the lowest-level directory that does exist. + * Strips off nonexistent (or non-accessible) subdirectories from the end of *dir, leaving the path of + * the lowest-level directory that does exist and we can read. */ void BLI_make_exist(char *dir) { int a; + char par_path[PATH_MAX + 3]; BLI_char_switch(dir, ALTSEP, SEP); a = strlen(dir); - while (!BLI_is_dir(dir)) { + for (BLI_join_dirfile(par_path, sizeof(par_path), dir, ".."); + !(BLI_is_dir(dir) && BLI_exists(par_path)); + BLI_join_dirfile(par_path, sizeof(par_path), dir, "..")) + { a--; while (dir[a] != SEP) { a--; @@ -1707,11 +1257,10 @@ bool BLI_testextensie_n(const char *str, ...) while ((ext = (const char *) va_arg(args, void *))) { if (testextensie_ex(str, str_len, ext, strlen(ext))) { ret = true; - goto finally; + break; } } -finally: va_end(args); return ret; @@ -2153,310 +1702,6 @@ void BLI_path_native_slash(char *path) #endif } -/** - * Tries appending each of the semicolon-separated extensions in the PATHEXT - * environment variable (Windows-only) onto *name in turn until such a file is found. - * Returns success/failure. - */ -static int add_win32_extension(char *name) -{ - int retval = 0; - int type; - - type = BLI_exists(name); - if ((type == 0) || S_ISDIR(type)) { -#ifdef _WIN32 - char filename[FILE_MAX]; - char ext[FILE_MAX]; - const char *extensions = getenv("PATHEXT"); - if (extensions) { - char *temp; - do { - strcpy(filename, name); - temp = strstr(extensions, ";"); - if (temp) { - strncpy(ext, extensions, temp - extensions); - ext[temp - extensions] = 0; - extensions = temp + 1; - strcat(filename, ext); - } - else { - strcat(filename, extensions); - } - - type = BLI_exists(filename); - if (type && (!S_ISDIR(type))) { - retval = 1; - strcpy(name, filename); - break; - } - } while (temp); - } -#endif - } - else { - retval = 1; - } - - return (retval); -} - -/** - * Checks if name is a fully qualified filename to an executable. - * If not it searches $PATH for the file. On Windows it also - * adds the correct extension (.com .exe etc) from - * $PATHEXT if necessary. Also on Windows it translates - * the name to its 8.3 version to prevent problems with - * spaces and stuff. Final result is returned in fullname. - * - * \param fullname The full path and full name of the executable - * (must be FILE_MAX minimum) - * \param name The name of the executable (usually argv[0]) to be checked - */ -static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name) -{ - char filename[FILE_MAX]; - const char *path = NULL, *temp; - -#ifdef _WIN32 - const char *separator = ";"; -#else - const char *separator = ":"; -#endif - - -#ifdef WITH_BINRELOC - /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */ - path = br_find_exe(NULL); - if (path) { - BLI_strncpy(fullname, path, maxlen); - free((void *)path); - return; - } -#endif - -#ifdef _WIN32 - wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath"); - if (GetModuleFileNameW(0, fullname_16, maxlen)) { - conv_utf_16_to_8(fullname_16, fullname, maxlen); - if (!BLI_exists(fullname)) { - printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname); - MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); - } - MEM_freeN(fullname_16); - return; - } - - MEM_freeN(fullname_16); -#endif - - /* unix and non linux */ - if (name && name[0]) { - - BLI_strncpy(fullname, name, maxlen); - if (name[0] == '.') { - char wdir[FILE_MAX] = ""; - BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */ - - // not needed but avoids annoying /./ in name - if (name[1] == SEP) - BLI_join_dirfile(fullname, maxlen, wdir, name + 2); - else - BLI_join_dirfile(fullname, maxlen, wdir, name); - - add_win32_extension(fullname); /* XXX, doesnt respect length */ - } - else if (BLI_last_slash(name)) { - // full path - BLI_strncpy(fullname, name, maxlen); - add_win32_extension(fullname); - } - else { - // search for binary in $PATH - path = getenv("PATH"); - if (path) { - do { - temp = strstr(path, separator); - if (temp) { - strncpy(filename, path, temp - path); - filename[temp - path] = 0; - path = temp + 1; - } - else { - strncpy(filename, path, sizeof(filename)); - } - BLI_path_append(fullname, maxlen, name); - if (add_win32_extension(filename)) { - BLI_strncpy(fullname, filename, maxlen); - break; - } - } while (temp); - } - } -#if defined(DEBUG) - if (strcmp(name, fullname)) { - printf("guessing '%s' == '%s'\n", name, fullname); - } -#endif - } -} - -void BLI_init_program_path(const char *argv0) -{ - bli_where_am_i(bprogname, sizeof(bprogname), argv0); - BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir)); -} - -/** - * Path to executable - */ -const char *BLI_program_path(void) -{ - return bprogname; -} - -/** - * Path to directory of executable - */ -const char *BLI_program_dir(void) -{ - return bprogdir; -} - -/** - * Gets the temp directory when blender first runs. - * If the default path is not found, use try $TEMP - * - * Also make sure the temp dir has a trailing slash - * - * \param fullname The full path to the temporary temp directory - * \param basename The full path to the persistent temp directory (may be NULL) - * \param maxlen The size of the fullname buffer - * \param userdir Directory specified in user preferences - */ -static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir) -{ - /* Clear existing temp dir, if needed. */ - BLI_temp_dir_session_purge(); - - fullname[0] = '\0'; - if (basename) { - basename[0] = '\0'; - } - - if (userdir && BLI_is_dir(userdir)) { - BLI_strncpy(fullname, userdir, maxlen); - } - - -#ifdef WIN32 - if (fullname[0] == '\0') { - const char *tmp = getenv("TEMP"); /* Windows */ - if (tmp && BLI_is_dir(tmp)) { - BLI_strncpy(fullname, tmp, maxlen); - } - } -#else - /* Other OS's - Try TMP and TMPDIR */ - if (fullname[0] == '\0') { - const char *tmp = getenv("TMP"); - if (tmp && BLI_is_dir(tmp)) { - BLI_strncpy(fullname, tmp, maxlen); - } - } - - if (fullname[0] == '\0') { - const char *tmp = getenv("TMPDIR"); - if (tmp && BLI_is_dir(tmp)) { - BLI_strncpy(fullname, tmp, maxlen); - } - } -#endif - - if (fullname[0] == '\0') { - BLI_strncpy(fullname, "/tmp/", maxlen); - } - else { - /* add a trailing slash if needed */ - BLI_add_slash(fullname); -#ifdef WIN32 - if (userdir && userdir != fullname) { - BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */ - } -#endif - } - - /* Now that we have a valid temp dir, add system-generated unique sub-dir. */ - if (basename) { - /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */ - char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX"); - const size_t ln = strlen(tmp_name) + 1; - if (ln <= maxlen) { -#ifdef WIN32 - if (_mktemp_s(tmp_name, ln) == 0) { - BLI_dir_create_recursive(tmp_name); - } -#else - mkdtemp(tmp_name); -#endif - } - if (BLI_is_dir(tmp_name)) { - BLI_strncpy(basename, fullname, maxlen); - BLI_strncpy(fullname, tmp_name, maxlen); - BLI_add_slash(fullname); - } - else { - printf("Warning! Could not generate a temp file name for '%s', falling back to '%s'\n", tmp_name, fullname); - } - - MEM_freeN(tmp_name); - } -} - -/** - * Sets btempdir_base to userdir if specified and is a valid directory, otherwise - * chooses a suitable OS-specific temporary directory. - * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base. - */ -void BLI_temp_dir_init(char *userdir) -{ - BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir); -; -} - -/** - * Path to temporary directory (with trailing slash) - */ -const char *BLI_temp_dir_session(void) -{ - return btempdir_session[0] ? btempdir_session : BLI_temp_dir_base(); -} - -/** - * Path to persistent temporary directory (with trailing slash) - */ -const char *BLI_temp_dir_base(void) -{ - return btempdir_base; -} - -/** - * Path to the system temporary directory (with trailing slash) - */ -void BLI_system_temporary_dir(char *dir) -{ - BLI_where_is_temp(dir, NULL, FILE_MAX, NULL); -} - -/** - * Delete content of this instance's temp dir. - */ -void BLI_temp_dir_session_purge(void) -{ - if (btempdir_session[0] && BLI_is_dir(btempdir_session)) { - BLI_delete(btempdir_session, true, true); - } -} #ifdef WITH_ICONV diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c index 16cf7ff960b..3aadbe5f1df 100644 --- a/source/blender/blenlib/intern/polyfill2d.c +++ b/source/blender/blenlib/intern/polyfill2d.c @@ -165,7 +165,7 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip); static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip); -BLI_INLINE eSign signum_i(float a) +BLI_INLINE eSign signum_enum(float a) { if (UNLIKELY(a == 0.0f)) return 0; @@ -191,7 +191,7 @@ BLI_INLINE float area_tri_signed_v2_alt_2x(const float v1[2], const float v2[2], static eSign span_tri_v2_sign(const float v1[2], const float v2[2], const float v3[2]) { - return signum_i(area_tri_signed_v2_alt_2x(v3, v2, v1)); + return signum_enum(area_tri_signed_v2_alt_2x(v3, v2, v1)); } diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c new file mode 100644 index 00000000000..7914b7cb39b --- /dev/null +++ b/source/blender/blenlib/intern/polyfill2d_beautify.c @@ -0,0 +1,490 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/polyfill2d_beautify.c + * \ingroup bli + * + * This function is to improve the tessellation resulting from polyfill2d, + * creating optimal topology. + * + * The functionality here matches #BM_mesh_beautify_fill, + * but its far simpler to perform this operation in 2d, + * on a simple polygon representation where we _know_: + * + * - The polygon is primitive with no holes with a continuous boundary. + * - Tris have consistent winding. + * - 2d (saves some hassles projecting face pairs on an axis for every edge-rotation) + * also saves us having to store all previous edge-states (see #EdRotState in bmesh_beautify.c) + * + * \note + * + * No globals - keep threadsafe. + */ + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "BLI_memarena.h" +#include "BLI_edgehash.h" +#include "BLI_heap.h" + +#include "BLI_polyfill2d_beautify.h" /* own include */ + +#include "BLI_strict_flags.h" + +struct PolyEdge { + /** ordered vert indices (smaller first) */ + unsigned int verts[2]; + /** ordered face indices (depends on winding compared to the edge verts) + * - (verts[0], verts[1]) == faces[0] + * - (verts[1], verts[0]) == faces[1] + */ + unsigned int faces[2]; + /** + * The face-index which isn't used by either of the edges verts [0 - 2]. + * could be calculated each time, but cleaner to store for reuse. + */ + unsigned int faces_other_v[2]; +}; + + +#ifndef NDEBUG +/** + * Only to check for error-cases. + */ +static void polyfill_validate_tri(unsigned int (*tris)[3], unsigned int tri_index, EdgeHash *ehash) +{ + const unsigned int *tri = tris[tri_index]; + int j_curr; + + BLI_assert(!ELEM(tri[0], tri[1], tri[2]) && + !ELEM(tri[1], tri[0], tri[2]) && + !ELEM(tri[2], tri[0], tri[1])); + + for (j_curr = 0; j_curr < 3; j_curr++) { + struct PolyEdge *e; + unsigned int e_v1 = tri[(j_curr ) ]; + unsigned int e_v2 = tri[(j_curr + 1) % 3]; + e = BLI_edgehash_lookup(ehash, e_v1, e_v2); + if (e) { + if (e->faces[0] == tri_index) { + BLI_assert(e->verts[0] == e_v1); + BLI_assert(e->verts[1] == e_v2); + } + else if (e->faces[1] == tri_index) { + BLI_assert(e->verts[0] == e_v2); + BLI_assert(e->verts[1] == e_v1); + } + else { + BLI_assert(0); + } + + BLI_assert(e->faces[0] != e->faces[1]); + BLI_assert(ELEM(e_v1, UNPACK3(tri))); + BLI_assert(ELEM(e_v2, UNPACK3(tri))); + BLI_assert(ELEM(e_v1, UNPACK2(e->verts))); + BLI_assert(ELEM(e_v2, UNPACK2(e->verts))); + BLI_assert(e_v1 != tris[e->faces[0]][e->faces_other_v[0]]); + BLI_assert(e_v1 != tris[e->faces[1]][e->faces_other_v[1]]); + BLI_assert(e_v2 != tris[e->faces[0]][e->faces_other_v[0]]); + BLI_assert(e_v2 != tris[e->faces[1]][e->faces_other_v[1]]); + + BLI_assert(ELEM(tri_index, UNPACK2(e->faces))); + } + } +} +#endif + +BLI_INLINE bool is_boundary_edge(unsigned int i_a, unsigned int i_b, const unsigned int coord_last) +{ + BLI_assert(i_a < i_b); + return ((i_a + 1 == i_b) || UNLIKELY((i_a == 0) && (i_b == coord_last))); +} +/** + * Assuming we have 2 triangles sharing an edge (2 - 4), + * check if the edge running from (1 - 3) gives better results. + * + * \return (negative number means the edge can be rotated, lager == better). + */ +float BLI_polyfill_beautify_quad_rotate_calc( + const float v1[2], const float v2[2], const float v3[2], const float v4[2]) +{ + /* not a loop (only to be able to break out) */ + do { + bool is_zero_a, is_zero_b; + + const float area_2x_234 = cross_tri_v2(v2, v3, v4); + const float area_2x_241 = cross_tri_v2(v2, v4, v1); + + const float area_2x_123 = cross_tri_v2(v1, v2, v3); + const float area_2x_134 = cross_tri_v2(v1, v3, v4); + + { + BLI_assert((ELEM(v1, v2, v3, v4) == false) && + (ELEM(v2, v1, v3, v4) == false) && + (ELEM(v3, v1, v2, v4) == false) && + (ELEM(v4, v1, v2, v3) == false)); + + is_zero_a = (fabsf(area_2x_234) <= FLT_EPSILON); + is_zero_b = (fabsf(area_2x_241) <= FLT_EPSILON); + + if (is_zero_a && is_zero_b) { + break; + } + } + + /* one of the tri's was degenerate, check we're not rotating + * into a different degenerate shape or flipping the face */ + if ((fabsf(area_2x_123) <= FLT_EPSILON) || (fabsf(area_2x_134) <= FLT_EPSILON)) { + /* one of the new rotations is degenerate */ + break; + } + + if ((area_2x_123 >= 0.0f) != (area_2x_134 >= 0.0f)) { + /* rotation would cause flipping */ + break; + } + + { + /* testing rule: the area divided by the perimeter, + * check if (1-3) beats the existing (2-4) edge rotation */ + float area_a, area_b; + float prim_a, prim_b; + float fac_24, fac_13; + + float len_12, len_23, len_34, len_41, len_24, len_13; + + /* edges around the quad */ + len_12 = len_v2v2(v1, v2); + len_23 = len_v2v2(v2, v3); + len_34 = len_v2v2(v3, v4); + len_41 = len_v2v2(v4, v1); + /* edges crossing the quad interior */ + len_13 = len_v2v2(v1, v3); + len_24 = len_v2v2(v2, v4); + + /* note, area is in fact (area * 2), + * but in this case its OK, since we're comparing ratios */ + + /* edge (2-4), current state */ + area_a = fabsf(area_2x_234); + area_b = fabsf(area_2x_241); + prim_a = len_23 + len_34 + len_24; + prim_b = len_41 + len_12 + len_24; + fac_24 = (area_a / prim_a) + (area_b / prim_b); + + /* edge (1-3), new state */ + area_a = fabsf(area_2x_123); + area_b = fabsf(area_2x_134); + prim_a = len_12 + len_23 + len_13; + prim_b = len_34 + len_41 + len_13; + fac_13 = (area_a / prim_a) + (area_b / prim_b); + + /* negative number if (1-3) is an improved state */ + return fac_24 - fac_13; + } + } while (false); + + return FLT_MAX; +} + +static float polyedge_rotate_beauty_calc( + const float (*coords)[2], + const unsigned int (*tris)[3], + const struct PolyEdge *e) +{ + const float *v1, *v2, *v3, *v4; + + v1 = coords[tris[e->faces[0]][e->faces_other_v[0]]]; + v3 = coords[tris[e->faces[1]][e->faces_other_v[1]]]; + v2 = coords[e->verts[0]]; + v4 = coords[e->verts[1]]; + + return BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4); +} + +static void polyedge_beauty_cost_update_single( + const float (*coords)[2], + const unsigned int (*tris)[3], + const struct PolyEdge *edges, + struct PolyEdge *e, + Heap *eheap, HeapNode **eheap_table) +{ + const unsigned int i = (unsigned int)(e - edges); + + if (eheap_table[i]) { + BLI_heap_remove(eheap, eheap_table[i]); + eheap_table[i] = NULL; + } + + { + /* recalculate edge */ + const float cost = polyedge_rotate_beauty_calc(coords, tris, e); + if (cost < 0.0f) { + eheap_table[i] = BLI_heap_insert(eheap, cost, e); + } + else { + eheap_table[i] = NULL; + } + } +} + +static void polyedge_beauty_cost_update( + const float (*coords)[2], + const unsigned int (*tris)[3], + const struct PolyEdge *edges, + struct PolyEdge *e, + Heap *eheap, HeapNode **eheap_table, + EdgeHash *ehash) +{ + const unsigned int *tri_0 = tris[e->faces[0]]; + const unsigned int *tri_1 = tris[e->faces[1]]; + unsigned int i; + + struct PolyEdge *e_arr[4] = { + BLI_edgehash_lookup(ehash, + tri_0[(e->faces_other_v[0] ) % 3], + tri_0[(e->faces_other_v[0] + 1) % 3]), + BLI_edgehash_lookup(ehash, + tri_0[(e->faces_other_v[0] + 2) % 3], + tri_0[(e->faces_other_v[0] ) % 3]), + BLI_edgehash_lookup(ehash, + tri_1[(e->faces_other_v[1] ) % 3], + tri_1[(e->faces_other_v[1] + 1) % 3]), + BLI_edgehash_lookup(ehash, + tri_1[(e->faces_other_v[1] + 2) % 3], + tri_1[(e->faces_other_v[1] ) % 3]), + }; + + + for (i = 0; i < 4; i++) { + if (e_arr[i]) { + BLI_assert(!(ELEM(e_arr[i]->faces[0], UNPACK2(e->faces)) && + ELEM(e_arr[i]->faces[1], UNPACK2(e->faces)))); + + polyedge_beauty_cost_update_single( + coords, tris, edges, + e_arr[i], + eheap, eheap_table); + } + } +} + +static void polyedge_rotate( + unsigned int (*tris)[3], + struct PolyEdge *e, + EdgeHash *ehash) +{ + unsigned int e_v1_new = tris[e->faces[0]][e->faces_other_v[0]]; + unsigned int e_v2_new = tris[e->faces[1]][e->faces_other_v[1]]; + +#ifndef NDEBUG + polyfill_validate_tri(tris, e->faces[0], ehash); + polyfill_validate_tri(tris, e->faces[1], ehash); +#endif + + BLI_assert(e_v1_new != e_v2_new); + BLI_assert(!ELEM(e_v2_new, UNPACK3(tris[e->faces[0]]))); + BLI_assert(!ELEM(e_v1_new, UNPACK3(tris[e->faces[1]]))); + + tris[e->faces[0]][(e->faces_other_v[0] + 1) % 3] = e_v2_new; + tris[e->faces[1]][(e->faces_other_v[1] + 1) % 3] = e_v1_new; + + e->faces_other_v[0] = (e->faces_other_v[0] + 2) % 3; + e->faces_other_v[1] = (e->faces_other_v[1] + 2) % 3; + + BLI_assert((tris[e->faces[0]][e->faces_other_v[0]] != e_v1_new) && + (tris[e->faces[0]][e->faces_other_v[0]] != e_v2_new)); + BLI_assert((tris[e->faces[1]][e->faces_other_v[1]] != e_v1_new) && + (tris[e->faces[1]][e->faces_other_v[1]] != e_v2_new)); + + BLI_edgehash_remove(ehash, e->verts[0], e->verts[1], NULL); + BLI_edgehash_insert(ehash, e_v1_new, e_v2_new, e); + + if (e_v1_new < e_v2_new) { + e->verts[0] = e_v1_new; + e->verts[1] = e_v2_new; + } + else { + /* maintain winding info */ + e->verts[0] = e_v2_new; + e->verts[1] = e_v1_new; + + SWAP(unsigned int, e->faces[0], e->faces[1]); + SWAP(unsigned int, e->faces_other_v[0], e->faces_other_v[1]); + } + + /* update adjacent data */ + { + unsigned int e_side = 0; + + for (e_side = 0; e_side < 2; e_side++) { + /* 't_other' which we need to swap out is always the same edge-order */ + const unsigned int t_other = (((e->faces_other_v[e_side]) + 2)) % 3; + unsigned int t_index = e->faces[e_side]; + unsigned int t_index_other = e->faces[!e_side]; + unsigned int *tri = tris[t_index]; + + struct PolyEdge *e_other; + unsigned int e_v1 = tri[(t_other ) ]; + unsigned int e_v2 = tri[(t_other + 1) % 3]; + + e_other = BLI_edgehash_lookup(ehash, e_v1, e_v2); + if (e_other) { + BLI_assert(t_index != e_other->faces[0] && t_index != e_other->faces[1]); + if (t_index_other == e_other->faces[0]) { + e_other->faces[0] = t_index; + e_other->faces_other_v[0] = (t_other + 2) % 3; + BLI_assert(!ELEM(tri[e_other->faces_other_v[0]], e_v1, e_v2)); + } + else if (t_index_other == e_other->faces[1]) { + e_other->faces[1] = t_index; + e_other->faces_other_v[1] = (t_other + 2) % 3; + BLI_assert(!ELEM(tri[e_other->faces_other_v[1]], e_v1, e_v2)); + } + else { + BLI_assert(0); + } + } + } + } + +#ifndef NDEBUG + polyfill_validate_tri(tris, e->faces[0], ehash); + polyfill_validate_tri(tris, e->faces[1], ehash); +#endif + + BLI_assert(!ELEM(tris[e->faces[0]][e->faces_other_v[0]], UNPACK2(e->verts))); + BLI_assert(!ELEM(tris[e->faces[1]][e->faces_other_v[1]], UNPACK2(e->verts))); +} + +/** + * The intention is that this calculates the output of #BLI_polyfill_calc + * + * + * \note assumes the \a coords form a boundary, + * so any edges running along contiguous (wrapped) indices, + * are ignored since the edges wont share 2 faces. + */ +void BLI_polyfill_beautify( + const float (*coords)[2], + const unsigned int coords_tot, + unsigned int (*tris)[3], + + /* structs for reuse */ + MemArena *arena, Heap *eheap, EdgeHash *ehash) +{ + const unsigned int coord_last = coords_tot - 1; + const unsigned int tris_tot = coords_tot - 2; + /* internal edges only (between 2 tris) */ + const unsigned int edges_tot = tris_tot - 1; + unsigned int edges_tot_used = 0; + unsigned int i; + + HeapNode **eheap_table; + + struct PolyEdge *edges = BLI_memarena_alloc(arena, edges_tot * sizeof(*edges)); + + BLI_assert(BLI_heap_size(eheap) == 0); + BLI_assert(BLI_edgehash_size(ehash) == 0); + + /* first build edges */ + for (i = 0; i < tris_tot; i++) { + unsigned int j_prev, j_curr, j_next; + j_prev = 2; + j_next = 1; + for (j_curr = 0; j_curr < 3; j_next = j_prev, j_prev = j_curr++) { + int e_index; + + unsigned int e_pair[2] = { + tris[i][j_prev], + tris[i][j_curr], + }; + + if (e_pair[0] > e_pair[1]) { + SWAP(unsigned int, e_pair[0], e_pair[1]); + e_index = 1; + } + else { + e_index = 0; + } + + if (!is_boundary_edge(e_pair[0], e_pair[1], coord_last)) { + struct PolyEdge *e = BLI_edgehash_lookup(ehash, e_pair[0], e_pair[1]); + if (e == NULL) { + e = &edges[edges_tot_used++]; + BLI_edgehash_insert(ehash, e_pair[0], e_pair[1], e); + memcpy(e->verts, e_pair, sizeof(e->verts)); +#ifndef NDEBUG + e->faces[!e_index] = (unsigned int)-1; +#endif + } + else { + + /* ensure each edge only ever has 2x users */ +#ifndef NDEBUG + BLI_assert(e->faces[e_index] == (unsigned int)-1); + BLI_assert((e->verts[0] == e_pair[0]) && + (e->verts[1] == e_pair[1])); +#endif + } + + e->faces[e_index] = i; + e->faces_other_v[e_index] = j_next; + } + } + } + + /* now perform iterative rotations */ + eheap_table = BLI_memarena_alloc(arena, sizeof(HeapNode *) * (size_t)edges_tot); + + // for (i = 0; i < tris_tot; i++) { polyfill_validate_tri(tris, i, eh); } + + /* build heap */ + for (i = 0; i < edges_tot; i++) { + struct PolyEdge *e = &edges[i]; + const float cost = polyedge_rotate_beauty_calc(coords, (const unsigned int (*)[3])tris, e); + if (cost < 0.0f) { + eheap_table[i] = BLI_heap_insert(eheap, cost, e); + } + else { + eheap_table[i] = NULL; + } + } + + while (BLI_heap_is_empty(eheap) == false) { + struct PolyEdge *e = BLI_heap_popmin(eheap); + i = (unsigned int)(e - edges); + eheap_table[i] = NULL; + + polyedge_rotate(tris, e, ehash); + + /* recalculate faces connected on the heap */ + polyedge_beauty_cost_update( + coords, (const unsigned int (*)[3])tris, edges, + e, + eheap, eheap_table, ehash); + } + + BLI_heap_clear(eheap, NULL); + BLI_edgehash_clear_ex(ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE); + + /* MEM_freeN(eheap_table); */ /* arena */ +} diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c index 59ccf381f29..7657cec8cfd 100644 --- a/source/blender/blenlib/intern/rand.c +++ b/source/blender/blenlib/intern/rand.c @@ -144,6 +144,31 @@ void BLI_rng_get_float_unit_v3(RNG *rng, float v[3]) } } +/** + * Generate a random point inside given tri. + */ +void BLI_rng_get_tri_sample_float_v2( + RNG *rng, const float v1[2], const float v2[2], const float v3[2], + float r_pt[2]) +{ + float u = BLI_rng_get_float(rng); + float v = BLI_rng_get_float(rng); + + float side_u[2], side_v[2]; + + if ((u + v) > 1.0f) { + u = 1.0f - u; + v = 1.0f - v; + } + + sub_v2_v2v2(side_u, v2, v1); + sub_v2_v2v2(side_v, v3, v1); + + copy_v2_v2(r_pt, v1); + madd_v2_v2fl(r_pt, side_u, u); + madd_v2_v2fl(r_pt, side_v, v); +} + void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot) { const size_t elem_size = (unsigned int)elem_size_i; diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index 1653ba5ae6e..8a96daeeb91 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -173,13 +173,13 @@ static bool boundisect(PolyFill *pf2, PolyFill *pf1) /* has pf2 been touched (intersected) by pf1 ? with bounding box */ /* test first if polys exist */ - if (pf1->edges == 0 || pf2->edges == 0) return 0; + if (pf1->edges == 0 || pf2->edges == 0) return false; - if (pf2->max_xy[0] < pf1->min_xy[0]) return 0; - if (pf2->max_xy[1] < pf1->min_xy[1]) return 0; + if (pf2->max_xy[0] < pf1->min_xy[0]) return false; + if (pf2->max_xy[1] < pf1->min_xy[1]) return false; - if (pf2->min_xy[0] > pf1->max_xy[0]) return 0; - if (pf2->min_xy[1] > pf1->max_xy[1]) return 0; + if (pf2->min_xy[0] > pf1->max_xy[0]) return false; + if (pf2->min_xy[1] > pf1->max_xy[1]) return false; /* join */ if (pf2->max_xy[0] < pf1->max_xy[0]) pf2->max_xy[0] = pf1->max_xy[0]; @@ -188,7 +188,7 @@ static bool boundisect(PolyFill *pf2, PolyFill *pf1) if (pf2->min_xy[0] > pf1->min_xy[0]) pf2->min_xy[0] = pf1->min_xy[0]; if (pf2->min_xy[1] > pf1->min_xy[1]) pf2->min_xy[1] = pf1->min_xy[1]; - return 1; + return true; } @@ -225,13 +225,13 @@ static bool testedgeside(const float v1[2], const float v2[2], const float v3[2] (v1[1] - v2[1]) * (v1[0] - v3[0]); if (inp < 0.0f) { - return 0; + return false; } else if (inp == 0.0f) { - if (v1[0] == v3[0] && v1[1] == v3[1]) return 0; - if (v2[0] == v3[0] && v2[1] == v3[1]) return 0; + if (v1[0] == v3[0] && v1[1] == v3[1]) return false; + if (v2[0] == v3[0] && v2[1] == v3[1]) return false; } - return 1; + return true; } static bool addedgetoscanvert(ScanFillVertLink *sc, ScanFillEdge *eed) @@ -261,7 +261,7 @@ static bool addedgetoscanvert(ScanFillVertLink *sc, ScanFillEdge *eed) for (ed = sc->edge_first; ed; ed = ed->next) { if (ed->v2 == eed->v2) { - return 0; + return false; } fac = ed->v2->xy[1] - y; @@ -279,7 +279,7 @@ static bool addedgetoscanvert(ScanFillVertLink *sc, ScanFillEdge *eed) if (ed) BLI_insertlinkbefore((ListBase *)&(sc->edge_first), ed, eed); else BLI_addtail((ListBase *)&(sc->edge_first), eed); - return 1; + return true; } @@ -341,10 +341,10 @@ static bool boundinsideEV(ScanFillEdge *eed, ScanFillVert *eve) maxy = eed->v1->xy[1]; } if (eve->xy[1] >= miny && eve->xy[1] <= maxy) { - return 1; + return true; } } - return 0; + return false; } diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c index 029e98bad5e..a606ac41aa1 100644 --- a/source/blender/blenlib/intern/scanfill_utils.c +++ b/source/blender/blenlib/intern/scanfill_utils.c @@ -76,7 +76,7 @@ typedef struct ScanFillIsect { #if 0 -void BKE_scanfill_obj_dump(ScanFillContext *sf_ctx) +void BLI_scanfill_obj_dump(ScanFillContext *sf_ctx) { FILE *f = fopen("test.obj", "w"); unsigned int i = 1; @@ -96,7 +96,7 @@ void BKE_scanfill_obj_dump(ScanFillContext *sf_ctx) #endif #if 0 -void BKE_scanfill_view3d_dump(ScanFillContext *sf_ctx) +void BLI_scanfill_view3d_dump(ScanFillContext *sf_ctx) { ScanFillEdge *eed; @@ -136,8 +136,8 @@ static int edge_isect_ls_sort_cb(void *thunk, const void *def_a_ptr, const void { const float *co = thunk; - const ScanFillIsect *i_a = ((LinkData *)def_a_ptr)->data; - const ScanFillIsect *i_b = ((LinkData *)def_b_ptr)->data; + const ScanFillIsect *i_a = ((const LinkData *)def_a_ptr)->data; + const ScanFillIsect *i_b = ((const LinkData *)def_b_ptr)->data; const float a = len_squared_v2v2(co, i_a->co); const float b = len_squared_v2v2(co, i_b->co); @@ -508,8 +508,8 @@ bool BLI_scanfill_calc_self_isect( sf_ctx->poly_nr = SF_POLY_UNSET; #if 0 - BKE_scanfill_view3d_dump(sf_ctx); - BKE_scanfill_obj_dump(sf_ctx); + BLI_scanfill_view3d_dump(sf_ctx); + BLI_scanfill_obj_dump(sf_ctx); #endif return changed; diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c index 0cf9f69b9ae..ba336ab6c4b 100644 --- a/source/blender/blenlib/intern/smallhash.c +++ b/source/blender/blenlib/intern/smallhash.c @@ -118,7 +118,7 @@ BLI_INLINE void smallhash_buckets_reserve(SmallHash *sh, const unsigned int nent } } -BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *sh, const uintptr_t key) +BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t key) { SmallHashEntry *e; unsigned int h = smallhash_key(key); @@ -246,6 +246,26 @@ void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *val) e->val = val; } +/** + * Inserts a new value to a key that may already be in ghash. + * + * Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups) + * + * \returns true if a new key has been added. + */ +bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) +{ + SmallHashEntry *e = smallhash_lookup(sh, key); + if (e) { + e->val = item; + return false; + } + else { + BLI_smallhash_insert(sh, key, item); + return true; + } +} + #ifdef USE_REMOVE bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) { @@ -264,33 +284,33 @@ bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) } #endif -void *BLI_smallhash_lookup(SmallHash *sh, uintptr_t key) +void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key) { SmallHashEntry *e = smallhash_lookup(sh, key); return e ? e->val : NULL; } -void **BLI_smallhash_lookup_p(SmallHash *sh, uintptr_t key) +void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key) { SmallHashEntry *e = smallhash_lookup(sh, key); return e ? &e->val : NULL; } -bool BLI_smallhash_haskey(SmallHash *sh, uintptr_t key) +bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key) { SmallHashEntry *e = smallhash_lookup(sh, key); return (e != NULL); } -int BLI_smallhash_count(SmallHash *sh) +int BLI_smallhash_count(const SmallHash *sh) { return (int)sh->nentries; } -void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) +BLI_INLINE SmallHashEntry *smallhash_iternext(SmallHashIter *iter, uintptr_t *key) { while (iter->i < iter->sh->nbuckets) { if (smallhash_val_is_used(iter->sh->buckets[iter->i].val)) { @@ -298,7 +318,7 @@ void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) *key = iter->sh->buckets[iter->i].key; } - return iter->sh->buckets[iter->i++].val; + return &iter->sh->buckets[iter->i++]; } iter->i++; @@ -307,7 +327,21 @@ void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) return NULL; } -void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key) +void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) +{ + SmallHashEntry *e = smallhash_iternext(iter, key); + + return e ? e->val : NULL; +} + +void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key) +{ + SmallHashEntry *e = smallhash_iternext(iter, key); + + return e ? &e->val : NULL; +} + +void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key) { iter->sh = sh; iter->i = 0; @@ -315,6 +349,15 @@ void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key) return BLI_smallhash_iternext(iter, key); } +void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key) +{ + iter->sh = sh; + iter->i = 0; + + return BLI_smallhash_iternext_p(iter, key); +} + + /** \name Debugging & Introspection * \{ */ diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index c062d62bca5..4c5268562ad 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -385,9 +385,11 @@ static void bli_adddirstrings(struct BuildDirCtx *dir_ctx) /** * Scans the contents of the directory named *dirname, and allocates and fills in an - * array of entries describing them in *filelist. The length of the array is the function result. + * array of entries describing them in *filelist. + * + * \return The length of filelist array. */ -unsigned int BLI_dir_contents(const char *dirname, struct direntry **filelist) +unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **filelist) { struct BuildDirCtx dir_ctx; @@ -409,12 +411,45 @@ unsigned int BLI_dir_contents(const char *dirname, struct direntry **filelist) return dir_ctx.nrfiles; } -/* frees storage for an array of direntries, including the array itself. */ -void BLI_free_filelist(struct direntry *filelist, unsigned int nrentries) +/** + * Deep-duplicate of an array of direntries, including the array itself. + * + * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. + */ +void BLI_filelist_duplicate( + struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries, + void *(*dup_poin)(void *)) +{ + unsigned int i; + + *dest_filelist = malloc(sizeof(**dest_filelist) * (size_t)(nrentries)); + for (i = 0; i < nrentries; ++i) { + struct direntry * const src = &src_filelist[i]; + struct direntry *dest = &(*dest_filelist)[i]; + *dest = *src; + if (dest->image) { + dest->image = IMB_dupImBuf(src->image); + } + if (dest->relname) { + dest->relname = MEM_dupallocN(src->relname); + } + if (dest->path) { + dest->path = MEM_dupallocN(src->path); + } + if (dest->poin && dup_poin) { + dest->poin = dup_poin(src->poin); + } + } +} + +/** + * frees storage for an array of direntries, including the array itself. + */ +void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *)) { unsigned int i; for (i = 0; i < nrentries; ++i) { - struct direntry * const entry = filelist + i; + struct direntry *entry = filelist + i; if (entry->image) { IMB_freeImBuf(entry->image); } @@ -422,7 +457,8 @@ void BLI_free_filelist(struct direntry *filelist, unsigned int nrentries) MEM_freeN(entry->relname); if (entry->path) MEM_freeN(entry->path); - /* entry->poin assumed not to point to anything needing freeing here */ + if (entry->poin && free_poin) + free_poin(entry->poin); } free(filelist); diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index eeafc1a9e8f..cc5a90dbc39 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -126,6 +126,54 @@ char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t } /** + * Like BLI_strncpy but ensures dst is always padded by given char, on both sides (unless src is empty). + * + * \param dst Destination for copy + * \param src Source string to copy + * \param pad the char to use for padding + * \param maxncpy Maximum number of characters to copy (generally the size of dst) + * \retval Returns dst + */ +char *BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t maxncpy) +{ + BLI_assert(maxncpy != 0); + +#ifdef DEBUG_STRSIZE + memset(dst, 0xff, sizeof(*dst) * maxncpy); +#endif + + if (src[0] == '\0') { + dst[0] = '\0'; + } + else { + /* Add heading/trailing wildcards if needed. */ + size_t idx = 0; + size_t srclen; + + if (src[idx] != pad) { + dst[idx++] = pad; + maxncpy--; + } + maxncpy--; /* trailing '\0' */ + + srclen = BLI_strnlen(src, maxncpy); + if ((src[srclen - 1] != pad) && (srclen == maxncpy)) { + srclen--; + } + + memcpy(&dst[idx], src, srclen); + idx += srclen; + + if (dst[idx - 1] != pad) { + dst[idx++] = pad; + } + dst[idx] = '\0'; + } + + return dst; +} + +/** * Like strncpy but ensures dst is always * '\0' terminated. * @@ -566,6 +614,50 @@ int BLI_natstrcmp(const char *s1, const char *s2) return strcmp(s1, s2); } +/** + * Like strcmp, but will ignore any heading/trailing pad char for comparison. + * So e.g. if pad is '*', '*world' and 'world*' will compare equal. + */ +int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad) +{ + size_t str1_len, str2_len; + + while (*str1 == pad) { + str1++; + } + while (*str2 == pad) { + str2++; + } + + str1_len = strlen(str1); + str2_len = strlen(str2); + + while (str1_len && (str1[str1_len - 1] == pad)) { + str1_len--; + } + while (str2_len && (str2[str2_len - 1] == pad)) { + str2_len--; + } + + if (str1_len == str2_len) { + return strncmp(str1, str2, str2_len); + } + else if (str1_len > str2_len) { + int ret = strncmp(str1, str2, str2_len); + if (ret == 0) { + ret = 1; + } + return ret; + } + else { + int ret = strncmp(str1, str2, str1_len); + if (ret == 0) { + ret = -1; + } + return ret; + } +} + void BLI_timestr(double _time, char *str, size_t maxlen) { /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */ @@ -681,6 +773,35 @@ int BLI_str_index_in_array(const char *__restrict str, const char **__restrict s return -1; } +bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength) +{ + size_t elength = strlen(end); + + if (elength < slength) { + const char *iter = &str[slength - elength]; + while (*iter) { + if (*iter++ != *end++) { + return false; + } + } + return true; + } + return false; +} + +/** + * Find if a string ends with another string. + * + * \param str The string to search within. + * \param end The string we look for at the end. + * \return If str ends with end. + */ +bool BLI_str_endswith(const char *__restrict str, const char *end) +{ + const size_t slength = strlen(str); + return BLI_strn_endswith(str, end, slength); +} + /** * Find the first char matching one of the chars in \a delim, from left. * diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 9697fcf09e9..f2930044204 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -69,11 +69,11 @@ static const char trailingBytesForUTF8[256] = { int BLI_utf8_invalid_byte(const char *str, int length) { - const unsigned char *p, *pend = (unsigned char *)str + length; + const unsigned char *p, *pend = (const unsigned char *)str + length; unsigned char c; int ab; - for (p = (unsigned char *)str; p < pend; p++) { + for (p = (const unsigned char *)str; p < pend; p++) { c = *p; if (c < 128) continue; @@ -130,7 +130,7 @@ int BLI_utf8_invalid_byte(const char *str, int length) utf8_error: - return (int)((char *)p - (char *)str) - 1; + return (int)((const char *)p - (const char *)str) - 1; } int BLI_utf8_invalid_strip(char *str, int length) @@ -209,6 +209,22 @@ char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t return r_dst; } +size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) +{ + char *r_dst = dst; + + BLI_assert(maxncpy != 0); + +#ifdef DEBUG_STRSIZE + memset(dst, 0xff, sizeof(*dst) * maxncpy); +#endif + + /* note: currently we don't attempt to deal with invalid utf8 chars */ + BLI_STR_UTF8_CPY(dst, src, maxncpy); + + return (size_t)(dst - r_dst); +} + char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) { while (*dst && maxncpy > 0) { diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c index e6389bc68f3..51b8efbb79f 100644 --- a/source/blender/blenlib/intern/system.c +++ b/source/blender/blenlib/intern/system.c @@ -22,9 +22,18 @@ * \ingroup bli */ +#include <stdio.h> +#include <stdlib.h> #include "BLI_system.h" +/* for backtrace */ +#if defined(__linux__) || defined(__APPLE__) +# include <execinfo.h> +#elif defined(_MSV_VER) +# include <DbgHelp.h> +#endif + int BLI_cpu_support_sse2(void) { #if defined(__x86_64__) || defined(_M_X64) @@ -57,3 +66,69 @@ int BLI_cpu_support_sse2(void) #endif } +/** + * Write a backtrace into a file for systems which support it. + */ +void BLI_system_backtrace(FILE *fp) +{ + /* ------------- */ + /* Linux / Apple */ +#if defined(__linux__) || defined(__APPLE__) + +#define SIZE 100 + void *buffer[SIZE]; + int nptrs; + char **strings; + int i; + + /* include a backtrace for good measure */ + nptrs = backtrace(buffer, SIZE); + strings = backtrace_symbols(buffer, nptrs); + for (i = 0; i < nptrs; i++) { + fputs(strings[i], fp); + fputc('\n', fp); + } + + free(strings); +#undef SIZE + + /* -------- */ + /* Windows */ +#elif defined(_MSC_VER) + + (void)fp; +#if 0 +#define MAXSYMBOL 256 + unsigned short i; + void *stack[SIZE]; + unsigned short nframes; + SYMBOL_INFO *symbolinfo; + HANDLE process; + + process = GetCurrentProcess(); + + SymInitialize(process, NULL, true); + + nframes = CaptureStackBackTrace(0, SIZE, stack, NULL); + symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table"); + symbolinfo->MaxNameLen = MAXSYMBOL - 1; + symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); + + for (i = 0; i < nframes; i++) { + SymFromAddr(process, ( DWORD64 )( stack[ i ] ), 0, symbolinfo); + + fprintf(fp, "%u: %s - 0x%0X\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address); + } + + MEM_freeN(symbolinfo); +#undef MAXSYMBOL +#endif + + /* ------------------ */ + /* non msvc/osx/linux */ +#else + (void)fp; +#endif + +} +/* end BLI_system_backtrace */ diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 219ccb18d98..d187a8d1968 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -33,6 +33,8 @@ #include "BLI_task.h" #include "BLI_threads.h" +#include "atomic_ops.h" + /* Types */ typedef struct Task { @@ -49,6 +51,8 @@ struct TaskPool { volatile size_t num; volatile size_t done; + size_t num_threads; + size_t currently_running_tasks; ThreadMutex num_mutex; ThreadCondition num_cond; @@ -84,6 +88,7 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done) BLI_assert(pool->num >= done); pool->num -= done; + atomic_sub_z(&pool->currently_running_tasks, done); pool->done += done; if (pool->num == 0) @@ -104,19 +109,37 @@ static void task_pool_num_increase(TaskPool *pool) static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task) { + bool found_task = false; BLI_mutex_lock(&scheduler->queue_mutex); while (!scheduler->queue.first && !scheduler->do_exit) BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); - if (!scheduler->queue.first) { - BLI_mutex_unlock(&scheduler->queue_mutex); - BLI_assert(scheduler->do_exit); - return false; - } - - *task = scheduler->queue.first; - BLI_remlink(&scheduler->queue, *task); + do { + Task *current_task; + if (!scheduler->queue.first) { + BLI_mutex_unlock(&scheduler->queue_mutex); + BLI_assert(scheduler->do_exit); + return false; + } + for (current_task = scheduler->queue.first; + current_task != NULL; + current_task = current_task->next) + { + TaskPool *pool = current_task->pool; + if (pool->num_threads == 0 || + pool->currently_running_tasks < pool->num_threads) + { + *task = current_task; + found_task = true; + atomic_add_z(&pool->currently_running_tasks, 1); + BLI_remlink(&scheduler->queue, *task); + break; + } + } + if (!found_task) + BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); + } while (!found_task); BLI_mutex_unlock(&scheduler->queue_mutex); @@ -288,6 +311,8 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata) pool->scheduler = scheduler; pool->num = 0; + pool->num_threads = 0; + pool->currently_running_tasks = 0; pool->do_cancel = false; BLI_mutex_init(&pool->num_mutex); @@ -351,12 +376,16 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) /* find task from this pool. if we get a task from another pool, * we can get into deadlock */ - for (task = scheduler->queue.first; task; task = task->next) { - if (task->pool == pool) { - work_task = task; - found_task = true; - BLI_remlink(&scheduler->queue, task); - break; + if (pool->num_threads == 0 || + pool->currently_running_tasks < pool->num_threads) + { + for (task = scheduler->queue.first; task; task = task->next) { + if (task->pool == pool) { + work_task = task; + found_task = true; + BLI_remlink(&scheduler->queue, task); + break; + } } } @@ -365,6 +394,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) /* if found task, do it, otherwise wait until other tasks are done */ if (found_task) { /* run task */ + atomic_add_z(&pool->currently_running_tasks, 1); work_task->run(pool, work_task->taskdata, 0); /* delete task */ @@ -387,6 +417,12 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) BLI_mutex_unlock(&pool->num_mutex); } +void BLI_pool_set_num_threads(TaskPool *pool, int num_threads) +{ + /* NOTE: Don't try to modify threads while tasks are running! */ + pool->num_threads = num_threads; +} + void BLI_task_pool_cancel(TaskPool *pool) { pool->do_cancel = true; diff --git a/source/blender/blenlib/intern/winstuff_dir.c b/source/blender/blenlib/intern/winstuff_dir.c index 3d669a869f9..b20da9ce959 100644 --- a/source/blender/blenlib/intern/winstuff_dir.c +++ b/source/blender/blenlib/intern/winstuff_dir.c @@ -45,11 +45,11 @@ #include "utfconv.h" /* Note: MinGW (FREE_WINDOWS) has opendir() and _wopendir(), and only the -* latter accepts a path name of wchar_t type. Rather than messing up with -* extra #ifdef's here and there, Blender's own implementations of opendir() -* and related functions are used to properly support paths with non-ASCII -* characters. (kjym3) -*/ + * latter accepts a path name of wchar_t type. Rather than messing up with + * extra #ifdef's here and there, Blender's own implementations of opendir() + * and related functions are used to properly support paths with non-ASCII + * characters. (kjym3) + */ DIR *opendir(const char *path) { diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index d9bcfc2e8f9..95440158277 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -308,6 +308,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* makes lookup of existing video clips in old main */ blo_make_movieclip_pointer_map(fd, oldmain); + + /* make lookups of existing sound data in old main */ + blo_make_sound_pointer_map(fd, oldmain); /* removed packed data from this trick - it's internal data that needs saves */ @@ -318,7 +321,10 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* ensures relinked movie clips are not freed */ blo_end_movieclip_pointer_map(fd, oldmain); - + + /* ensures relinked sounds are not freed */ + blo_end_sound_pointer_map(fd, oldmain); + /* move libraries from old main to new main */ if (bfd && mainlist.first != mainlist.last) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 4aa4cde4687..d31167976ed 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -143,13 +143,9 @@ #include "BKE_treehash.h" #include "BKE_sound.h" -#include "IMB_imbuf.h" // for proxy / timecode versioning stuff #include "NOD_common.h" #include "NOD_socket.h" -#include "NOD_composite.h" -#include "NOD_shader.h" -#include "NOD_texture.h" #include "BLO_readfile.h" #include "BLO_undofile.h" @@ -159,7 +155,6 @@ #include "readfile.h" -#include "PIL_time.h" #include <errno.h> @@ -1130,6 +1125,8 @@ void blo_freefiledata(FileData *fd) oldnewmap_free(fd->imamap); if (fd->movieclipmap) oldnewmap_free(fd->movieclipmap); + if (fd->soundmap) + oldnewmap_free(fd->soundmap); if (fd->packedmap) oldnewmap_free(fd->packedmap); if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP)) @@ -1223,6 +1220,13 @@ static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie return NULL; } +static void *newsoundadr(FileData *fd, void *adr) /* used to restore sound data after undo */ +{ + if (fd->soundmap && adr) + return oldnewmap_lookup_and_inc(fd->soundmap, adr, true); + return NULL; +} + static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */ { if (fd->packedmap && adr) @@ -1439,6 +1443,37 @@ void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain) } } +void blo_make_sound_pointer_map(FileData *fd, Main *oldmain) +{ + bSound *sound = oldmain->sound.first; + + fd->soundmap = oldnewmap_new(); + + for (; sound; sound = sound->id.next) { + if (sound->waveform) + oldnewmap_insert(fd->soundmap, sound->waveform, sound->waveform, 0); + } +} + +/* set old main sound caches to zero if it has been restored */ +/* this works because freeing old main only happens after this call */ +void blo_end_sound_pointer_map(FileData *fd, Main *oldmain) +{ + OldNew *entry = fd->soundmap->entries; + bSound *sound = oldmain->sound.first; + int i; + + /* used entries were restored, so we put them to zero */ + for (i = 0; i < fd->soundmap->nentries; i++, entry++) { + if (entry->nr > 0) + entry->newp = NULL; + } + + for (; sound; sound = sound->id.next) { + sound->waveform = newsoundadr(fd, sound->waveform); + } +} + /* XXX disabled this feature - packed files also belong in temp saves and quit.blend, to make restore work */ static void insert_packedmap(FileData *fd, PackedFile *pf) @@ -3090,14 +3125,14 @@ static void lib_link_key(FileData *fd, Main *main) static void switch_endian_keyblock(Key *key, KeyBlock *kb) { int elemsize, a, b; - const char *data, *poin, *cp; + char *data; elemsize = key->elemsize; data = kb->data; for (a = 0; a < kb->totelem; a++) { - cp = key->elemstr; - poin = data; + const char *cp = key->elemstr; + char *poin = data; while (cp[0]) { /* cp[0] == amount */ switch (cp[1]) { /* cp[1] = type */ @@ -3222,6 +3257,7 @@ static void direct_link_world(FileData *fd, World *wrld) } wrld->preview = direct_link_preview_image(fd, wrld->preview); + BLI_listbase_clear(&wrld->gpumaterial); } @@ -4822,9 +4858,14 @@ static void direct_link_object(FileData *fd, Object *ob) /* loading saved files with editmode enabled works, but for undo we like * to stay in object mode during undo presses so keep editmode disabled. * - * Also when linking in a file don't allow editmode: [#34776] */ + * Also when linking in a file don't allow edit and pose modes. + * See [#34776, #42780] for more information. + */ if (fd->memfile || (ob->id.flag & (LIB_EXTERN | LIB_INDIRECT))) { ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT); + if (!fd->memfile) { + ob->mode &= ~OB_MODE_POSE; + } } ob->adt = newdataadr(fd, ob->adt); @@ -5406,7 +5447,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) } if (sce->ed) { - ListBase *old_seqbasep = &((Editing *)sce->ed)->seqbase; + ListBase *old_seqbasep = &sce->ed->seqbase; ed = sce->ed = newdataadr(fd, sce->ed); @@ -5420,6 +5461,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) seq->seq1= newdataadr(fd, seq->seq1); seq->seq2= newdataadr(fd, seq->seq2); seq->seq3= newdataadr(fd, seq->seq3); + /* a patch: after introduction of effects with 3 input strips */ if (seq->seq3 == NULL) seq->seq3 = seq->seq2; @@ -5590,6 +5632,9 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) win->eventstate = NULL; win->curswin = NULL; win->tweak = NULL; +#ifdef WIN32 + win->ime_data = NULL; +#endif BLI_listbase_clear(&win->queue); BLI_listbase_clear(&win->handlers); @@ -5645,6 +5690,21 @@ static void lib_link_windowmanager(FileData *fd, Main *main) /* ****************** READ GREASE PENCIL ***************** */ +/* relink's grease pencil data's refs */ +static void lib_link_gpencil(FileData *fd, Main *main) +{ + bGPdata *gpd; + + for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) { + if (gpd->id.flag & LIB_NEED_LINK) { + gpd->id.flag -= LIB_NEED_LINK; + + if (gpd->adt) + lib_link_animdata(fd, &gpd->id, gpd->adt); + } + } +} + /* relinks grease-pencil data - used for direct_link and old file linkage */ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) { @@ -5656,6 +5716,10 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) if (gpd == NULL) return; + /* relink animdata */ + gpd->adt = newdataadr(fd, gpd->adt); + direct_link_animdata(fd, gpd->adt); + /* relink layers */ link_list(fd, &gpd->layers); @@ -6726,14 +6790,26 @@ static void direct_link_sound(FileData *fd, bSound *sound) { sound->handle = NULL; sound->playback_handle = NULL; - sound->waveform = NULL; - // versioning stuff, if there was a cache, then we enable caching: + /* versioning stuff, if there was a cache, then we enable caching: */ if (sound->cache) { sound->flags |= SOUND_FLAGS_CACHING; sound->cache = NULL; } + if (fd->soundmap) { + sound->waveform = newsoundadr(fd, sound->waveform); + } + else { + sound->waveform = NULL; + } + + if (sound->mutex) + sound->mutex = BLI_mutex_alloc(); + + /* clear waveform loading flag */ + sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + sound->packedfile = direct_link_packedfile(fd, sound->packedfile); sound->newpackedfile = direct_link_packedfile(fd, sound->newpackedfile); } @@ -7615,6 +7691,7 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_movieclip(fd, main); lib_link_mask(fd, main); lib_link_linestyle(fd, main); + lib_link_gpencil(fd, main); lib_link_mesh(fd, main); /* as last: tpage images with users at zero */ @@ -8720,6 +8797,12 @@ static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *li } } +static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) +{ + if (gpd->adt) + expand_animdata(fd, mainvar, gpd->adt); +} + void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *)) { expand_doit = expand_doit_func; @@ -8814,6 +8897,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) case ID_LS: expand_linestyle(fd, mainvar, (FreestyleLineStyle *)id); break; + case ID_GD: + expand_gpencil(fd, mainvar, (bGPdata *)id); + break; } do_it = true; diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index d56f58d1b37..2b40accbf21 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -88,6 +88,7 @@ typedef struct FileData { struct OldNewMap *libmap; struct OldNewMap *imamap; struct OldNewMap *movieclipmap; + struct OldNewMap *soundmap; struct OldNewMap *packedmap; struct BHeadSort *bheadmap; @@ -133,6 +134,8 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain); void blo_end_image_pointer_map(FileData *fd, Main *oldmain); void blo_make_movieclip_pointer_map(FileData *fd, Main *oldmain); void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain); +void blo_make_sound_pointer_map(FileData *fd, Main *oldmain); +void blo_end_sound_pointer_map(FileData *fd, Main *oldmain); void blo_make_packed_pointer_map(FileData *fd, Main *oldmain); void blo_end_packed_pointer_map(FileData *fd, Main *oldmain); void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd); diff --git a/source/blender/blenloader/intern/runtime.c b/source/blender/blenloader/intern/runtime.c index d6fd2f92443..ec496e1c866 100644 --- a/source/blender/blenloader/intern/runtime.c +++ b/source/blender/blenloader/intern/runtime.c @@ -51,7 +51,6 @@ #include "BLO_readfile.h" #include "BLO_runtime.h" -#include "BKE_blender.h" #include "BKE_report.h" /* Runtime reading */ diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index 12f4a295a34..f70d889828f 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -40,7 +40,6 @@ #include "DNA_listBase.h" #include "BLI_blenlib.h" -#include "BLI_linklist.h" #include "BLO_undofile.h" diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 14b165e2341..8eb54c30cb1 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -25,11 +25,10 @@ * \ingroup blenloader */ -#include "zlib.h" - #ifndef WIN32 # include <unistd.h> /* for read close */ #else +# include <zlib.h> /* odd include order-issue */ # include <io.h> // for open close read # include "winsock2.h" # include "BLI_winstuff.h" @@ -92,14 +91,9 @@ #include "NOD_socket.h" #include "BLO_readfile.h" -#include "BLO_undofile.h" - -#include "RE_engine.h" #include "readfile.h" -#include "PIL_time.h" - #include <errno.h> /* 2.50 patch */ diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 7c6b6ec7249..7e5127aa407 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -25,8 +25,6 @@ * \ingroup blenloader */ -#include "zlib.h" - #include "BLI_utildefines.h" /* allow readfile to use deprecated functionality */ diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 37ad2167332..0ff953e7420 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -54,14 +54,12 @@ #include "DNA_genfile.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" - #include "BKE_main.h" #include "BKE_node.h" #include "BKE_pointcache.h" #include "BLI_math.h" +#include "BLI_listbase.h" #include "BLI_string.h" #include "BLO_readfile.h" @@ -512,4 +510,27 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) do_versions_pointcache(&sce->id, rbw->pointcache); } } + + if (!MAIN_VERSION_ATLEAST(main, 273, 1)) { +#define BRUSH_RAKE (1 << 7) +#define BRUSH_RANDOM_ROTATION (1 << 25) + + Brush *br; + + for (br = main->brush.first; br; br = br->id.next) { + if (br->flag & BRUSH_RAKE) { + br->mtex.brush_angle_mode |= MTEX_ANGLE_RAKE; + br->mask_mtex.brush_angle_mode |= MTEX_ANGLE_RAKE; + } + else if (br->flag & BRUSH_RANDOM_ROTATION) { + br->mtex.brush_angle_mode |= MTEX_ANGLE_RANDOM; + br->mask_mtex.brush_angle_mode |= MTEX_ANGLE_RANDOM; + } + br->mtex.random_angle = 2.0f * M_PI; + br->mask_mtex.random_angle = 2.0f * M_PI; + } + +#undef BRUSH_RAKE +#undef BRUSH_RANDOM_ROTATION + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 4732f8578ed..4c7b011097b 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -138,9 +138,13 @@ void BLO_update_defaults_startup_blend(Main *bmain) { Brush *br; - br = BKE_brush_add(bmain, "Fill"); - br->imagepaint_tool = PAINT_TOOL_FILL; - br->ob_mode = OB_MODE_TEXTURE_PAINT; + + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Fill"); + if (!br) { + br = BKE_brush_add(bmain, "Fill"); + br->imagepaint_tool = PAINT_TOOL_FILL; + br->ob_mode = OB_MODE_TEXTURE_PAINT; + } br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Mask"); if (br) { diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 1d0babcad3e..27e49522be4 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -30,13 +30,12 @@ */ -#include "zlib.h" - #include <limits.h> #ifndef WIN32 # include <unistd.h> // for read close #else +# include <zlib.h> /* odd include order-issue */ # include <io.h> // for open close read # include "winsock2.h" # include "BLI_winstuff.h" @@ -96,14 +95,9 @@ #include "BKE_scene.h" #include "BKE_sequencer.h" -#include "IMB_imbuf.h" // for proxy / timecode versioning stuff - #include "NOD_socket.h" #include "BLO_readfile.h" -#include "BLO_undofile.h" - -#include "RE_engine.h" #include "readfile.h" @@ -523,6 +517,40 @@ static void do_version_free_effects_245(ListBase *lb) } } +static void do_version_constraints_245(ListBase *lb) +{ + bConstraint *con; + bConstraintTarget *ct; + + for (con = lb->first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_PYTHON) { + bPythonConstraint *data = (bPythonConstraint *)con->data; + if (data->tar) { + /* version patching needs to be done */ + ct = MEM_callocN(sizeof(bConstraintTarget), "PyConTarget"); + + ct->tar = data->tar; + BLI_strncpy(ct->subtarget, data->subtarget, sizeof(ct->subtarget)); + ct->space = con->tarspace; + + BLI_addtail(&data->targets, ct); + data->tarnum++; + + /* clear old targets to avoid problems */ + data->tar = NULL; + data->subtarget[0] = '\0'; + } + } + else if (con->type == CONSTRAINT_TYPE_LOCLIKE) { + bLocateLikeConstraint *data = (bLocateLikeConstraint *)con->data; + + /* new headtail functionality makes Bone-Tip function obsolete */ + if (data->flag & LOCLIKE_TIP) + con->headtail = 1.0f; + } + } +} + PartEff *blo_do_version_give_parteff_245(Object *ob) { PartEff *paf; @@ -2953,69 +2981,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 7)) { Object *ob; bPoseChannel *pchan; - bConstraint *con; - bConstraintTarget *ct; for (ob = main->object.first; ob; ob = ob->id.next) { if (ob->pose) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = (bPythonConstraint *)con->data; - if (data->tar) { - /* version patching needs to be done */ - ct = MEM_callocN(sizeof(bConstraintTarget), "PyConTarget"); - - ct->tar = data->tar; - BLI_strncpy(ct->subtarget, data->subtarget, sizeof(ct->subtarget)); - ct->space = con->tarspace; - - BLI_addtail(&data->targets, ct); - data->tarnum++; - - /* clear old targets to avoid problems */ - data->tar = NULL; - data->subtarget[0] = '\0'; - } - } - else if (con->type == CONSTRAINT_TYPE_LOCLIKE) { - bLocateLikeConstraint *data = (bLocateLikeConstraint *)con->data; - - /* new headtail functionality makes Bone-Tip function obsolete */ - if (data->flag & LOCLIKE_TIP) - con->headtail = 1.0f; - } - } - } - } - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = (bPythonConstraint *)con->data; - if (data->tar) { - /* version patching needs to be done */ - ct = MEM_callocN(sizeof(bConstraintTarget), "PyConTarget"); - - ct->tar = data->tar; - BLI_strncpy(ct->subtarget, data->subtarget, sizeof(ct->subtarget)); - ct->space = con->tarspace; - - BLI_addtail(&data->targets, ct); - data->tarnum++; - - /* clear old targets to avoid problems */ - data->tar = NULL; - data->subtarget[0] = '\0'; - } - } - else if (con->type == CONSTRAINT_TYPE_LOCLIKE) { - bLocateLikeConstraint *data = (bLocateLikeConstraint *)con->data; - - /* new headtail functionality makes Bone-Tip function obsolete */ - if (data->flag & LOCLIKE_TIP) - con->headtail = 1.0f; + do_version_constraints_245(&pchan->constraints); } } + do_version_constraints_245(&ob->constraints); if (ob->soft && ob->soft->keys) { SoftBody *sb = ob->soft; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index fa7f2d6ae95..f4c08149e05 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -79,9 +79,8 @@ #include <string.h> #include <stdlib.h> -#include "zlib.h" - #ifdef WIN32 +# include <zlib.h> /* odd include order-issue */ # include "winsock2.h" # include <io.h> # include "BLI_winstuff.h" @@ -163,11 +162,9 @@ #include "BKE_mesh.h" #ifdef USE_NODE_COMPAT_CUSTOMNODES -#include "NOD_common.h" #include "NOD_socket.h" /* for sock->default_value data */ #endif -#include "RNA_access.h" #include "BLO_writefile.h" #include "BLO_readfile.h" @@ -1405,7 +1402,7 @@ static void write_pose(WriteData *wd, bPose *pose) /* write IK param */ if (pose->ikparam) { - const char *structname = (char *)BKE_pose_ikparam_get_name(pose); + const char *structname = BKE_pose_ikparam_get_name(pose); if (structname) writestruct(wd, DATA, structname, 1, pose->ikparam); } @@ -2019,7 +2016,8 @@ static void write_lattices(WriteData *wd, ListBase *idbase) static void write_previews(WriteData *wd, PreviewImage *prv) { - if (prv) { + /* Never write previews in undo steps! */ + if (prv && !wd->current) { short w = prv->w[1]; short h = prv->h[1]; unsigned int *rect = prv->rect[1]; @@ -2427,6 +2425,8 @@ static void write_gpencils(WriteData *wd, ListBase *lb) /* write gpd data block to file */ writestruct(wd, ID_GD, "bGPdata", 1, gpd); + if (gpd->adt) write_animdata(wd, gpd->adt); + /* write grease-pencil layers to file */ writelist(wd, DATA, "bGPDlayer", &gpd->layers); for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 39359b97a4e..120ff4997dc 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -256,6 +256,12 @@ enum { #define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE) #define BM_ALL_NOLOOP (BM_VERT | BM_EDGE | BM_FACE) +#define BM_CHECK_TYPE_ELEM(ele) \ + CHECK_TYPE_ANY(ele, void *, BMFace *, BMEdge *, BMVert *, BMLoop *, BMElem *, BMElemF *, BMHeader *) + +#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \ + (BM_CHECK_TYPE_ELEM(ele), CHECK_TYPE_NONCONST(ele)), ele + /* BMHeader->hflag (char) */ enum { BM_ELEM_SELECT = (1 << 0), diff --git a/source/blender/bmesh/intern/bmesh_callback_generic.c b/source/blender/bmesh/intern/bmesh_callback_generic.c index 84fcc67f3c4..913255bfb33 100644 --- a/source/blender/bmesh/intern/bmesh_callback_generic.c +++ b/source/blender/bmesh/intern/bmesh_callback_generic.c @@ -53,3 +53,8 @@ bool BM_elem_cb_check_hflag_disabled(BMElem *ele, void *user_data) return (BM_elem_flag_test(ele, hflag) == 0); } + +bool BM_elem_cb_check_elem_not_equal(BMElem *ele, void *user_data) +{ + return (ele != user_data); +} diff --git a/source/blender/bmesh/intern/bmesh_callback_generic.h b/source/blender/bmesh/intern/bmesh_callback_generic.h index 8c46128f3b0..3cae01d417f 100644 --- a/source/blender/bmesh/intern/bmesh_callback_generic.h +++ b/source/blender/bmesh/intern/bmesh_callback_generic.h @@ -28,6 +28,7 @@ bool BM_elem_cb_check_hflag_enabled(BMElem *, void *user_data); bool BM_elem_cb_check_hflag_disabled(BMElem *, void *user_data); bool BM_elem_cb_check_hflag_ex(BMElem *, void *user_data); +bool BM_elem_cb_check_elem_not_equal(BMElem *ele, void *user_data); #define BM_elem_cb_check_hflag_ex_simple(type, hflag_p, hflag_n) \ (bool (*)(type, void *))BM_elem_cb_check_hflag_ex, \ diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index e83a1d5b00a..aa1f511e8d7 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -662,7 +662,7 @@ void BM_edgeloop_flip(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store) void BM_edgeloop_expand(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, int el_store_len) { - /* first double until we are more then half as big */ + /* first double until we are more than half as big */ while ((el_store->len * 2) < el_store_len) { LinkData *node_curr = el_store->verts.first; while (node_curr) { diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h index 792a9cdfe0d..49e511bdcb5 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.h +++ b/source/blender/bmesh/intern/bmesh_iterators.h @@ -84,30 +84,40 @@ typedef enum BMIterType { extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX]; #define BM_ITER_MESH(ele, iter, bm, itype) \ - for (ele = BM_iter_new(iter, bm, itype, NULL); ele; ele = BM_iter_step(iter)) + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL); \ + ele; \ + BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter)) #define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar) \ - for (ele = BM_iter_new(iter, bm, itype, NULL), indexvar = 0; ele; ele = BM_iter_step(iter), (indexvar)++) + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL), indexvar = 0; \ + ele; \ + BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++) /* a version of BM_ITER_MESH which keeps the next item in storage * so we can delete the current item, see bug [#36923] */ #ifdef DEBUG # define BM_ITER_MESH_MUTABLE(ele, ele_next, iter, bm, itype) \ - for (ele = BM_iter_new(iter, bm, itype, NULL); \ - ele ? ((void)((iter)->count = BM_iter_mesh_count(itype, bm)), \ - (void)(ele_next = BM_iter_step(iter)), 1) : 0; \ - ele = ele_next) + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL); \ + ele ? ((void)((iter)->count = BM_iter_mesh_count(itype, bm)), \ + (void)(ele_next = BM_iter_step(iter)), 1) : 0; \ + BM_CHECK_TYPE_ELEM_ASSIGN(ele) = ele_next) #else # define BM_ITER_MESH_MUTABLE(ele, ele_next, iter, bm, itype) \ - for (ele = BM_iter_new(iter, bm, itype, NULL); ele ? ((ele_next = BM_iter_step(iter)), 1) : 0; ele = ele_next) + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL); \ + ele ? ((BM_CHECK_TYPE_ELEM_ASSIGN(ele_next) = BM_iter_step(iter)), 1) : 0; \ + ele = ele_next) #endif #define BM_ITER_ELEM(ele, iter, data, itype) \ - for (ele = BM_iter_new(iter, NULL, itype, data); ele; ele = BM_iter_step(iter)) + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, NULL, itype, data); \ + ele; \ + BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter)) #define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar) \ - for (ele = BM_iter_new(iter, NULL, itype, data), indexvar = 0; ele; ele = BM_iter_step(iter), (indexvar)++) + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, NULL, itype, data), indexvar = 0; \ + ele; \ + BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++) /* iterator type structs */ struct BMIter__elem_of_mesh { diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index 825bbb136b1..d966d882c67 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -479,7 +479,9 @@ int BMO_iter_map_value_int(BMOIter *iter); bool BMO_iter_map_value_bool(BMOIter *iter); #define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag) \ - for (ele = BMO_iter_new(iter, slot_args, slot_name, restrict_flag); ele; ele = BMO_iter_step(iter)) + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_new(iter, slot_args, slot_name, restrict_flag); \ + ele; \ + BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter)) /******************* Inlined Functions********************/ typedef void (*opexec)(BMesh *bm, BMOperator *op); diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 8557bcd91b7..f39fe29b596 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -82,6 +82,7 @@ enum { SIMFACE_PERIMETER, SIMFACE_NORMAL, SIMFACE_COPLANAR, + SIMFACE_SMOOTH, #ifdef WITH_FREESTYLE SIMFACE_FREESTYLE #endif diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index a5a7bc5189e..e4aa4bb0c0e 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -37,6 +37,7 @@ #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_polyfill2d.h" +#include "BLI_polyfill2d_beautify.h" #include "bmesh.h" #include "bmesh_tools.h" @@ -213,9 +214,6 @@ float BM_face_calc_area(BMFace *f) if (f->len == 3) { area = area_tri_v3(verts[0], verts[1], verts[2]); } - else if (f->len == 4) { - area = area_quad_v3(verts[0], verts[1], verts[2], verts[3]); - } else { area = area_poly_v3((const float (*)[3])verts, f->len); } @@ -742,20 +740,21 @@ bool BM_face_point_inside_test(BMFace *f, const float co[3]) * * \note use_tag tags new flags and edges. */ -void BM_face_triangulate(BMesh *bm, BMFace *f, - BMFace **r_faces_new, - int *r_faces_new_tot, - MemArena *sf_arena, - const int quad_method, - const int ngon_method, - const bool use_tag) +void BM_face_triangulate( + BMesh *bm, BMFace *f, + BMFace **r_faces_new, + int *r_faces_new_tot, + const int quad_method, + const int ngon_method, + const bool use_tag, + MemArena *pf_arena, + + /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ + struct Heap *pf_heap, struct EdgeHash *pf_ehash) { BMLoop *l_iter, *l_first, *l_new; BMFace *f_new; - int orig_f_len = f->len; int nf_i = 0; - BMEdge **edge_array; - int edge_array_len; bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY); BLI_assert(BM_face_is_normal_valid(f)); @@ -781,38 +780,39 @@ void BM_face_triangulate(BMesh *bm, BMFace *f, break; } case MOD_TRIANGULATE_QUAD_SHORTEDGE: - { - BMLoop *l_v3, *l_v4; - float d1, d2; - - l_v1 = l_first; - l_v2 = l_first->next->next; - l_v3 = l_first->next; - l_v4 = l_first->prev; - - d1 = len_squared_v3v3(l_v1->v->co, l_v2->v->co); - d2 = len_squared_v3v3(l_v3->v->co, l_v4->v->co); - - if (d2 < d1) { - l_v1 = l_v3; - l_v2 = l_v4; - } - break; - } case MOD_TRIANGULATE_QUAD_BEAUTY: default: { BMLoop *l_v3, *l_v4; - float cost; + bool split_24; l_v1 = l_first->next; l_v2 = l_first->next->next; l_v3 = l_first->prev; l_v4 = l_first; - cost = BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0); + if (quad_method == MOD_TRIANGULATE_QUAD_SHORTEDGE) { + float d1, d2; + d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co); + d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co); + split_24 = ((d2 - d1) > 0.0f); + } + else { + /* first check if the quad is concave on either diagonal */ + const int flip_flag = is_quad_flip_v3(l_v1->v->co, l_v2->v->co, l_v3->v->co, l_v4->v->co); + if (UNLIKELY(flip_flag & (1 << 0))) { + split_24 = true; + } + else if (UNLIKELY(flip_flag & (1 << 1))) { + split_24 = false; + } + else { + split_24 = (BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) > 0.0f); + } + } - if (cost < 0.0f) { + /* named confusingly, l_v1 is in fact the second vertex */ + if (split_24) { l_v1 = l_v4; //l_v2 = l_v2; } @@ -854,11 +854,12 @@ void BM_face_triangulate(BMesh *bm, BMFace *f, } BLI_polyfill_calc_arena((const float (*)[2])projverts, f->len, -1, tris, - sf_arena); + pf_arena); if (use_beauty) { - edge_array = BLI_array_alloca(edge_array, orig_f_len - 3); - edge_array_len = 0; + BLI_polyfill_beautify( + (const float (*)[2])projverts, f->len, tris, + pf_arena, pf_heap, pf_ehash); } /* loop over calculated triangles and create new geometry */ @@ -895,7 +896,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f, } /* we know any edge that we create and _isnt_ */ - if (use_beauty || use_tag) { + if (use_tag) { /* new faces loops */ l_iter = l_first = l_new; do { @@ -905,92 +906,19 @@ void BM_face_triangulate(BMesh *bm, BMFace *f, bool is_new_edge = (l_iter == l_iter->radial_next); if (is_new_edge) { - if (use_beauty) { - edge_array[edge_array_len] = e; - edge_array_len++; - } - - if (use_tag) { - BM_elem_flag_enable(e, BM_ELEM_TAG); - - } + BM_elem_flag_enable(e, BM_ELEM_TAG); } /* note, never disable tag's */ } while ((l_iter = l_iter->next) != l_first); } } - if ((!use_beauty) || (!r_faces_new)) { + { /* we can't delete the real face, because some of the callers expect it to remain valid. * so swap data and delete the last created tri */ bmesh_face_swap_data(f, f_new); BM_face_kill(bm, f_new); } - - if (use_beauty) { - BLI_assert(edge_array_len <= orig_f_len - 3); - - BM_mesh_beautify_fill(bm, edge_array, edge_array_len, 0, 0, 0, 0); - - if (r_faces_new) { - /* beautify deletes and creates new faces - * we need to re-populate the r_faces_new array - * with the new faces - */ - int i; - - -#define FACE_USED_TEST(f) (BM_elem_index_get(f) == -2) -#define FACE_USED_SET(f) BM_elem_index_set(f, -2) - - nf_i = 0; - for (i = 0; i < edge_array_len; i++) { - BMFace *f_a, *f_b; - BMEdge *e = edge_array[i]; -#ifndef NDEBUG - const bool ok = BM_edge_face_pair(e, &f_a, &f_b); - BLI_assert(ok); -#else - BM_edge_face_pair(e, &f_a, &f_b); -#endif - - if (FACE_USED_TEST(f_a) == false) { - FACE_USED_SET(f_a); /* set_dirty */ - - if (nf_i < edge_array_len) { - r_faces_new[nf_i++] = f_a; - } - else { - f_new = f_a; - break; - } - } - - if (FACE_USED_TEST(f_b) == false) { - FACE_USED_SET(f_b); /* set_dirty */ - - if (nf_i < edge_array_len) { - r_faces_new[nf_i++] = f_b; - } - else { - f_new = f_b; - break; - } - } - } - -#undef FACE_USED_TEST -#undef FACE_USED_SET - - /* nf_i doesn't include the last face */ - BLI_assert(nf_i <= orig_f_len - 3); - - /* we can't delete the real face, because some of the callers expect it to remain valid. - * so swap data and delete the last created tri */ - bmesh_face_swap_data(f, f_new); - BM_face_kill(bm, f_new); - } - } } bm->elem_index_dirty |= BM_FACE; diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index d62c81c4052..b25a7dbaa55 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -27,6 +27,9 @@ * \ingroup bmesh */ +struct EdgeHash; +struct Heap; + #include "BLI_compiler_attrs.h" void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot); @@ -56,12 +59,15 @@ void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL(); void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL(); bool BM_face_point_inside_test(BMFace *f, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void BM_face_triangulate(BMesh *bm, BMFace *f, - BMFace **r_faces_new, - int *r_faces_new_tot, - struct MemArena *sf_arena, - const int quad_method, const int ngon_method, - const bool use_tag) ATTR_NONNULL(1, 2); +void BM_face_triangulate( + BMesh *bm, BMFace *f, + BMFace **r_faces_new, + int *r_faces_new_tot, + const int quad_method, const int ngon_method, + const bool use_tag, + struct MemArena *pf_arena, + struct Heap *pf_heap, struct EdgeHash *pf_ehash + ) ATTR_NONNULL(1, 2); void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL(); void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 0792e956e5b..f56cf76c41d 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -193,7 +193,7 @@ bool BM_vert_pair_share_face_check( BMFace *f; BM_ITER_ELEM (f, &iter, v_a, BM_FACES_OF_VERT) { - if (BM_vert_in_face(f, v_b)) { + if (BM_vert_in_face(v_b, f)) { return true; } } @@ -212,7 +212,7 @@ bool BM_vert_pair_share_face_check_cb( BM_ITER_ELEM (f, &iter, v_a, BM_FACES_OF_VERT) { if (test_fn(f, user_data)) { - if (BM_vert_in_face(f, v_b)) { + if (BM_vert_in_face(v_b, f)) { return true; } } @@ -270,6 +270,36 @@ static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b) } /** + * Check if a point is inside the corner defined by a loop + * (within the 2 planes defined by the loops corner & face normal). + * + * \return less than 0.0 when inside. + */ +float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) +{ + const float *axis = l->f->no; + return (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, co, axis) - + angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, axis)); +} + +/** + * Check if a point is inside the edge defined by a loop + * (within the plane defined by the loops edge & face normal). + * + * \return less than 0.0 when inside. + */ +float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) +{ + const float *axis = l->f->no; + float dir[3]; + float plane[3]; + sub_v3_v3v3(dir, l->v->co, l->next->v->co); + cross_v3_v3v3(plane, axis, dir); + return (dot_v3v3(plane, co) - + dot_v3v3(plane, l->v->co)); +} + +/** * Given 2 verts, find a face they share that has the lowest angle across these verts and give back both loops. * * This can be better then #BM_vert_pair_share_face_by_len because concave splits are ranked lowest. @@ -345,7 +375,7 @@ BMLoop *BM_vert_find_first_loop(BMVert *v) /** * Returns true if the vertex is used in a given face. */ -bool BM_vert_in_face(BMFace *f, BMVert *v) +bool BM_vert_in_face(BMVert *v, BMFace *f) { BMLoop *l_iter, *l_first; @@ -373,7 +403,7 @@ bool BM_vert_in_face(BMFace *f, BMVert *v) * Compares the number of vertices in an array * that appear in a given face */ -int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len) +int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) { BMLoop *l_iter, *l_first; @@ -417,7 +447,7 @@ int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len) /** * Return true if all verts are in the face. */ -bool BM_verts_in_face(BMFace *f, BMVert **varr, int len) +bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) { BMLoop *l_iter, *l_first; @@ -714,17 +744,17 @@ bool BM_vert_is_edge_pair(BMVert *v) /** * Returns the number of edges around this vertex. */ -int BM_vert_edge_count(BMVert *v) +int BM_vert_edge_count(const BMVert *v) { return bmesh_disk_count(v); } -int BM_vert_edge_count_nonwire(BMVert *v) +int BM_vert_edge_count_nonwire(const BMVert *v) { int count = 0; BMIter eiter; BMEdge *edge; - BM_ITER_ELEM (edge, &eiter, v, BM_EDGES_OF_VERT) { + BM_ITER_ELEM (edge, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) { if (edge->l) { count++; } @@ -734,7 +764,7 @@ int BM_vert_edge_count_nonwire(BMVert *v) /** * Returns the number of faces around this edge */ -int BM_edge_face_count(BMEdge *e) +int BM_edge_face_count(const BMEdge *e) { int count = 0; @@ -756,7 +786,7 @@ int BM_edge_face_count(BMEdge *e) * Returns the number of faces around this vert * length matches #BM_LOOPS_OF_VERT iterator */ -int BM_vert_face_count(BMVert *v) +int BM_vert_face_count(const BMVert *v) { return bmesh_disk_facevert_count(v); } @@ -1572,7 +1602,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) #if 0 BM_ITER_ELEM (f, &viter, v_search, BM_FACES_OF_VERT) { if (f->len == len) { - if (BM_verts_in_face(f, varr, len)) { + if (BM_verts_in_face(varr, len, f)) { if (r_existface) { *r_existface = f; } @@ -1797,7 +1827,7 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len) * * \note The face may contain other verts \b not in \a varr. * - * \note Its possible there are more then one overlapping faces, + * \note Its possible there are more than one overlapping faces, * in this case the first one found will be assigned to \a r_f_overlap. * * \param varr Array of unordered verts. @@ -1830,7 +1860,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) for (i = 0; i < len; i++) { BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) { - if (len <= BM_verts_in_face_count(f, varr, len)) { + if (len <= BM_verts_in_face_count(varr, len, f)) { if (r_f_overlap) *r_f_overlap = f; diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index b5b423ed58f..5e6d4b5154b 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -27,9 +27,9 @@ * \ingroup bmesh */ -bool BM_vert_in_face(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_verts_in_face(BMFace *f, BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_edge_in_face(BMEdge *e, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -64,10 +64,10 @@ BMFace *BM_vert_pair_share_face_by_angle( BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent) ATTR_NONNULL(); -int BM_vert_edge_count_nonwire(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int BM_vert_edge_count(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int BM_edge_face_count(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int BM_vert_face_count(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_edge_pair(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -83,6 +83,8 @@ bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL( bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); float BM_loop_calc_face_angle(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]) ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c index c6829b8d5f1..b7bf80b0e3f 100644 --- a/source/blender/bmesh/intern/bmesh_walkers_impl.c +++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c @@ -33,7 +33,6 @@ #include "BKE_customdata.h" #include "bmesh.h" -#include "intern/bmesh_private.h" #include "intern/bmesh_walkers_private.h" /* pop into stack memory (common operation) */ diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index e4417477e76..6002dcf2c0d 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -180,20 +180,42 @@ static void bridge_loop_pair(BMesh *bm, /* normalizing isn't strictly needed but without we may get very large values */ float no[3]; + float dir_a_orig[3], dir_b_orig[3]; float dir_a[3], dir_b[3]; + const float *test_a, *test_b; - sub_v3_v3v3(dir_a, + sub_v3_v3v3(dir_a_orig, ((BMVert *)(((LinkData *)lb_a->first)->data))->co, ((BMVert *)(((LinkData *)lb_a->last)->data))->co); - sub_v3_v3v3(dir_b, + sub_v3_v3v3(dir_b_orig, ((BMVert *)(((LinkData *)lb_b->first)->data))->co, ((BMVert *)(((LinkData *)lb_b->last)->data))->co); /* make the directions point out from the normals, 'no' is used as a temp var */ - cross_v3_v3v3(no, dir_a, el_dir); cross_v3_v3v3(dir_a, no, el_dir); - cross_v3_v3v3(no, dir_b, el_dir); cross_v3_v3v3(dir_b, no, el_dir); + cross_v3_v3v3(no, dir_a_orig, el_dir); cross_v3_v3v3(dir_a, no, el_dir); + cross_v3_v3v3(no, dir_b_orig, el_dir); cross_v3_v3v3(dir_b, no, el_dir); - if (dot_v3v3(dir_a, dir_b) < 0.0f) { + if (LIKELY(!is_zero_v3(dir_a) && !is_zero_v3(dir_b))) { + test_a = dir_a; + test_b = dir_b; + } + else { + /** + * This is a corner case: + * + * <pre> + * (loop a) (loop b) + * +--------+ +--------+ + * </pre> + * + * When loops are aligned to the direction between the loops values of 'dir_a/b' is degenerate, + * in this case compare the original directions (before they were corrected by 'el_dir'), see: T43013 + */ + test_a = dir_a_orig; + test_b = dir_b_orig; + } + + if (dot_v3v3(test_a, test_b) < 0.0f) { BM_edgeloop_flip(bm, el_store_b); } diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index 418e75b7ac3..9db87ddfb77 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -141,7 +141,7 @@ static void state_calc_co_pair(const PathContext *pc, /** * Ideally we wouldn't need this and for most cases we don't. - * But when a face has vertices that are on the boundary more then once this becomes tricky. + * But when a face has vertices that are on the boundary more than once this becomes tricky. */ static bool state_link_find(PathLinkState *state, BMElem *ele) { @@ -464,19 +464,23 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) negate_v3(basis_nor_b); } add_v3_v3v3(basis_nor, basis_nor_a, basis_nor_b); - - if (UNLIKELY(fabsf(dot_v3v3(basis_nor, basis_dir)) < FLT_EPSILON)) { - ortho_v3_v3(basis_nor, basis_dir); - } } #endif /* get third axis */ + normalize_v3(basis_dir); + normalize_v3(basis_nor); cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); + if (UNLIKELY(normalize_v3(basis_tmp) < FLT_EPSILON)) { + ortho_v3_v3(basis_nor, basis_dir); + normalize_v3(basis_nor); + cross_v3_v3v3(basis_tmp, basis_dir, basis_nor); + normalize_v3(basis_tmp); + } - normalize_v3_v3(pc.matrix[0], basis_tmp); - normalize_v3_v3(pc.matrix[1], basis_dir); - normalize_v3_v3(pc.matrix[2], basis_nor); + copy_v3_v3(pc.matrix[0], basis_tmp); + copy_v3_v3(pc.matrix[1], basis_dir); + copy_v3_v3(pc.matrix[2], basis_nor); invert_m3(pc.matrix); pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_a->co); diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index cd5592f08c9..a5a6480c187 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -109,7 +109,7 @@ static BMEdge *bmo_edge_copy(BMOperator *op, /* add to new/old edge map if necassary */ if (rlen < 2) { - /* not sure what non-manifold cases of greater then three + /* not sure what non-manifold cases of greater than three * radial should do. */ BMO_slot_map_elem_insert(op, slot_boundarymap_out, e_src, e_dst); } diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 26a4dbe1e1d..fb99c9777d0 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -285,8 +285,8 @@ static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles, /* Note: can't change ghash while iterating, so mark * with 'skip' flag rather than deleting triangles */ - if (BM_vert_in_face(f, t->v[1]) && - BM_vert_in_face(f, t->v[2]) && f_on_hull) + if (BM_vert_in_face(t->v[1], f) && + BM_vert_in_face(t->v[2], f) && f_on_hull) { t->skip = true; BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index e69dcca6342..2108a2c0589 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -662,78 +662,46 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) void bmo_create_cube_exec(BMesh *bm, BMOperator *op) { - BMVert *v1, *v2, *v3, *v4, *v5, *v6, *v7, *v8; - float vec[3], mat[4][4], off = BMO_slot_float_get(op->slots_in, "size") / 2.0f; + BMVert *verts[8]; + float mat[4][4]; + float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f; + int i, x, y, z; + const char faces[6][4] = { + {1, 3, 2, 0}, + {3, 7, 6, 2}, + {7, 5, 4, 6}, + {5, 1, 0, 4}, + {0, 2, 6, 4}, + {5, 7, 3, 1}, + }; BMO_slot_mat4_get(op->slots_in, "matrix", mat); if (!off) off = 0.5f; + i = 0; - vec[0] = -off; - vec[1] = -off; - vec[2] = -off; - mul_m4_v3(mat, vec); - v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v1, VERT_MARK); - - vec[0] = -off; - vec[1] = off; - vec[2] = -off; - mul_m4_v3(mat, vec); - v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v2, VERT_MARK); - - vec[0] = off; - vec[1] = off; - vec[2] = -off; - mul_m4_v3(mat, vec); - v3 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v3, VERT_MARK); - - vec[0] = off; - vec[1] = -off; - vec[2] = -off; - mul_m4_v3(mat, vec); - v4 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v4, VERT_MARK); - - vec[0] = -off; - vec[1] = -off; - vec[2] = off; - mul_m4_v3(mat, vec); - v5 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v5, VERT_MARK); - - vec[0] = -off; - vec[1] = off; - vec[2] = off; - mul_m4_v3(mat, vec); - v6 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v6, VERT_MARK); - - vec[0] = off; - vec[1] = off; - vec[2] = off; - mul_m4_v3(mat, vec); - v7 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v7, VERT_MARK); - - vec[0] = off; - vec[1] = -off; - vec[2] = off; - mul_m4_v3(mat, vec); - v8 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v8, VERT_MARK); - - /* the four sides */ - BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, BM_CREATE_NOP); - BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, BM_CREATE_NOP); - BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, BM_CREATE_NOP); - BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, BM_CREATE_NOP); - - /* top/bottom */ - BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, BM_CREATE_NOP); - BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, BM_CREATE_NOP); + for (x = -1; x < 2; x += 2) { + for (y = -1; y < 2; y += 2) { + for (z = -1; z < 2; z += 2) { + float vec[3] = {(float)x * off, (float)y * off, (float)z * off}; + mul_m4_v3(mat, vec); + verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); + BMO_elem_flag_enable(bm, verts[i], VERT_MARK); + i++; + } + } + } + + for (i = 0; i < ARRAY_SIZE(faces); i++) { + BMVert *quad[4] = { + verts[faces[i][0]], + verts[faces[i][1]], + verts[faces[i][2]], + verts[faces[i][3]], + }; + + BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true); + } BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 75f9feef413..9c8b9ca160d 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -238,7 +238,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) static int vergaverco(const void *e1, const void *e2) { - const BMVert *v1 = *(void **)e1, *v2 = *(void **)e2; + const BMVert *v1 = *(const void **)e1, *v2 = *(const void **)e2; float x1 = v1->co[0] + v1->co[1] + v1->co[2]; float x2 = v2->co[0] + v2->co[1] + v2->co[2]; diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c index 4b5eebb2a73..02462e380b4 100644 --- a/source/blender/bmesh/operators/bmo_similar.c +++ b/source/blender/bmesh/operators/bmo_similar.c @@ -245,6 +245,13 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) cont = false; } break; + + case SIMFACE_SMOOTH: + if (BM_elem_flag_test(fm, BM_ELEM_SMOOTH) == BM_elem_flag_test(fs, BM_ELEM_SMOOTH)) { + BMO_elem_flag_enable(bm, fm, FACE_MARK); + cont = false; + } + break; #ifdef WITH_FREESTYLE case SIMFACE_FREESTYLE: if (CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) { diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 7b125186110..87311199f52 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -1082,7 +1082,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) BMIter other_fiter; BM_ITER_ELEM (other_loop, &other_fiter, loops[a]->v, BM_LOOPS_OF_VERT) { if (other_loop->f != face) { - if (BM_vert_in_face(other_loop->f, loops[b]->v)) { + if (BM_vert_in_face(loops[b]->v, other_loop->f)) { /* we assume that these verts are not making an edge in the face */ BLI_assert(other_loop->prev->v != loops[a]->v); BLI_assert(other_loop->next->v != loops[a]->v); diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index e7b65a10790..da1991a187d 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -236,6 +236,20 @@ static void bmo_region_extend_expand( bmo_face_flag_set_flush(bm, f, SEL_FLAG, true); } } + + /* handle wire edges (when stepping over faces) */ + { + BMIter eiter; + BMEdge *e; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_wire(e)) { + if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) { + BMO_elem_flag_enable(bm, e, SEL_FLAG); + BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); + } + } + } + } } } } @@ -306,6 +320,21 @@ static void bmo_region_extend_contract( break; } } + + /* handle wire edges (when stepping over faces) */ + if (!found) { + BMIter eiter; + BMEdge *e; + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_wire(e)) { + if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) { + found = true; + break; + } + } + } + } } if (found) { diff --git a/source/blender/bmesh/operators/bmo_wireframe.c b/source/blender/bmesh/operators/bmo_wireframe.c index 62409fc3987..ac81dde93c0 100644 --- a/source/blender/bmesh/operators/bmo_wireframe.c +++ b/source/blender/bmesh/operators/bmo_wireframe.c @@ -26,8 +26,6 @@ * Creates a solid wireframe from connected faces. */ -#include "MEM_guardedalloc.h" - #include "DNA_material_types.h" #include "BLI_sys_types.h" diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c index 6639e767e77..990a2108bd7 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.c +++ b/source/blender/bmesh/tools/bmesh_beautify.c @@ -37,6 +37,7 @@ #include "BLI_math.h" #include "BLI_heap.h" +#include "BLI_polyfill2d_beautify.h" #include "MEM_guardedalloc.h" @@ -96,7 +97,7 @@ static GSet *erot_gset_new(void) static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2]) { - BLI_assert(BM_edge_is_manifold((BMEdge *)e)); + BLI_assert(BM_edge_is_manifold(e)); BLI_assert(BM_vert_in_edge(e, e->l->prev->v) == false); BLI_assert(BM_vert_in_edge(e, e->l->radial_next->prev->v) == false); @@ -125,22 +126,22 @@ static void erot_state_alternate(const BMEdge *e, EdRotState *e_state) /* -------------------------------------------------------------------- */ /* Calculate the improvement of rotating the edge */ -/** - * \return a negative value means the edge can be rotated. - */ static float bm_edge_calc_rotate_beauty__area( const float v1[3], const float v2[3], const float v3[3], const float v4[3]) { /* not a loop (only to be able to break out) */ do { float v1_xy[2], v2_xy[2], v3_xy[2], v4_xy[2]; - bool is_zero_a, is_zero_b; /* first get the 2d values */ { + const float eps = 1e-5; float no_a[3], no_b[3]; float no[3]; float axis_mat[3][3]; + float no_scale; + cross_tri_v3(no_a, v2, v3, v4); + cross_tri_v3(no_b, v2, v4, v1); // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f); BLI_assert((ELEM(v1, v2, v3, v4) == false) && @@ -148,97 +149,40 @@ static float bm_edge_calc_rotate_beauty__area( (ELEM(v3, v1, v2, v4) == false) && (ELEM(v4, v1, v2, v3) == false)); - is_zero_a = (normal_tri_v3(no_a, v2, v3, v4) <= FLT_EPSILON); - is_zero_b = (normal_tri_v3(no_b, v2, v4, v1) <= FLT_EPSILON); - - if (LIKELY(is_zero_a == false && is_zero_b == false)) { - add_v3_v3v3(no, no_a, no_b); - if (UNLIKELY(normalize_v3(no) <= FLT_EPSILON)) { - break; - } - } - else if (is_zero_a == false) { - copy_v3_v3(no, no_a); - } - else if (is_zero_b == false) { - copy_v3_v3(no, no_b); - } - else { - /* both zero area, no useful normal can be calculated */ + add_v3_v3v3(no, no_a, no_b); + if (UNLIKELY((no_scale = normalize_v3(no)) <= FLT_EPSILON)) { break; } - // { float a = angle_normalized_v3v3(no_a, no_b); printf("~ %.7f\n", a); fflush(stdout);} - axis_dominant_v3_to_m3(axis_mat, no); mul_v2_m3v3(v1_xy, axis_mat, v1); mul_v2_m3v3(v2_xy, axis_mat, v2); mul_v2_m3v3(v3_xy, axis_mat, v3); mul_v2_m3v3(v4_xy, axis_mat, v4); - } - - // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f); - - if (is_zero_a == false && is_zero_b == false) { - /* both tri's are valid, check we make a concave quad */ - if (!is_quad_convex_v2(v1_xy, v2_xy, v3_xy, v4_xy)) { - break; - } - } - else { - /* one of the tri's was degenerate, chech we're not rotating - * into a different degenerate shape or flipping the face */ - float area_a, area_b; - - area_a = area_tri_signed_v2(v1_xy, v2_xy, v3_xy); - area_b = area_tri_signed_v2(v1_xy, v3_xy, v4_xy); - - if ((fabsf(area_a) <= FLT_EPSILON) || (fabsf(area_b) <= FLT_EPSILON)) { - /* one of the new rotations is degenerate */ - break; - } - if ((area_a >= 0.0f) != (area_b >= 0.0f)) { - /* rotation would cause flipping */ + /** + * Check if input faces are already flipped. + * Logic for 'signum_i' addition is: + * + * Accept: + * - (1, 1) or (-1, -1): same side (common case). + * - (-1/1, 0): one degenerate, OK since we may rotate into a valid state. + * + * Ignore: + * - (-1, 1): opposite winding, ignore. + * - ( 0, 0): both degenerate, ignore. + * + * \note The cross product is divided by 'no_scale' + * so the rotation calculation is scale independent. + */ + if (!(signum_i_ex(cross_tri_v2(v2_xy, v3_xy, v4_xy) / no_scale, eps) + + signum_i_ex(cross_tri_v2(v2_xy, v4_xy, v1_xy) / no_scale, eps))) + { break; } } - { - /* testing rule: the area divided by the perimeter, - * check if (1-3) beats the existing (2-4) edge rotation */ - float area_a, area_b; - float prim_a, prim_b; - float fac_24, fac_13; - - float len_12, len_23, len_34, len_41, len_24, len_13; - - /* edges around the quad */ - len_12 = len_v2v2(v1_xy, v2_xy); - len_23 = len_v2v2(v2_xy, v3_xy); - len_34 = len_v2v2(v3_xy, v4_xy); - len_41 = len_v2v2(v4_xy, v1_xy); - /* edges crossing the quad interior */ - len_13 = len_v2v2(v1_xy, v3_xy); - len_24 = len_v2v2(v2_xy, v4_xy); - - /* edge (2-4), current state */ - area_a = area_tri_v2(v2_xy, v3_xy, v4_xy); - area_b = area_tri_v2(v2_xy, v4_xy, v1_xy); - prim_a = len_23 + len_34 + len_24; - prim_b = len_24 + len_41 + len_12; - fac_24 = (area_a / prim_a) + (area_b / prim_b); - - /* edge (1-3), new state */ - area_a = area_tri_v2(v1_xy, v2_xy, v3_xy); - area_b = area_tri_v2(v1_xy, v3_xy, v4_xy); - prim_a = len_12 + len_23 + len_13; - prim_b = len_34 + len_41 + len_13; - fac_13 = (area_a / prim_a) + (area_b / prim_b); - - /* negative number if (1-3) is an improved state */ - return fac_24 - fac_13; - } + return BLI_polyfill_beautify_quad_rotate_calc(v1_xy, v2_xy, v3_xy, v4_xy); } while (false); return FLT_MAX; @@ -272,6 +216,12 @@ static float bm_edge_calc_rotate_beauty__angle( return FLT_MAX; } +/** + * Assuming we have 2 triangles sharing an edge (2 - 4), + * check if the edge running from (1 - 3) gives better results. + * + * \return (negative number means the edge can be rotated, lager == better). + */ float BM_verts_calc_rotate_beauty( const BMVert *v1, const BMVert *v2, const BMVert *v3, const BMVert *v4, const short flag, const short method) @@ -400,9 +350,10 @@ static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_ /** * \note This function sets the edge indices to invalid values. */ -void BM_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge_array_len, - const short flag, const short method, - const short oflag_edge, const short oflag_face) +void BM_mesh_beautify_fill( + BMesh *bm, BMEdge **edge_array, const int edge_array_len, + const short flag, const short method, + const short oflag_edge, const short oflag_face) { Heap *eheap; /* edge heap */ HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */ diff --git a/source/blender/bmesh/tools/bmesh_beautify.h b/source/blender/bmesh/tools/bmesh_beautify.h index 7cc17008b50..0d6aa23b81d 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.h +++ b/source/blender/bmesh/tools/bmesh_beautify.h @@ -31,12 +31,14 @@ enum { VERT_RESTRICT_TAG = (1 << 0), }; -void BM_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge_array_len, - const short flag, const short method, - const short oflag_edge, const short oflag_face); +void BM_mesh_beautify_fill( + BMesh *bm, BMEdge **edge_array, const int edge_array_len, + const short flag, const short method, + const short oflag_edge, const short oflag_face); -float BM_verts_calc_rotate_beauty(const BMVert *v1, const BMVert *v2, - const BMVert *v3, const BMVert *v4, - const short flag, const short method); +float BM_verts_calc_rotate_beauty( + const BMVert *v1, const BMVert *v2, + const BMVert *v3, const BMVert *v4, + const short flag, const short method); #endif /* __BMESH_BEAUTIFY_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 99ff6996b71..b25572ed8e2 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1474,7 +1474,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) return; } - lastd = bp->vertex_only ? bv->offset : e->offset_l; + lastd = e->offset_l; do { if (e->is_bev) { /* handle only left side of beveled edge e here: next iteration should do right side */ @@ -1557,9 +1557,10 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) /* None of e->prev, e, e->next are beveled. * could either leave alone or add slide points to make * one polygon around bv->v. For now, we choose latter. + * For vertex bevel, we use e->offset_l as slide distance. * Could slide to make an even bevel plane but for now will * just use last distance a meet point moved from bv->v. */ - slide_dist(e, bv->v, lastd, co); + slide_dist(e, bv->v, bp->vertex_only ? e->offset_l : lastd, co); if (construct) { v = add_new_bound_vert(mem_arena, vm, co); v->efirst = v->elast = e; @@ -2229,7 +2230,6 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) BoundVert *bndv; int i, j, k, ns2; float co[3], coc[3]; - float w; if (r == PRO_SQUARE_R) return make_cube_corner_straight(mem_arena, nseg); @@ -2262,10 +2262,8 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) bndv = bndv->next; } /* center vertex */ - w = (float)(1.0 / M_SQRT3); - co[0] = w; - co[1] = w; - co[2] = w; + copy_v3_fl(co, M_SQRT1_3); + if (nseg > 2) { if (r > 1.5f) mul_v3_fl(co, 1.4f); @@ -3081,6 +3079,18 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) e->offset_r_spec *= weight; } } + else if (bp->vertex_only) { + /* Weight has already been applied to bv->offset, if present. + * Transfer to e->offset_[lr]_spec and treat percent as special case */ + if (bp->offset_type == BEVEL_AMT_PERCENT) { + v2 = BM_edge_other_vert(e->e, bv->v); + e->offset_l_spec = BM_edge_calc_length(e->e) * bv->offset / 100.0f; + } + else { + e->offset_l_spec = bv->offset; + } + e->offset_r_spec = e->offset_l_spec; + } else { e->offset_l_spec = e->offset_r_spec = 0.0f; } diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c index 463304f27f7..e6e33c905da 100644 --- a/source/blender/bmesh/tools/bmesh_bisect_plane.c +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -112,7 +112,7 @@ static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v) static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], const short oflag_center) { - /* unlikely more then 2 verts are needed */ + /* unlikely more than 2 verts are needed */ const unsigned int f_len_orig = (unsigned int)f->len; BMVert **vert_split_arr = BLI_array_alloca(vert_split_arr, f_len_orig); STACK_DECLARE(vert_split_arr); diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 4d87c3e3551..8a1569630fa 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -857,7 +857,7 @@ bool BM_mesh_intersect( {UNPACK3(looptris[i][2]->v->co)}, }; - BLI_bvhtree_insert(tree_a, i, (float *)t_cos, 3); + BLI_bvhtree_insert(tree_a, i, (const float *)t_cos, 3); } } BLI_bvhtree_balance(tree_a); @@ -874,7 +874,7 @@ bool BM_mesh_intersect( {UNPACK3(looptris[i][2]->v->co)}, }; - BLI_bvhtree_insert(tree_b, i, (float *)t_cos, 3); + BLI_bvhtree_insert(tree_b, i, (const float *)t_cos, 3); } } BLI_bvhtree_balance(tree_b); diff --git a/source/blender/bmesh/tools/bmesh_triangulate.c b/source/blender/bmesh/tools/bmesh_triangulate.c index 446c03a543f..b76054f270f 100644 --- a/source/blender/bmesh/tools/bmesh_triangulate.c +++ b/source/blender/bmesh/tools/bmesh_triangulate.c @@ -27,13 +27,20 @@ * */ +#include "DNA_modifier_types.h" /* for MOD_TRIANGULATE_NGON_BEAUTY only */ + #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" #include "BLI_alloca.h" #include "BLI_memarena.h" #include "BLI_listbase.h" -#include "BLI_scanfill.h" +#include "BLI_heap.h" +#include "BLI_edgehash.h" + +/* only for defines */ +#include "BLI_polyfill2d.h" +#include "BLI_polyfill2d_beautify.h" #include "bmesh.h" @@ -42,16 +49,25 @@ /** * a version of #BM_face_triangulate that maps to #BMOpSlot */ -static void bm_face_triangulate_mapping(BMesh *bm, BMFace *face, MemArena *sf_arena, - const int quad_method, const int ngon_method, - const bool use_tag, - BMOperator *op, BMOpSlot *slot_facemap_out) +static void bm_face_triangulate_mapping( + BMesh *bm, BMFace *face, + const int quad_method, const int ngon_method, + const bool use_tag, + BMOperator *op, BMOpSlot *slot_facemap_out, + + MemArena *pf_arena, + /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ + struct Heap *pf_heap, struct EdgeHash *pf_ehash) { int faces_array_tot = face->len - 3; BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); BLI_assert(face->len > 3); - BM_face_triangulate(bm, face, faces_array, &faces_array_tot, sf_arena, quad_method, ngon_method, use_tag); + BM_face_triangulate( + bm, face, faces_array, &faces_array_tot, + quad_method, ngon_method, use_tag, + pf_arena, + pf_heap, pf_ehash); if (faces_array_tot) { int i; @@ -63,22 +79,39 @@ static void bm_face_triangulate_mapping(BMesh *bm, BMFace *face, MemArena *sf_ar } -void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only, - BMOperator *op, BMOpSlot *slot_facemap_out) +void BM_mesh_triangulate( + BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only, + BMOperator *op, BMOpSlot *slot_facemap_out) { BMIter iter; BMFace *face; - MemArena *sf_arena; + MemArena *pf_arena; + Heap *pf_heap; + EdgeHash *pf_ehash; - sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); + pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); + + if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) { + pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); + pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); + } + else { + pf_heap = NULL; + pf_ehash = NULL; + } if (slot_facemap_out) { /* same as below but call: bm_face_triangulate_mapping() */ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { if (face->len > 3) { if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) { - bm_face_triangulate_mapping(bm, face, sf_arena, quad_method, ngon_method, tag_only, - op, slot_facemap_out); + bm_face_triangulate_mapping( + bm, face, quad_method, + ngon_method, tag_only, + op, slot_facemap_out, + + pf_arena, + pf_heap, pf_ehash); } } } @@ -87,11 +120,20 @@ void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { if (face->len > 3) { if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) { - BM_face_triangulate(bm, face, NULL, NULL, sf_arena, quad_method, ngon_method, tag_only); + BM_face_triangulate( + bm, face, NULL, NULL, + quad_method, ngon_method, tag_only, + pf_arena, + pf_heap, pf_ehash); } } } } - BLI_memarena_free(sf_arena); + BLI_memarena_free(pf_arena); + + if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) { + BLI_heap_free(pf_heap, NULL); + BLI_edgehash_free(pf_ehash, NULL); + } } diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index 033145b33d1..7ffd300c6de 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -37,6 +37,7 @@ #include "BKE_object.h" #include "BKE_armature.h" #include "BLI_string.h" +#include "BLI_listbase.h" #include "ED_armature.h" #include "ArmatureImporter.h" @@ -49,7 +50,22 @@ static const char *bc_get_joint_name(T *node) return id.size() ? id.c_str() : node->getOriginalId().c_str(); } -ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce) : +static EditBone *get_edit_bone(bArmature * armature, char *name) { + EditBone *eBone; + + for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) { + if (!strcmp(name, eBone->name)) + return eBone; + } + + return NULL; + +} + + + +ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) : + import_settings(import_settings), unit_converter(conv), TransformReader(conv), scene(sce), @@ -57,6 +73,15 @@ ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, mesh_importer(mesh) { } +void ArmatureImporter::clear_extended_boneset() +{ + for (std::map<std::string, BoneExtended *>::iterator it = extended_bones.begin(); it != extended_bones.end(); ++it) { + if (it->second != NULL) + delete it->second; + } + extended_bones.clear(); +} + ArmatureImporter::~ArmatureImporter() { // free skin controller data if we forget to do this earlier @@ -64,6 +89,7 @@ ArmatureImporter::~ArmatureImporter() for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { it->second.free(); } + clear_extended_boneset(); } #if 0 @@ -83,16 +109,17 @@ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node); } #endif -void ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBone *parent, int totchild, +int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBone *parent, int totchild, float parent_mat[4][4], bArmature *arm) { float mat[4][4]; float joint_inv_bind_mat[4][4]; + int chain_length = 0; //Checking if bone is already made. std::vector<COLLADAFW::Node *>::iterator it; it = std::find(finished_joints.begin(), finished_joints.end(), node); - if (it != finished_joints.end()) return; + if (it != finished_joints.end()) return chain_length; // JointData* jd = get_joint_data(node); @@ -143,96 +170,156 @@ void ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBo // set tail, don't set it to head because 0-length bones are not allowed add_v3_v3v3(bone->tail, bone->head, vec); - // set parent tail + /* find smallest bone length in armature (used later for leaf bone length) */ if (parent) { - // XXX increase this to prevent "very" small bones? - const float epsilon = 0.000001f; - - // derive leaf bone length + /* guess reasonable leaf bone length */ float length = len_v3v3(parent->head, bone->head); - if ((length < leaf_bone_length || totbone == 0) && length > epsilon) { + if ((length < leaf_bone_length || totbone == 0) && length > MINIMUM_BONE_LENGTH) { leaf_bone_length = length; } - - if (totchild == 1) { - copy_v3_v3(parent->tail, bone->head); - - // not setting BONE_CONNECTED because this would lock child bone location with respect to parent - bone->flag |= BONE_CONNECTED; - - - // treat zero-sized bone like a leaf bone - if (length <= epsilon) { - add_leaf_bone(parent_mat, parent, node); - } - } - } COLLADAFW::NodePointerArray& children = node->getChildNodes(); + + BoneExtended &be = add_bone_extended(bone, node); + be.set_leaf_bone(true); + for (unsigned int i = 0; i < children.getCount(); i++) { - create_bone(skin, children[i], bone, children.getCount(), mat, arm); + int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm); + if (cl > chain_length) + chain_length = cl; } - // in second case it's not a leaf bone, but we handle it the same way - if (!children.getCount() || children.getCount() > 1) { - add_leaf_bone(mat, bone, node); - } bone->length = len_v3v3(bone->head, bone->tail); joint_by_uid[node->getUniqueId()] = node; finished_joints.push_back(node); + + be.set_chain_length(chain_length + 1); + + return chain_length + 1; } -void ArmatureImporter::add_leaf_bone(float mat[4][4], EditBone *bone, COLLADAFW::Node *node) +/** + * Collada only knows Joints, hence bones at the end of a bone chain + * don't have a defined length. This function guesses reasonable + * tail locations for the affected bones (nodes which don't have any connected child) + * Hint: The extended_bones set gets populated in ArmatureImporter::create_bone +**/ +void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone) { - LeafBone leaf; + /* armature has no bones */ + if (bone == NULL) + return; - leaf.bone = bone; - copy_m4_m4(leaf.mat, mat); - BLI_strncpy(leaf.name, bone->name, sizeof(leaf.name)); - - TagsMap::iterator etit; - ExtraTags *et = 0; - etit = uid_tags_map.find(node->getUniqueId().toAscii()); - if (etit != uid_tags_map.end()) { - et = etit->second; - //else return; + BoneExtended *be = extended_bones[bone->name]; + if (be != NULL && be->is_leaf_bone() ) { + /* Collada only knows Joints, Here we guess a reasonable leaf bone length */ + float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length; + + EditBone *ebone = get_edit_bone(armature, bone->name); + float vec[3]; + + if (this->import_settings->fix_orientation) { + if (ebone->parent != NULL) { + EditBone *parent = ebone->parent; + sub_v3_v3v3(vec, ebone->head, parent->tail); + if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH) + { + sub_v3_v3v3(vec, parent->tail, parent->head); + } + } + else { + vec[2] = 0.1f; + sub_v3_v3v3(vec, ebone->tail, ebone->head); + } + } + else { + sub_v3_v3v3(vec, ebone->tail, ebone->head); + } - float x, y, z; - et->setData("tip_x", &x); - et->setData("tip_y", &y); - et->setData("tip_z", &z); - float vec[3] = {x, y, z}; - copy_v3_v3(leaf.bone->tail, leaf.bone->head); - add_v3_v3v3(leaf.bone->tail, leaf.bone->head, vec); - } - else { - leaf_bones.push_back(leaf); + normalize_v3_v3(vec, vec); + mul_v3_fl(vec, leaf_length); + add_v3_v3v3(ebone->tail, ebone->head, vec); } -} -void ArmatureImporter::fix_leaf_bones( ) -{ - // Collada only knows Joints, Here we guess a reasonable - // leaf bone length - float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0:leaf_bone_length; + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { + fix_leaf_bones(armature, child); + } - // just setting tail for leaf bones here - std::vector<LeafBone>::iterator it; - for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) { +} - LeafBone& leaf = *it; - // pointing up - float vec[3] = {0.0f, 0.0f, 0.1f}; - - sub_v3_v3v3(vec, leaf.bone->tail , leaf.bone->head); - mul_v3_fl(vec, leaf_length); - add_v3_v3v3(leaf.bone->tail, leaf.bone->head , vec); +void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone, int clip) +{ + BoneExtended *dominant_child = NULL; + int maxlen = 0; + Bone *child = (Bone *)parentbone->childbase.first; + if (child && (import_settings->find_chains || child->next==NULL) ) + { + for (; child; child = child->next) { + BoneExtended *be = extended_bones[child->name]; + if (be != NULL) { + if (be->get_chain_length() <= clip) { + if (be->get_chain_length() > maxlen) { + dominant_child = be; + maxlen = be->get_chain_length(); + } + else if (be->get_chain_length() == maxlen) { + dominant_child = NULL; + } + } + } + } + } + BoneExtended *pbe = extended_bones[parentbone->name]; + if (dominant_child != NULL) { + /* Found a valid chain. Now connect current bone with that chain.*/ + EditBone *pebone = get_edit_bone(armature, parentbone->name); + EditBone *cebone = get_edit_bone(armature, dominant_child->get_name()); + if (pebone && !(cebone->flag & BONE_CONNECTED)) { + + float vec[3]; + sub_v3_v3v3(vec, cebone->head, pebone->head); + + /* + * It is possible that the child's head is located on the parents head. + * When this happens, then moving the parent's tail to the child's head + * would result in a zero sized bone and Blender would silently remove the bone. + * So we move the tail only when the resulting bone has a minimum length: + */ + + if (len_squared_v3(vec) > MINIMUM_BONE_LENGTH) + { + pebone->tail[0] = cebone->head[0]; + pebone->tail[1] = cebone->head[1]; + pebone->tail[2] = cebone->head[2]; + + if (pbe && pbe->get_chain_length() >= this->import_settings->min_chain_length) { + cebone->flag |= BONE_CONNECTED; + printf("Connecting chain: parent %s --> %s (child)\n", pebone->name, cebone->name); + pbe->set_leaf_bone(false); + } + } + } + for (Bone *child = (Bone *)parentbone->childbase.first; child; child = child->next) { + ArmatureImporter::connect_bone_chains(armature, child, UNLIMITED_CHAIN_MAX); + } + } + else if (maxlen>1 && maxlen > this->import_settings->min_chain_length) { + /* Try again with smaller chain length */ + ArmatureImporter::connect_bone_chains(armature, parentbone, maxlen - 1); } + else { + /* can't connect this Bone. Proceed with children ... */ + if (pbe) pbe->set_leaf_bone(true); + for (Bone *child = (Bone *)parentbone->childbase.first; child; child = child->next) { + ArmatureImporter::connect_bone_chains(armature, child, UNLIMITED_CHAIN_MAX); + } + } + } #if 0 @@ -351,21 +438,26 @@ void ArmatureImporter::create_armature_bones( ) continue; } + clear_extended_boneset(); + ED_armature_to_edit(armature); create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature); - //leaf bone tails are derived from the matrix, so no need of this. - fix_leaf_bones(); + /* exit armature edit mode to populate the Armature object */ + ED_armature_from_edit(armature); + ED_armature_edit_free(armature); + + /* and step back to edit mode to fix the leaf nodes */ + ED_armature_to_edit(armature); + + connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); + fix_leaf_bones(armature, (Bone *)armature->bonebase.first); // exit armature edit mode unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm; ED_armature_from_edit(armature); - - //This serves no purpose, as pose is automatically reset later, in BKE_where_is_bone() - //set_pose(ob_arm, *ri, NULL, NULL); - ED_armature_edit_free(armature); DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); } @@ -459,9 +551,11 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) } // enter armature edit mode - ED_armature_to_edit((bArmature *)ob_arm->data); + bArmature * armature = (bArmature *)ob_arm->data; + ED_armature_to_edit(armature); + + clear_extended_boneset(); - leaf_bones.clear(); totbone = 0; // bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row leaf_bone_length = FLT_MAX; @@ -480,20 +574,27 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) // since root_joints may contain joints for multiple controllers, we need to filter if (skin.uses_joint_or_descendant(*ri)) { - create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature *)ob_arm->data); + create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature); if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent()) skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]); } } - fix_leaf_bones(); + /* exit armature edit mode to populate the Armature object */ + ED_armature_from_edit(armature); + ED_armature_edit_free(armature); + + /* and step back to edit mode to fix the leaf nodes */ + ED_armature_to_edit(armature); + + connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); + fix_leaf_bones(armature, (Bone *)armature->bonebase.first); // exit armature edit mode - ED_armature_from_edit((bArmature *)ob_arm->data); - ED_armature_edit_free((bArmature *)ob_arm->data); + ED_armature_from_edit(armature); + ED_armature_edit_free(armature); DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); - } void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]) @@ -538,10 +639,11 @@ void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, con } - -// root - if this joint is the top joint in hierarchy, if a joint -// is a child of a node (not joint), root should be true since -// this is where we build armature bones from +/** + * root - if this joint is the top joint in hierarchy, if a joint + * is a child of a node (not joint), root should be true since + * this is where we build armature bones from + **/ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node, Object *parent) { root_joints.push_back(node); @@ -785,3 +887,71 @@ bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint) return found; } + + +/** + * BoneExtended is a helper class needed for the Bone chain finder + * See ArmatureImporter::fix_leaf_bones() + * and ArmatureImporter::connect_bone_chains() + **/ + +BoneExtended::BoneExtended(EditBone *aBone) +{ + this->set_name(aBone->name); + this->chain_length = 0; + this->is_leaf = false; +} + +char *BoneExtended::get_name() +{ + return name; +} + +void BoneExtended::set_name(char *aName) +{ + BLI_strncpy(name, aName, MAXBONENAME); +} + +int BoneExtended::get_chain_length() +{ + return chain_length; +} + +void BoneExtended::set_chain_length(const int aLength) +{ + chain_length = aLength; +} + + +void BoneExtended::set_leaf_bone(bool state) +{ + is_leaf = state; +} + +bool BoneExtended::is_leaf_bone() +{ + return is_leaf; +} + +BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node) +{ + + TagsMap::iterator etit; + ExtraTags *et = 0; + etit = uid_tags_map.find(node->getUniqueId().toAscii()); + if (etit != uid_tags_map.end()) { + float x, y, z; + + et = etit->second; + et->setData("tip_x", &x); + et->setData("tip_y", &y); + et->setData("tip_z", &z); + float vec[3] = { x, y, z }; + copy_v3_v3(bone->tail, bone->head); + add_v3_v3v3(bone->tail, bone->head, vec); + } + + BoneExtended *be = new BoneExtended(bone); + extended_bones[bone->name] = be; + return *be; +} diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index beeac85cc4d..732fda80ff1 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -54,23 +54,41 @@ extern "C" { #include "collada_internal.h" #include "collada_utils.h" +#include "ImportSettings.h" + +#define UNLIMITED_CHAIN_MAX INT_MAX +#define MINIMUM_BONE_LENGTH 0.000001f + +class BoneExtended { + +private: + char name[MAXBONENAME]; + int chain_length; + bool is_leaf; + +public: + + BoneExtended(EditBone *aBone); + char *get_name(); + int get_chain_length(); + + void set_name(char *aName); + void set_chain_length(const int aLength); + void set_leaf_bone(bool state); + bool is_leaf_bone(); +}; class ArmatureImporter : private TransformReader { private: Scene *scene; UnitConverter *unit_converter; + const ImportSettings *import_settings; // std::map<int, JointData> joint_index_to_joint_info_map; // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map; - struct LeafBone { - // COLLADAFW::Node *node; - EditBone *bone; - char name[32]; - float mat[4][4]; // bone matrix, derived from inv_bind_mat - }; - std::vector<LeafBone> leaf_bones; + std::map<std::string, BoneExtended *> extended_bones; // int bone_direction_row; // XXX not used float leaf_bone_length; int totbone; @@ -106,13 +124,15 @@ private: JointData *get_joint_data(COLLADAFW::Node *node); #endif - void create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild, + int create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild, float parent_mat[4][4], bArmature *arm); - void add_leaf_bone(float mat[4][4], EditBone *bone, COLLADAFW::Node * node); + BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node); + void clear_extended_boneset(); + + void fix_leaf_bones(bArmature *armature, Bone *bone); + void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length); - void fix_leaf_bones(); - void set_pose( Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]); @@ -137,7 +157,7 @@ private: TagsMap uid_tags_map; public: - ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce); + ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings); ~ArmatureImporter(); void add_root_joint(COLLADAFW::Node *node, Object *parent); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 8101e579098..20ef45b6b71 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -104,7 +104,7 @@ DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_set import_settings(import_settings), mImportStage(General), mContext(C), - armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C)), + armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), import_settings), mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C)), anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) { diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp index 7ac138ac807..854e8abd76d 100644 --- a/source/blender/collada/ErrorHandler.cpp +++ b/source/blender/collada/ErrorHandler.cpp @@ -47,7 +47,7 @@ ErrorHandler::~ErrorHandler() //-------------------------------------------------------------------- bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error) { - mError = true; + bool isError = true; if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) { COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error; @@ -56,14 +56,14 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error) // Workaround to avoid wrong error if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_MIN_OCCURS_UNMATCHED) { if (strcmp(parserError.getElement(), "effect") == 0) { - mError = false; + isError = false; } } if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) { if (!((strcmp(parserError.getElement(), "extra") == 0) && (strcmp(parserError.getAdditionalText().c_str(), "sibling: fx_profile_abstract") == 0))) { - mError = false; + isError = false; } } @@ -75,11 +75,21 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error) } else if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXFWL) { COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error; + /* + * Accept non critical errors as warnings (i.e. texture not found) + * This makes the importer more gracefull, so it now imports what makes sense. + */ + if (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL) { + isError = false; + } + std::cout << "Sax FWL Error: " << saxFWLError->getErrorMessage() << std::endl; } else { std::cout << "opencollada error: " << error->getFullErrorMessage() << std::endl; } - return false; + mError |= isError; + + return false; // let OpenCollada decide when to abort } diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index 55fe2034869..5fd5fab3492 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -67,7 +67,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) return; } - bool is_dirty = imbuf->userflags & IB_BITMAPDIRTY; + bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0; ImageFormatData imageFormat; BKE_imbuf_to_image_format(&imageFormat, imbuf); diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h index 3f3a9fb354e..51a13da7724 100644 --- a/source/blender/collada/ImportSettings.h +++ b/source/blender/collada/ImportSettings.h @@ -32,7 +32,9 @@ struct ImportSettings { public: bool import_units; - + bool find_chains; + bool fix_orientation; + int min_chain_length; char *filepath; }; diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index 75928f9d189..71875d6274a 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -38,13 +38,16 @@ #include "BLI_math.h" #include "BLI_compiler_attrs.h" -#include "BKE_object.h" #include "DNA_armature_types.h" #include "DNA_modifier_types.h" #include "DNA_scene_types.h" + +#include "BKE_action.h" +#include "BKE_object.h" +#include "BKE_object_deform.h" + #include "ED_mesh.h" #include "ED_object.h" -#include "BKE_action.h" #include "SkinInfo.h" #include "collada_utils.h" @@ -263,7 +266,7 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]); } - ED_vgroup_add_name(ob, (char *)name); + BKE_object_defgroup_add_name(ob, name); } // <vcount> - number of joints per vertex - joints_per_vertex diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index 595787b44ac..e205608a365 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -102,7 +102,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B double d_obmat[4][4]; float f_obmat[4][4]; - /* Export the local Matrix (relative to the object parent) */ + /* Export the local Matrix (relative to the object parent, be it an object, bone or vertex(-tices)) */ BKE_object_matrix_local_get(ob, f_obmat); converter.mat4_to_dae_double(d_obmat, f_obmat); diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index ffbbb8623ac..f1d5f1a208a 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -44,13 +44,18 @@ extern "C" int collada_import(bContext *C, const char *filepath, - int import_units) + int import_units, + int find_chains, + int fix_orientation, + int min_chain_length) { ImportSettings import_settings; - import_settings.filepath = (char *)filepath; - - import_settings.import_units = import_units != 0; + import_settings.filepath = (char *)filepath; + import_settings.import_units = import_units != 0; + import_settings.find_chains = find_chains != 0; + import_settings.fix_orientation = fix_orientation != 0; + import_settings.min_chain_length = min_chain_length; DocumentImporter imp(C, &import_settings); if (imp.import()) return 1; diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 524c704cdee..6819a62fdf0 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -55,7 +55,10 @@ struct Scene; */ int collada_import(struct bContext *C, const char *filepath, - int import_units); + int import_units, + int find_chains, + int fix_orientation, + int min_chain_length); int collada_export(struct Scene *sce, const char *filepath, diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h index a398ae937a3..3fbafa0a029 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.h +++ b/source/blender/compositor/intern/COM_CompositorContext.h @@ -185,7 +185,7 @@ public: void setFastCalculation(bool fastCalculation) {this->m_fastCalculation = fastCalculation;} bool isFastCalculation() const { return this->m_fastCalculation; } - bool isGroupnodeBufferEnabled() const { return this->getbNodeTree()->flag & NTREE_COM_GROUPNODE_BUFFER; } + bool isGroupnodeBufferEnabled() const { return (this->getbNodeTree()->flag & NTREE_COM_GROUPNODE_BUFFER) != 0; } }; diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp index 470f8fd2ef7..af693ea9149 100644 --- a/source/blender/compositor/intern/COM_Debug.cpp +++ b/source/blender/compositor/intern/COM_Debug.cpp @@ -398,7 +398,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system) char filename[FILE_MAX]; BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index); - BLI_join_dirfile(filename, sizeof(filename), BLI_temp_dir_session(), basename); + BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename); ++m_file_index; FILE *fp = BLI_fopen(filename, "wb"); diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp index 2dcf419d81b..c5096a6b352 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cpp +++ b/source/blender/compositor/intern/COM_NodeGraph.cpp @@ -179,6 +179,8 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink /// @note: ignore invalid links if (!(b_nodelink->flag & NODE_LINK_VALID)) return; + if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL)) + return; /* Note: a DNA input socket can have multiple NodeInput in the compositor tree! (proxies) * The output then gets linked to each one of them. diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp index 3d79eb693ea..933b8d0282b 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.cpp +++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp @@ -34,7 +34,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi bNode *editorNode = this->getbNode(); bool is_active = (editorNode->flag & NODE_DO_OUTPUT_RECALC) || context.isRendering(); - bool ignore_alpha = editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA; + bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0; NodeInput *imageSocket = this->getInputSocket(0); NodeInput *alphaSocket = this->getInputSocket(1); diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cpp index b12dfc02ed7..89010d0e861 100644 --- a/source/blender/compositor/nodes/COM_MixNode.cpp +++ b/source/blender/compositor/nodes/COM_MixNode.cpp @@ -41,8 +41,8 @@ void MixNode::convertToOperations(NodeConverter &converter, const CompositorCont NodeInput *color2Socket = this->getInputSocket(2); NodeOutput *outputSocket = this->getOutputSocket(0); bNode *editorNode = this->getbNode(); - bool useAlphaPremultiply = this->getbNode()->custom2 & 1; - bool useClamp = this->getbNode()->custom2 & 2; + bool useAlphaPremultiply = (this->getbNode()->custom2 & 1) != 0; + bool useClamp = (this->getbNode()->custom2 & 2) != 0; MixBaseOperation *convertProg; switch (editorNode->custom1) { diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cpp index 07aa960c4d9..ff0b8fb1706 100644 --- a/source/blender/compositor/nodes/COM_ViewerNode.cpp +++ b/source/blender/compositor/nodes/COM_ViewerNode.cpp @@ -35,7 +35,7 @@ void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorC { bNode *editorNode = this->getbNode(); bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) && (editorNode->flag & NODE_DO_OUTPUT); - bool ignore_alpha = editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA; + bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0; NodeInput *imageSocket = this->getInputSocket(0); NodeInput *alphaSocket = this->getInputSocket(1); diff --git a/source/blender/compositor/operations/COM_OpenCLKernels.cl b/source/blender/compositor/operations/COM_OpenCLKernels.cl index 1b965eb8659..cbd05cbec17 100644 --- a/source/blender/compositor/operations/COM_OpenCLKernels.cl +++ b/source/blender/compositor/operations/COM_OpenCLKernels.cl @@ -80,10 +80,10 @@ __kernel void bokehBlurKernel(__read_only image2d_t boundingBox, __read_only ima } //KERNEL --- DEFOCUS /VARIABLESIZEBOKEHBLUR --- -__kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2d_t bokehImage, - __read_only image2d_t inputSize, - __write_only image2d_t output, int2 offsetInput, int2 offsetOutput, - int step, int maxBlurScalar, float threshold, float scalar, int2 dimension, int2 offset) +__kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2d_t bokehImage, + __read_only image2d_t inputSize, + __write_only image2d_t output, int2 offsetInput, int2 offsetOutput, + int step, int maxBlurScalar, float threshold, float scalar, int2 dimension, int2 offset) { float4 color = {1.0f, 0.0f, 0.0f, 1.0f}; int2 coords = {get_global_id(0), get_global_id(1)}; @@ -212,8 +212,8 @@ __kernel void erodeKernel(__read_only image2d_t inputImage, __write_only image2 // KERNEL --- DIRECTIONAL BLUR --- __kernel void directionalBlurKernel(__read_only image2d_t inputImage, __write_only image2d_t output, - int2 offsetOutput, int iterations, float scale, float rotation, float2 translate, - float2 center, int2 offset) + int2 offsetOutput, int iterations, float scale, float rotation, float2 translate, + float2 center, int2 offset) { int2 coords = {get_global_id(0), get_global_id(1)}; coords += offset; diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp index bcef652a8b5..12b04c386f2 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp @@ -50,34 +50,52 @@ void SunBeamsOperation::initExecution() * For a target point (x,y) the sector should be chosen such that * ``u >= v >= 0`` * This removes the need to handle all sorts of special cases. + * + * Template parameters: + * fxu : buffer increment in x for sector u+1 + * fxv : buffer increment in x for sector v+1 + * fyu : buffer increment in y for sector u+1 + * fyv : buffer increment in y for sector v+1 */ -template <int fxx, int fxy, int fyx, int fyy> +template <int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator { /* utility functions implementing the matrix transform to/from sector space */ - - static inline void buffer_to_sector(int x, int y, int &u, int &v) + + static inline void buffer_to_sector(const float source[2], int x, int y, int &u, int &v) { - u = x * fxx + y * fyx; - v = x * fxy + y * fyy; + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x -= x0; + y -= y0; + u = x * fxu + y * fyu; + v = x * fxv + y * fyv; } - static inline void buffer_to_sector(float x, float y, float &u, float &v) + static inline void buffer_to_sector(const float source[2], float x, float y, float &u, float &v) { - u = x * fxx + y * fyx; - v = x * fxy + y * fyy; + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x -= (float)x0; + y -= (float)y0; + u = x * fxu + y * fyu; + v = x * fxv + y * fyv; } - static inline void sector_to_buffer(int u, int v, int &x, int &y) + static inline void sector_to_buffer(const float source[2], int u, int v, int &x, int &y) { - x = u * fxx + v * fxy; - y = u * fyx + v * fyy; + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x = x0 + u * fxu + v * fxv; + y = y0 + u * fyu + v * fyv; } - static inline void sector_to_buffer(float u, float v, float &x, float &y) + static inline void sector_to_buffer(const float source[2], float u, float v, float &x, float &y) { - x = u * fxx + v * fxy; - y = u * fyx + v * fyy; + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x = (float)x0 + u * fxu + v * fxv; + y = (float)y0 + u * fyu + v * fyv; } /** @@ -91,12 +109,12 @@ struct BufferLineAccumulator { * \param num Total steps in the loop * \param v, dv Vertical offset in sector space, for line offset perpendicular to the loop axis */ - static float *init_buffer_iterator(MemoryBuffer *input, const float source[2], const float pt_ofs[2], + static float *init_buffer_iterator(MemoryBuffer *input, const float source[2], const float co[2], float dist_min, float dist_max, int &x, int &y, int &num, float &v, float &dv, float &falloff_factor) { float pu, pv; - buffer_to_sector(pt_ofs[0], pt_ofs[1], pu, pv); + buffer_to_sector(source, co[0], co[1], pu, pv); /* line angle */ float tan_phi = pv / pu; @@ -113,9 +131,7 @@ struct BufferLineAccumulator { int end = (int)ceilf(umin); num = end - start; - sector_to_buffer(end, (int)ceilf(v), x, y); - x += (int)source[0]; - y += (int)source[1]; + sector_to_buffer(source, end, (int)ceilf(v), x, y); falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f; @@ -130,7 +146,7 @@ struct BufferLineAccumulator { * The loop runs backwards(!) over the primary sector space axis u, i.e. increasing distance to pt. * After each step it decrements v by dv < 1, adding a buffer shift when necessary. */ - static void eval(MemoryBuffer *input, float output[4], const float pt_ofs[2], const float source[2], + static void eval(MemoryBuffer *input, float output[4], const float co[2], const float source[2], float dist_min, float dist_max) { rcti rect = *input->getRect(); @@ -139,14 +155,16 @@ struct BufferLineAccumulator { float v, dv; float falloff_factor; float border[4]; - - if ((int)pt_ofs[0] == 0 && (int)pt_ofs[1] == 0) { + + zero_v4(output); + + if ((int)(co[0] - source[0]) == 0 && (int)(co[1] - source[1]) == 0) { copy_v4_v4(output, input->getBuffer() + COM_NUMBER_OF_CHANNELS * ((int)source[0] + input->getWidth() * (int)source[1])); return; } /* initialise the iteration variables */ - float *buffer = init_buffer_iterator(input, source, pt_ofs, dist_min, dist_max, x, y, num, v, dv, falloff_factor); + float *buffer = init_buffer_iterator(input, source, co, dist_min, dist_max, x, y, num, v, dv, falloff_factor); zero_v3(border); border[3] = 1.0f; @@ -178,18 +196,18 @@ struct BufferLineAccumulator { */ /* decrement u */ - x -= fxx; - y -= fyx; - buffer -= (fxx + fyx * buffer_width) * COM_NUMBER_OF_CHANNELS; + x -= fxu; + y -= fyu; + buffer -= (fxu + fyu * buffer_width) * COM_NUMBER_OF_CHANNELS; /* decrement v (in steps of dv < 1) */ v_local -= dv; if (v_local < 0.0f) { v_local += 1.0f; - x -= fxy; - y -= fyy; - buffer -= (fxy + fyy * buffer_width) * COM_NUMBER_OF_CHANNELS; + x -= fxv; + y -= fyv; + buffer -= (fxv + fyv * buffer_width) * COM_NUMBER_OF_CHANNELS; } } @@ -233,21 +251,21 @@ static void accumulate_line(MemoryBuffer *input, float output[4], const float co if (pt_ofs[0] > 0.0f) { if (pt_ofs[1] > 0.0f) { /* 2 */ - BufferLineAccumulator<0, 1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator<0, 1, 1, 0>::eval(input, output, co, source, dist_min, dist_max); } else { /* 7 */ - BufferLineAccumulator<0, 1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator<0, 1, -1, 0>::eval(input, output, co, source, dist_min, dist_max); } } else { if (pt_ofs[1] > 0.0f) { /* 3 */ - BufferLineAccumulator<0, -1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator<0, -1, 1, 0>::eval(input, output, co, source, dist_min, dist_max); } else { /* 6 */ - BufferLineAccumulator<0, -1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator<0, -1, -1, 0>::eval(input, output, co, source, dist_min, dist_max); } } } @@ -255,21 +273,21 @@ static void accumulate_line(MemoryBuffer *input, float output[4], const float co if (pt_ofs[0] > 0.0f) { if (pt_ofs[1] > 0.0f) { /* 1 */ - BufferLineAccumulator< 1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator< 1, 0, 0, 1>::eval(input, output, co, source, dist_min, dist_max); } else { /* 8 */ - BufferLineAccumulator< 1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator< 1, 0, 0, -1>::eval(input, output, co, source, dist_min, dist_max); } } else { if (pt_ofs[1] > 0.0f) { /* 4 */ - BufferLineAccumulator<-1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator<-1, 0, 0, 1>::eval(input, output, co, source, dist_min, dist_max); } else { /* 5 */ - BufferLineAccumulator<-1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + BufferLineAccumulator<-1, 0, 0, -1>::eval(input, output, co, source, dist_min, dist_max); } } } diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c index 7df9269a4a8..92048f32a28 100644 --- a/source/blender/datatoc/datatoc_icon.c +++ b/source/blender/datatoc/datatoc_icon.c @@ -166,7 +166,8 @@ static bool write_png(const char *name, const unsigned int *pixels, /* set the individual row-pointers to point at the correct offsets */ for (i = 0; i < height; i++) { row_pointers[height - 1 - i] = (png_bytep) - (((unsigned char *)pixels) + (i * width) * bytesperpixel * sizeof(unsigned char)); + (((const unsigned char *)pixels) + + (i * width) * bytesperpixel * sizeof(unsigned char)); } /* write out the entire image data in one call */ diff --git a/source/blender/datatoc/datatoc_icon.py b/source/blender/datatoc/datatoc_icon.py index 930d588f859..16092431195 100755 --- a/source/blender/datatoc/datatoc_icon.py +++ b/source/blender/datatoc/datatoc_icon.py @@ -113,6 +113,17 @@ def icondir_to_png(path_src, file_dst): files = [os.path.join(path_src, f) for f in os.listdir(path_src) if f.endswith(".dat")] + # First check if we need to bother. + if os.path.exists(file_dst): + dst_time = os.path.getmtime(file_dst) + has_newer = False + for f in files: + if os.path.getmtime(f) > dst_time: + has_newer = True + break + if not has_newer: + return + with open(files[0], 'rb') as f_src: (icon_w, icon_h, orig_x, orig_y, diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index f384b2f372c..d76eba93640 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -2365,6 +2365,83 @@ static bAnimChannelType ACF_DSSPK = acf_dsspk_setting_ptr /* pointer for setting */ }; +/* GPencil Expander ------------------------------------------- */ + +// TODO: just get this from RNA? +static int acf_dsgpencil_icon(bAnimListElem *UNUSED(ale)) +{ + return ICON_GREASEPENCIL; +} + +/* get the appropriate flag(s) for the setting when it is valid */ +static int acf_dsgpencil_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +{ + /* clear extra return data first */ + *neg = false; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GP_DATA_EXPAND; + + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; + + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; + + default: /* unsupported */ + return 0; + } +} + +/* get pointer to the setting */ +static void *acf_dsgpencil_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +{ + bGPdata *gpd = (bGPdata *)ale->data; + + /* clear extra return data first */ + *type = 0; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(gpd->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 (gpd->adt) + return GET_ACF_FLAG_PTR(gpd->adt->flag, type); + return NULL; + + default: /* unsupported */ + return NULL; + } +} + +/* grease pencil expander type define */ +static bAnimChannelType ACF_DSGPENCIL = +{ + "GPencil DS Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_generic_dataexpand_color, /* backdrop color */ + acf_generic_dataexpand_backdrop, /* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_basic_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_generic_idblock_name_prop, /* name prop */ + acf_dsgpencil_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsgpencil_setting_flag, /* flag for setting */ + acf_dsgpencil_setting_ptr /* pointer for setting */ +}; + /* ShapeKey Entry ------------------------------------------- */ /* name for ShapeKey */ @@ -3162,6 +3239,7 @@ static void ANIM_init_channel_typeinfo_data(void) animchannelTypeInfo[type++] = &ACF_DSLAT; /* Lattice Channel */ animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */ animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */ + animchannelTypeInfo[type++] = &ACF_DSGPENCIL; /* GreasePencil Channel */ animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */ @@ -3407,6 +3485,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float /* step 4) draw special toggles ................................. * - in Graph Editor, checkboxes for visibility in curves area * - in NLA Editor, glowing dots for solo/not solo... + * - in Grease Pencil mode, color swatches for layer color */ if (ac->sl) { if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { @@ -3431,6 +3510,10 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float /* just skip - drawn as widget now */ offset += ICON_WIDTH; } + else if (ale->type == ANIMTYPE_GPLAYER) { + /* just skip - drawn as a widget */ + offset += ICON_WIDTH; + } } /* step 5) draw name ............................................... */ @@ -3601,18 +3684,6 @@ static void achannel_nlatrack_solo_widget_cb(bContext *C, void *adt_poin, void * WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL); } -/* callback for rename widgets - clear rename-in-progress */ -static void achannel_setting_rename_done_cb(bContext *C, void *ads_poin, void *UNUSED(arg2)) -{ - bDopeSheet *ads = (bDopeSheet *)ads_poin; - - /* reset rename index so that edit box disappears now that editing is done */ - ads->renameIndex = 0; - - /* send notifiers */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL); -} - /* callback for widget sliders - insert keyframes */ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poin) { @@ -3838,7 +3909,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann } /* Draw UI widgets the given channel */ -void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index) +void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index) { bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); View2D *v2d = &ac->ar->v2d; @@ -3878,6 +3949,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale /* step 3) draw special toggles ................................. * - in Graph Editor, checkboxes for visibility in curves area * - in NLA Editor, glowing dots for solo/not solo... + * - in Grease Pencil mode, color swatches for layer color */ if (ac->sl) { if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { @@ -3890,6 +3962,31 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO); offset += ICON_WIDTH; } + else if (ale->type == ANIMTYPE_GPLAYER) { + /* color swatch for layer color */ + bGPDlayer *gpl = (bGPDlayer *)ale->data; + PointerRNA ptr; + float w = ICON_WIDTH / 2.0f; + + RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr); + + UI_block_align_begin(block); + + UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); + uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset, yminc, w, ICON_WIDTH, + &ptr, "color", -1, + 0, 0, 0, 0, gpl->info); + + UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_fill_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); + uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset + w, yminc, w, ICON_WIDTH, + &ptr, "fill_color", -1, + 0, 0, 0, 0, gpl->info); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_align_end(block); + + offset += ICON_WIDTH; + } } /* step 4) draw text - check if renaming widget is in use... */ @@ -3912,8 +4009,14 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height, &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL); - UI_but_func_set(but, achannel_setting_rename_done_cb, ac->ads, NULL); - UI_but_active_only(C, ac->ar, block, but); + + /* copy what outliner does here, see outliner_buttons */ + if (UI_but_active_only(C, ac->ar, block, but) == false) { + ac->ads->renameIndex = 0; + + /* send notifiers */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL); + } UI_block_emboss_set(block, UI_EMBOSS_NONE); } diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index b6ab0407711..d8ad6506186 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -129,6 +129,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat case ANIMTYPE_DSLAT: case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: { /* need to verify that this data is valid for now */ if (ale->adt) { @@ -136,6 +137,13 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat } break; } + case ANIMTYPE_GPLAYER: + { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + + ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE); + break; + } } } @@ -176,6 +184,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat case ANIMTYPE_DSSPK: case ANIMTYPE_DSNTREE: case ANIMTYPE_DSTEX: + case ANIMTYPE_DSGPENCIL: { /* need to verify that this data is valid for now */ if (ale && ale->adt) { @@ -184,8 +193,14 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat break; } - /* unhandled currently, but may be interesting */ case ANIMTYPE_GPLAYER: + { + bGPDlayer *gpl = (bGPDlayer *)channel_data; + gpl->flag |= GP_LAYER_ACTIVE; + break; + } + + /* unhandled currently, but may be interesting */ case ANIMTYPE_MASKLAYER: case ANIMTYPE_SHAPEKEY: case ANIMTYPE_NLAACTION: @@ -268,6 +283,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d case ANIMTYPE_DSLAT: case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: { if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) sel = ACHANNEL_SETFLAG_CLEAR; @@ -361,6 +377,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d case ANIMTYPE_DSLAT: case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: { /* need to verify that this data is valid for now */ if (ale->adt) { @@ -843,6 +860,13 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr is_sel = SEL_NLT(nlt); break; } + case ANIMTYPE_GPLAYER: + { + bGPDlayer *gpl = (bGPDlayer *)channel; + + is_sel = SEL_GPL(gpl); + break; + } default: printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type); return; @@ -1167,6 +1191,47 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange /* ------------------- */ +static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get rearranging function */ + AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); + + if (rearrange_func == NULL) + return; + + /* get Grease Pencil datablocks */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + ListBase anim_data_visible = {NULL, NULL}; + bGPdata *gpd = ale->data; + + /* only consider layers if this datablock is open */ + BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK); + if ((gpd->flag & GP_DATA_EXPAND) == 0) + continue; + + /* Filter visible data. */ + rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER); + + /* rearrange datablock's layers */ + rearrange_animchannel_islands(&gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible); + + /* free visible layers data */ + BLI_freelistN(&anim_data_visible); + } + + /* free GPD channel data */ + ANIM_animdata_freelist(&anim_data); +} + +/* ------------------- */ + static int animchannels_rearrange_exec(bContext *C, wmOperator *op) { bAnimContext ac; @@ -1182,7 +1247,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op) /* method to move channels depends on the editor */ if (ac.datatype == ANIMCONT_GPENCIL) { /* Grease Pencil channels */ - printf("Grease Pencil not supported for moving yet\n"); + rearrange_gpencil_channels(&ac, mode); } else if (ac.datatype == ANIMCONT_MASK) { /* Grease Pencil channels */ @@ -1585,175 +1650,6 @@ static void ANIM_OT_channels_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Set Channel Visibility Operator *********************** */ -/* NOTE: this operator is only valid in the Graph Editor channels region */ - -static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - ListBase all_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* get list of all channels that selection may need to be flushed to - * - hierarchy mustn't affect what we have access to here... - */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype); - - /* hide all channels not selected - * - hierarchy matters if we're doing this from the channels region - * since we only want to apply this to channels we can "see", - * and have these affect their relatives - * - but for Graph Editor, this gets used also from main region - * where hierarchy doesn't apply, as for [#21276] - */ - if ((ac.spacetype == SPACE_IPO) && (ac.regiontype != RGN_TYPE_CHANNELS)) { - /* graph editor (case 2) */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); - } - else { - /* standard case */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS); - } - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - for (ale = anim_data.first; ale; ale = ale->next) { - /* clear setting first */ - ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR); - - /* now also flush selection status as appropriate - * NOTE: in some cases, this may result in repeat flushing being performed - */ - ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0); - } - - ANIM_animdata_freelist(&anim_data); - - /* make all the selected channels visible */ - filter = (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - for (ale = anim_data.first; ale; ale = ale->next) { - /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ - /* TODO: find out why this is the case, and fix that */ - if (ale->type == ANIMTYPE_OBJECT) - continue; - - /* enable the setting */ - ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD); - - /* now, also flush selection status up/down as appropriate */ - ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1); - } - - ANIM_animdata_freelist(&anim_data); - BLI_freelistN(&all_data); - - - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -static void ANIM_OT_channels_visibility_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Visibility"; - ot->idname = "ANIM_OT_channels_visibility_set"; - ot->description = "Make only the selected animation channels visible in the Graph Editor"; - - /* api callbacks */ - ot->exec = animchannels_visibility_set_exec; - ot->poll = ED_operator_graphedit_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -/* ******************** Toggle Channel Visibility Operator *********************** */ -/* NOTE: this operator is only valid in the Graph Editor channels region */ - -static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - ListBase all_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - short vis = ACHANNEL_SETFLAG_ADD; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* get list of all channels that selection may need to be flushed to - * - hierarchy mustn't affect what we have access to here... - */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype); - - /* filter data - * - restrict this to only applying on settings we can get to in the list - */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - /* See if we should be making showing all selected or hiding */ - for (ale = anim_data.first; ale; ale = ale->next) { - /* set the setting in the appropriate way (if available) */ - if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) { - vis = ACHANNEL_SETFLAG_CLEAR; - break; - } - } - - /* Now set the flags */ - for (ale = anim_data.first; ale; ale = ale->next) { - /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ - /* TODO: find out why this is the case, and fix that */ - if (ale->type == ANIMTYPE_OBJECT) - continue; - - /* change the setting */ - ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis); - - /* now, also flush selection status up/down as appropriate */ - ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD)); - } - - /* cleanup */ - ANIM_animdata_freelist(&anim_data); - BLI_freelistN(&all_data); - - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -static void ANIM_OT_channels_visibility_toggle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Toggle Visibility"; - ot->idname = "ANIM_OT_channels_visibility_toggle"; - ot->description = "Toggle visibility in Graph Editor of all selected animation channels"; - - /* api callbacks */ - ot->exec = animchannels_visibility_toggle_exec; - ot->poll = ED_operator_graphedit_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - /* ********************** Set Flags Operator *********************** */ /* defines for setting animation-channel flags */ @@ -2334,7 +2230,7 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op) /* 'standard' behavior - check if selected, then apply relevant selection */ if (RNA_boolean_get(op->ptr, "invert")) - ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_TOGGLE); + ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT); else ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD); @@ -2736,6 +2632,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, case ANIMTYPE_DSLAT: case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: { /* sanity checking... */ if (ale->adt) { @@ -2897,7 +2794,13 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, gpl->flag |= GP_LAYER_SELECT; } - notifierFlags |= (ND_ANIMCHAN | NA_EDITED); + /* change active layer, if this is selected (since we must always have an active layer) */ + if (gpl->flag & GP_LAYER_SELECT) { + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER); + } + + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* Grease Pencil updates */ + notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Ediotrs updates */ break; } case ANIMTYPE_MASKDATABLOCK: @@ -3042,9 +2945,6 @@ void ED_operatortypes_animchannels(void) WM_operatortype_append(ANIM_OT_channels_expand); WM_operatortype_append(ANIM_OT_channels_collapse); - WM_operatortype_append(ANIM_OT_channels_visibility_toggle); - WM_operatortype_append(ANIM_OT_channels_visibility_set); - WM_operatortype_append(ANIM_OT_channels_fcurves_enable); WM_operatortype_append(ANIM_OT_channels_clean_empty); @@ -3110,10 +3010,6 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf) /* grouping */ WM_keymap_add_item(keymap, "ANIM_OT_channels_group", GKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "ANIM_OT_channels_ungroup", GKEY, KM_PRESS, KM_ALT, 0); - - /* Graph Editor only */ - WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0); } /* ************************************************************************** */ diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index f3b47b168e9..eb57907c9ec 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -92,7 +92,7 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale) RNA_property_update_main(G.main, scene, &ptr, prop); } else { - /* in other case we do standard depsgaph update, ideally + /* in other case we do standard depsgraph update, ideally * we'd be calling property update functions here too ... */ DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive? } diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 807e1322595..2d7656642d3 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -41,7 +41,6 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_nla.h" -#include "BKE_object.h" #include "ED_anim_api.h" #include "ED_keyframes_edit.h" diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index cedaea716e3..d6daa64a9f2 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -771,6 +771,21 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne ale->adt = BKE_animdata_from_id(data); break; } + case ANIMTYPE_DSGPENCIL: + { + bGPdata *gpd = (bGPdata *)data; + AnimData *adt = gpd->adt; + + /* NOTE: we just reuse the same expand filter for this case */ + ale->flag = EXPANDED_GPD(gpd); + + // XXX: currently, this is only used for access to its animation data + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } case ANIMTYPE_GROUP: { bActionGroup *agrp = (bActionGroup *)data; @@ -1413,27 +1428,77 @@ static size_t animdata_filter_gpencil(ListBase *anim_data, void *UNUSED(data), i /* only show if gpd is used by something... */ if (ID_REAL_USERS(gpd) < 1) continue; + + /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation), + * for convenience, this will return GP Datablocks instead. This may cause issues down + * the track, but for now, this will do... + */ + if (filter_mode & ANIMFILTER_ANIMDATA) { + /* just add GPD as a channel - this will add everything needed */ + ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL); + } + else { + /* add gpencil animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) + { + tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; - /* add gpencil animation channels */ - BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) - { - tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode); + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* add gpd as channel too (if for drawing, and it has layers) */ + ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL); + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } } - END_ANIMFILTER_SUBCHANNELS; + } + + /* return the number of items added to the list */ + return items; +} + +/* Helper for Grease Pencil data integrated with main DopeSheet */ +static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode) +{ + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add relevant animation channels for Grease Pencil */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) + { + /* add animation channels */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode); - /* did we find anything? */ - if (tmp_items) { - /* include data-expand widget first */ - if (filter_mode & ANIMFILTER_LIST_CHANNELS) { - /* add gpd as channel too (if for drawing, and it has layers) */ - ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL); + /* add Grease Pencil layers */ + // TODO: do these need a separate expander? + // XXX: what order should these go in? + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by active status */ + // XXX: active check here needs checking + if (ANIMCHANNEL_ACTIVEOK(gpd)) { + ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_DSGPENCIL, gpd); } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; } /* return the number of items added to the list */ @@ -1699,6 +1764,12 @@ static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data, mtex = (MTex **)(&wo->mtex); break; } + case ID_PA: + { + ParticleSettings *part = (ParticleSettings *)owner_id; + mtex = (MTex **)(&part->mtex); + break; + } default: { /* invalid/unsupported option */ @@ -1910,8 +1981,12 @@ static size_t animdata_filter_ds_particles(bAnimContext *ac, ListBase *anim_data /* add particle-system's animation data to temp collection */ BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part)) { - /* material's animation data */ + /* particle system's animation data */ tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode); + + /* textures */ + if (!(ads->filterflag & ADS_FILTER_NOTEX)) + tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)psys->part, filter_mode); } END_ANIMFILTER_SUBCHANNELS; @@ -2215,6 +2290,11 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) { tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode); } + + /* grease pencil */ + if ((ob->gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { + tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->gpd, filter_mode); + } } END_ANIMFILTER_SUBCHANNELS; @@ -2257,7 +2337,7 @@ static size_t animdata_filter_ds_world(bAnimContext *ac, ListBase *anim_data, bD /* textures for world */ if (!(ads->filterflag & ADS_FILTER_NOTEX)) - items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode); + tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode); /* nodes */ if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) @@ -2349,6 +2429,7 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_SCEC(sce)) { bNodeTree *ntree = sce->nodetree; + bGPdata *gpd = sce->gpd; World *wo = sce->world; /* Action, Drivers, or NLA for Scene */ @@ -2371,6 +2452,11 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode); } + /* grease pencil */ + if ((gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { + tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, gpd, filter_mode); + } + /* TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here */ } END_ANIMFILTER_SUBCHANNELS; diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 0f202003dd8..cbcbc8743f1 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -41,6 +41,7 @@ #include "DNA_scene_types.h" #include "BKE_context.h" +#include "BKE_sequencer.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_sound.h" @@ -55,6 +56,7 @@ #include "ED_anim_api.h" #include "ED_screen.h" +#include "ED_sequencer.h" #include "anim_intern.h" @@ -92,9 +94,15 @@ static void change_frame_apply(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - + int frame = RNA_int_get(op->ptr, "frame"); + bool do_snap = RNA_boolean_get(op->ptr, "snap"); + + if (do_snap && CTX_wm_space_seq(C)) { + frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); + } + /* set the new frame number */ - CFRA = RNA_int_get(op->ptr, "frame"); + CFRA = frame; FRAMENUMBER_MIN_CLAMP(CFRA); SUBFRA = 0.0f; @@ -136,6 +144,25 @@ static int frame_from_event(bContext *C, const wmEvent *event) return frame; } +static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event) +{ + ScrArea *sa = CTX_wm_area(C); + if (sa && sa->spacetype == SPACE_SEQ) { + SpaceSeq *sseq = sa->spacedata.first; + if (ED_space_sequencer_check_show_strip(sseq)) { + ED_sequencer_special_preview_set(C, event->mval); + } + } +} +static void change_frame_seq_preview_end(bContext *C) +{ + if (ED_sequencer_special_preview_get() != NULL) { + Scene *scene = CTX_data_scene(C); + ED_sequencer_special_preview_clear(); + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); + } +} + /* Modal Operator init */ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -144,7 +171,9 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event * click-dragging over a range (modal scrubbing). */ RNA_int_set(op->ptr, "frame", frame_from_event(C, event)); - + + change_frame_seq_preview_begin(C, event); + change_frame_apply(C, op); /* add temp handler */ @@ -153,14 +182,21 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event return OPERATOR_RUNNING_MODAL; } +static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op)) +{ + change_frame_seq_preview_end(C); +} + /* Modal event handling of frame changing */ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event) { + int ret = OPERATOR_RUNNING_MODAL; /* execute the events */ switch (event->type) { case ESCKEY: - return OPERATOR_FINISHED; - + ret = OPERATOR_FINISHED; + break; + case MOUSEMOVE: RNA_int_set(op->ptr, "frame", frame_from_event(C, event)); change_frame_apply(C, op); @@ -173,15 +209,31 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event) * the modal op) doesn't work for some reason */ if (event->val == KM_RELEASE) - return OPERATOR_FINISHED; + ret = OPERATOR_FINISHED; + break; + + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + if (event->val == KM_RELEASE) { + RNA_boolean_set(op->ptr, "snap", false); + } + else if (event->val == KM_PRESS) { + RNA_boolean_set(op->ptr, "snap", true); + } break; } - return OPERATOR_RUNNING_MODAL; + if (ret != OPERATOR_RUNNING_MODAL) { + change_frame_seq_preview_end(C); + } + + return ret; } static void ANIM_OT_change_frame(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Change Frame"; ot->idname = "ANIM_OT_change_frame"; @@ -190,6 +242,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) /* api callbacks */ ot->exec = change_frame_exec; ot->invoke = change_frame_invoke; + ot->cancel = change_frame_cancel; ot->modal = change_frame_modal; ot->poll = change_frame_poll; @@ -198,6 +251,8 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) /* rna */ ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); + prop = RNA_def_boolean(ot->srna, "snap", false, "Snap", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ****************** set preview range operator ****************************/ diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 7bdc49da54e..5799101a7db 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -39,18 +39,12 @@ #include "BLI_utildefines.h" #include "DNA_anim_types.h" -#include "DNA_object_types.h" -#include "DNA_material_types.h" #include "DNA_texture_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" #include "BKE_animsys.h" #include "BKE_fcurve.h" #include "BKE_context.h" #include "BKE_report.h" -#include "BKE_material.h" -#include "BKE_texture.h" #include "ED_keyframing.h" diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index c5e54cc1c7c..d2dbe961b42 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -39,7 +39,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" #include "BLI_dlrbTree.h" #include "BLI_utildefines.h" @@ -155,6 +154,7 @@ static DLRBT_Node *nalloc_ak_gpframe(void *data) /* store settings based on state of BezTriple */ ak->cfra = gpf->framenum; ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0; + ak->key_type = gpf->key_type; /* set 'modified', since this is used to identify long keyframes */ ak->modified = 1; @@ -171,6 +171,10 @@ static void nupdate_ak_gpframe(void *node, void *data) /* set selection status and 'touched' status */ if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT; ak->modified += 1; + + /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */ + if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) + ak->key_type = BEZT_KEYTYPE_KEYFRAME; } /* ......... */ @@ -732,6 +736,21 @@ void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos) BLI_dlrbTree_free(&blocks); } +void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos) +{ + DLRBT_Tree keys; + + BLI_dlrbTree_init(&keys); + + gpencil_to_keylist(ads, gpd, &keys); + + BLI_dlrbTree_linkedlist_sync(&keys); + + draw_keylist(v2d, &keys, NULL, ypos, 0); + + BLI_dlrbTree_free(&keys); +} + void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos) { DLRBT_Tree keys; @@ -924,6 +943,20 @@ void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree } +void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys) +{ + bGPDlayer *gpl; + + if (gpd && keys) { + /* for now, just aggregate out all the frames, but only for visible layers */ + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if ((gpl->flag & GP_LAYER_HIDE) == 0) { + gpl_to_keylist(ads, gpl, keys); + } + } + } +} + void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys) { bGPDframe *gpf; diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 7f612de14b7..439b3b94974 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -41,9 +41,7 @@ #include "DNA_anim_types.h" #include "DNA_object_types.h" -#include "DNA_node_types.h" #include "DNA_scene_types.h" -#include "DNA_space_types.h" #include "BKE_fcurve.h" @@ -548,6 +546,44 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) return 0; } +/** + * only called from #ok_bezier_region_circle + */ +static bool bezier_region_circle_test( + const struct KeyframeEdit_CircleData *data_circle, + const float xy[2]) +{ + if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) { + float xy_view[2]; + + BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy); + + xy_view[0] = xy_view[0] - data_circle->mval[0]; + xy_view[1] = xy_view[1] - data_circle->mval[1]; + return len_squared_v2(xy_view) < data_circle->radius_squared; + } + + return false; +} + + +static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) +{ + /* rect is stored in data property (it's of type rectf, but may not be set) */ + if (ked->data) { + short ok = 0; + +#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index]) + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); +#undef KEY_CHECK_OK + + /* return ok flags */ + return ok; + } + else + return 0; +} + KeyframeEditFunc ANIM_editkeyframes_ok(short mode) { @@ -567,6 +603,8 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode) return ok_bezier_region; case BEZT_OK_REGION_LASSO: /* only if the point falls within KeyframeEdit_LassoData defined data */ return ok_bezier_region_lasso; + case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_LassoData defined data */ + return ok_bezier_region_circle; default: /* nothing was ok */ return NULL; } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 6e59bb9f463..7ac11c1cd06 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -43,13 +43,14 @@ #include "DNA_scene_types.h" +#include "BKE_action.h" #include "BKE_fcurve.h" #include "BKE_report.h" #include "BKE_library.h" #include "BKE_global.h" +#include "BKE_deform.h" #include "RNA_access.h" -#include "RNA_enum_types.h" #include "ED_anim_api.h" #include "ED_keyframing.h" @@ -478,6 +479,7 @@ typedef struct tAnimCopybufItem { BezTriple *bezt; /* keyframes in buffer */ short id_type; /* Result of GS(id->name)*/ + bool is_bone; /* special flag for armature bones */ } tAnimCopybufItem; @@ -541,6 +543,31 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data) aci->grp = fcu->grp; aci->rna_path = MEM_dupallocN(fcu->rna_path); aci->array_index = fcu->array_index; + + /* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo. + * storing the relevant information here helps avoiding crashes if we undo-repaste */ + if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) { + Object *ob = (Object *)aci->id; + char *str_start; + + if ((str_start = strstr(aci->rna_path, "pose.bones["))) { + bPoseChannel *pchan; + int length = 0; + char *str_end; + + str_start += 12; + str_end = strchr(str_start, '\"'); + length = str_end - str_start; + str_start[length] = 0; + pchan = BKE_pose_channel_find_name(ob->pose, str_start); + str_start[length] = '\"'; + + if (pchan) { + aci->is_bone = true; + } + } + } + BLI_addtail(&animcopybuf, aci); /* add selected keyframes to buffer */ @@ -588,19 +615,65 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data) return 0; } +static void flip_names(tAnimCopybufItem *aci, char **name) +{ + if (aci->is_bone) { + char *str_start; + if ((str_start = strstr(aci->rna_path, "pose.bones["))) { + /* ninja coding, try to change the name */ + char bname_new[MAX_VGROUP_NAME]; + char *str_iter, *str_end; + int length, prefix_l, postfix_l; + + str_start += 12; + prefix_l = str_start - aci->rna_path; + + str_end = strchr(str_start, '\"'); + + length = str_end - str_start; + postfix_l = strlen(str_end); + + /* more ninja stuff, temporary substitute with NULL terminator */ + str_start[length] = 0; + BKE_deform_flip_side_name(bname_new, str_start, false); + str_start[length] = '\"'; + + str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path"); + + BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1); + str_iter += prefix_l ; + BLI_strncpy(str_iter, bname_new, length + 1); + str_iter += length; + BLI_strncpy(str_iter, str_end, postfix_l + 1); + str_iter[postfix_l] = '\0'; + } + } +} + /* ------------------- */ /* most strict method: exact matches only */ -static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple) +static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple, bool flip) { tAnimCopybufItem *aci; for (aci = animcopybuf.first; aci; aci = aci->next) { - /* check that paths exist */ if (to_simple || (aci->rna_path && fcu->rna_path)) { - if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) { - if ((from_single) || (aci->array_index == fcu->array_index)) + if (!to_simple && flip && aci->is_bone && fcu->rna_path) { + if ((from_single) || (aci->array_index == fcu->array_index)) { + char *name = NULL; + flip_names(aci, &name); + if (strcmp(name, fcu->rna_path) == 0) { + MEM_freeN(name); + break; + } + MEM_freeN(name); + } + } + else if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) { + if ((from_single) || (aci->array_index == fcu->array_index)) { break; + } } } } @@ -671,8 +744,30 @@ static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from /* ................ */ +static void do_curve_mirror_flippping(tAnimCopybufItem *aci, BezTriple *bezt) +{ + if (aci->is_bone) { + const size_t slength = strlen(aci->rna_path); + bool flip = false; + if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0) + flip = true; + else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) && ELEM(aci->array_index, 2, 3)) + flip = true; + else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) && ELEM(aci->array_index, 1, 2)) + flip = true; + else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) && ELEM(aci->array_index, 2, 3)) + flip = true; + + if (flip) { + bezt->vec[0][1] = -bezt->vec[0][1]; + bezt->vec[1][1] = -bezt->vec[1][1]; + bezt->vec[2][1] = -bezt->vec[2][1]; + } + } +} + /* helper for paste_animedit_keys() - performs the actual pasting */ -static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode) +static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip) { BezTriple *bezt; int i; @@ -727,6 +822,9 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float /* just start pasting, with the first keyframe on the current frame, and so on */ for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) { /* temporarily apply offset to src beztriple while copying */ + if (flip) + do_curve_mirror_flippping(aci, bezt); + bezt->vec[0][0] += offset; bezt->vec[1][0] += offset; bezt->vec[2][0] += offset; @@ -734,12 +832,16 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float /* insert the keyframe * NOTE: we do not want to inherit handles from existing keyframes in this case! */ - insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL); + insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL); + /* un-apply offset from src beztriple after copying */ bezt->vec[0][0] -= offset; bezt->vec[1][0] -= offset; bezt->vec[2][0] -= offset; + + if (flip) + do_curve_mirror_flippping(aci, bezt); } /* recalculate F-Curve's handles? */ @@ -769,7 +871,7 @@ EnumPropertyItem keyframe_paste_merge_items[] = { * \return Status code is whether the method FAILED to do anything */ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, - const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip) { bAnimListElem *ale; @@ -817,7 +919,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, fcu = (FCurve *)ale->data; /* destination F-Curve */ aci = animcopybuf.first; - paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode); + paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false); } else { /* from selected channels @@ -840,7 +942,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, switch (pass) { case 0: /* most strict, must be exact path match data_path & index */ - aci = pastebuf_match_path_full(fcu, from_single, to_simple); + aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip); break; case 1: @@ -857,7 +959,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, /* copy the relevant data from the matching buffer curve */ if (aci) { totmatch++; - paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode); + paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip); } ale->update |= ANIM_UPDATE_DEFAULT; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 2c66d92ab58..7e2ce4cd3f1 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -658,7 +658,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) /* validate data */ if (ELEM(NULL, ptr, ptr->data, prop)) - return 0; + return false; /* get first constraint and determine type of keyframe constraints to check for * - constraints can be on either Objects or PoseChannels, so we only check if the @@ -880,7 +880,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr /* no F-Curve to add keyframe to? */ if (fcu == NULL) { BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to"); - return 0; + return false; } /* F-Curve not editable? */ if (fcurve_is_keyframable(fcu) == 0) { @@ -888,13 +888,13 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, " "and try removing F-Modifiers", fcu->rna_path, fcu->array_index); - return 0; + return false; } /* if no property given yet, try to validate from F-Curve info */ if ((ptr.id.data == NULL) && (ptr.data == NULL)) { BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from"); - return 0; + return false; } if (prop == NULL) { PointerRNA tmp_ptr; @@ -907,7 +907,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr BKE_reportf(reports, RPT_ERROR, "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", idname, fcu->rna_path); - return 0; + return false; } else { /* property found, so overwrite 'ptr' to make later code easier */ @@ -956,18 +956,18 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr /* only return success if keyframe added */ if (insert_mode) - return 1; + return true; } else { /* just insert keyframe */ insert_vert_fcurve(fcu, cfra, curval, flag); /* return success */ - return 1; + return true; } /* failed */ - return 0; + return false; } /* Main Keyframing API call: @@ -1284,10 +1284,10 @@ static int modify_key_op_poll(bContext *C) /* if no area or active scene */ if (ELEM(NULL, sa, scene)) - return 0; + return false; /* should be fine */ - return 1; + return true; } /* Insert Key Operator ------------------------ */ @@ -1922,17 +1922,17 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) /* ******************************************* */ /* AUTO KEYFRAME */ -int autokeyframe_cfra_can_key(Scene *scene, ID *id) +bool autokeyframe_cfra_can_key(Scene *scene, ID *id) { float cfra = (float)CFRA; // XXX for now, this will do /* only filter if auto-key mode requires this */ if (IS_AUTOKEY_ON(scene) == 0) - return 0; + return false; if (IS_AUTOKEY_MODE(scene, NORMAL)) { /* can insert anytime we like... */ - return 1; + return true; } else { /* REPLACE */ /* for whole block - only key if there's a keyframe on that frame already @@ -1952,7 +1952,7 @@ bool fcurve_frame_has_keyframe(FCurve *fcu, float frame, short filter) { /* quick sanity check */ if (ELEM(NULL, fcu, fcu->bezt)) - return 0; + return false; /* we either include all regardless of muting, or only non-muted */ if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED) == 0) { @@ -1965,11 +1965,11 @@ bool fcurve_frame_has_keyframe(FCurve *fcu, float frame, short filter) if (replace) { /* sanity check: 'i' may in rare cases exceed arraylen */ if ((i >= 0) && (i < fcu->totvert)) - return 1; + return true; } } - return 0; + return false; } /* Checks whether an Action has a keyframe for a given frame @@ -1981,11 +1981,11 @@ static bool action_frame_has_keyframe(bAction *act, float frame, short filter) /* can only find if there is data */ if (act == NULL) - return 0; + return false; /* if only check non-muted, check if muted */ if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED)) - return 0; + return false; /* loop over F-Curves, using binary-search to try to find matches * - this assumes that keyframes are only beztriples @@ -1994,12 +1994,12 @@ static bool action_frame_has_keyframe(bAction *act, float frame, short filter) /* only check if there are keyframes (currently only of type BezTriple) */ if (fcu->bezt && fcu->totvert) { if (fcurve_frame_has_keyframe(fcu, frame, filter)) - return 1; + return true; } } /* nothing found */ - return 0; + return false; } /* Checks whether an Object has a keyframe for a given frame */ @@ -2007,7 +2007,7 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) { /* error checking */ if (ob == NULL) - return 0; + return false; /* check own animation data - specifically, the action it contains */ if ((ob->adt) && (ob->adt->action)) { @@ -2018,7 +2018,7 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP); if (action_frame_has_keyframe(ob->adt->action, ob_frame, filter)) - return 1; + return true; } /* try shapekey keyframes (if available, and allowed by filter) */ @@ -2031,7 +2031,7 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) /* 1. test for relative (with keyframes) */ if (id_frame_has_keyframe((ID *)key, frame, filter)) - return 1; + return true; /* 2. test for time */ /* TODO... yet to be implemented (this feature may evolve before then anyway) */ @@ -2045,7 +2045,7 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) /* we only retrieve the active material... */ if (id_frame_has_keyframe((ID *)ma, frame, filter)) - return 1; + return true; } else { int a; @@ -2055,13 +2055,13 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) Material *ma = give_current_material(ob, a + 1); if (id_frame_has_keyframe((ID *)ma, frame, filter)) - return 1; + return true; } } } /* nothing found */ - return 0; + return false; } /* --------------- API ------------------- */ @@ -2071,7 +2071,7 @@ bool id_frame_has_keyframe(ID *id, float frame, short filter) { /* sanity checks */ if (id == NULL) - return 0; + return false; /* perform special checks for 'macro' types */ switch (GS(id->name)) { @@ -2095,7 +2095,7 @@ bool id_frame_has_keyframe(ID *id, float frame, short filter) /* no keyframe found */ - return 0; + return false; } /* ************************************************** */ diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index b7e38546ca2..574258de4f6 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -28,8 +28,6 @@ * \ingroup edarmature */ -#include "BLI_math.h" - #include "RNA_access.h" #include "WM_api.h" diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 15f75ada060..3126cca7457 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -43,6 +43,7 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_deform.h" +#include "BKE_object_deform.h" #include "BKE_report.h" #include "BKE_subsurf.h" #include "BKE_modifier.h" @@ -52,7 +53,10 @@ #include "armature_intern.h" -#include "meshlaplacian.h" + +#ifdef WITH_OPENNL +# include "meshlaplacian.h" +#endif #if 0 #include "reeb.h" @@ -117,7 +121,7 @@ static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) */ if (!(bone->flag & BONE_NO_DEFORM)) { if (!defgroup_find_name(ob, bone->name)) { - ED_vgroup_add_name(ob, bone->name); + BKE_object_defgroup_add_name(ob, bone->name); return 1; } } @@ -164,7 +168,7 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) if (!(defgroup = defgroup_find_name(ob, bone->name))) - defgroup = ED_vgroup_add_name(ob, bone->name); + defgroup = BKE_object_defgroup_add_name(ob, bone->name); if (data->list != NULL) { hgroup = (bDeformGroup ***) &data->list; @@ -276,7 +280,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if (numbones == 0) return; - if (ED_vgroup_data_create(ob->data) == false) + if (BKE_object_defgroup_data_create(ob->data) == NULL) return; /* create an array of pointer to bones that are skinnable diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 912fbc36d5d..3dbf7b4b65a 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -31,8 +31,6 @@ #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLF_translation.h" - #include "BKE_context.h" #include "BKE_sketch.h" diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 9c27fe5218a..413a74d24b5 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -365,8 +365,8 @@ typedef struct tSortActionGroup { /* compare bone groups by name */ static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr) { - tSortActionGroup *sgrp_a = (tSortActionGroup *)sgrp_a_ptr; - tSortActionGroup *sgrp_b = (tSortActionGroup *)sgrp_b_ptr; + const tSortActionGroup *sgrp_a = sgrp_a_ptr; + const tSortActionGroup *sgrp_b = sgrp_b_ptr; return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name); } diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 15e70980425..2e6eace88aa 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -916,7 +916,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID); ListBase dsources = {NULL, NULL}; - short autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); + bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); /* start tagging/keying */ for (agrp = act->groups.first; agrp; agrp = agrp->next) { diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 380a3fffc6d..1297755b7d0 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -49,8 +49,6 @@ #include "WM_api.h" #include "WM_types.h" - - #include "ED_armature.h" #include "ED_keyframing.h" diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index f1b34182439..0f42dc923a4 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -36,10 +36,6 @@ #include "DNA_curve_types.h" #include "DNA_scene_types.h" -#include "BLI_math.h" -#include "BLI_blenlib.h" - - #include "RNA_access.h" #include "WM_api.h" diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index d1208b8ba1c..99c64be5797 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -85,6 +85,7 @@ typedef struct { GHash *undoIndex; ListBase fcurves, drivers; int actnu; + int flag; } UndoCurve; /* Definitions needed for shape keys */ @@ -6880,6 +6881,7 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v) cu->actvert = undoCurve->actvert; cu->actnu = undoCurve->actnu; + cu->flag = undoCurve->flag; ED_curve_updateAnimPaths(cu); } @@ -6919,6 +6921,7 @@ static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v) undoCurve->actvert = cu->actvert; undoCurve->actnu = cu->actnu; + undoCurve->flag = cu->flag; return undoCurve; } diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 108166109b8..8393acc6919 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -500,7 +500,7 @@ void FONT_OT_text_paste_from_file(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); } @@ -558,7 +558,7 @@ void FONT_OT_text_paste_from_clipboard(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); } @@ -1835,7 +1835,7 @@ void FONT_OT_open(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | FTFONTFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_FTFONT, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); } @@ -1884,8 +1884,8 @@ static void undoFont_to_editFont(void *strv, void *ecu, void *UNUSED(obdata)) EditFont *ef = cu->editfont; const char *str = strv; - ef->pos = *((short *)str); - ef->len = *((short *)(str + 2)); + ef->pos = *((const short *)str); + ef->len = *((const short *)(str + 2)); memcpy(ef->textbuf, str + 4, (ef->len + 1) * sizeof(wchar_t)); memcpy(ef->textbufinfo, str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->len * sizeof(CharInfo)); diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 5dc9679777f..58192f59219 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -39,11 +39,12 @@ set(INC_SYS set(SRC drawgpencil.c editaction_gpencil.c - gpencil_buttons.c gpencil_edit.c gpencil_ops.c gpencil_paint.c + gpencil_select.c gpencil_undo.c + gpencil_utils.c gpencil_intern.h ) diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 5a838d7bc39..895fc6608e2 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -27,6 +27,7 @@ * \ingroup edgpencil */ + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -58,6 +59,8 @@ #include "ED_gpencil.h" #include "ED_view3d.h" +#include "UI_resources.h" + #include "gpencil_intern.h" /* ************************************************** */ @@ -73,6 +76,9 @@ typedef enum eDrawStrokeFlags { GP_DRAWDATA_ONLYI2D = (1 << 3), /* only draw 'image' strokes */ GP_DRAWDATA_IEDITHACK = (1 << 4), /* special hack for drawing strokes in Image Editor (weird coordinates) */ GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */ + GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */ + GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */ + GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */ } eDrawStrokeFlags; @@ -111,10 +117,10 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn /* draw stroke curve */ if (G.debug & G_DEBUG) setlinestyle(2); - + glLineWidth(oldpressure * thickness); glBegin(GL_LINE_STRIP); - + for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) @@ -126,7 +132,7 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn /* need to roll-back one point to ensure that there are no gaps in the stroke */ if (i != 0) glVertex2iv(&(pt - 1)->x); - + /* now the point we want... */ glVertex2iv(&pt->x); @@ -136,14 +142,221 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn glVertex2iv(&pt->x); } glEnd(); - + /* reset for predictable OpenGL context */ glLineWidth(1.0f); - + if (G.debug & G_DEBUG) setlinestyle(0); } } +/* --------- 2D Stroke Drawing Helpers --------- */ + +/* helper function to calculate x-y drawing coordinates for 2D points */ +static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2]) +{ + if (sflag & GP_STROKE_2DSPACE) { + r_co[0] = pt->x; + r_co[1] = pt->y; + } + else if (sflag & GP_STROKE_2DIMAGE) { + const float x = (float)((pt->x * winx) + offsx); + const float y = (float)((pt->y * winy) + offsy); + + r_co[0] = x; + r_co[1] = y; + } + else { + const float x = (float)(pt->x / 100 * winx) + offsx; + const float y = (float)(pt->y / 100 * winy) + offsy; + + r_co[0] = x; + r_co[1] = y; + } +} + +/* ----------- Volumetric Strokes --------------- */ + +/* draw a 2D buffer stroke in "volumetric" style + * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms + */ +static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness, + short dflag, short UNUSED(sflag)) +{ + GLUquadricObj *qobj = gluNewQuadric(); + float modelview[4][4]; + + tGPspoint *pt; + int i; + + /* error checking */ + if ((points == NULL) || (totpoints <= 0)) + return; + + /* check if buffer can be drawn */ + if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D)) + return; + + /* get basic matrix - should be camera space (i.e "identity") */ + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); + + /* draw points */ + glPushMatrix(); + + for (i = 0, pt = points; i < totpoints; i++, pt++) { + /* set the transformed position */ + // TODO: scale should change based on zoom level, which requires proper translation mult too! + modelview[3][0] = pt->x; + modelview[3][1] = pt->y; + + glLoadMatrixf((float *)modelview); + + /* draw the disk using the current state... */ + gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); + + + modelview[3][0] = modelview[3][1] = 0.0f; + } + + glPopMatrix(); + gluDeleteQuadric(qobj); +} + +/* draw a 2D strokes in "volumetric" style */ +static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness, + short dflag, short sflag, + int offsx, int offsy, int winx, int winy) +{ + GLUquadricObj *qobj = gluNewQuadric(); + float modelview[4][4]; + float baseloc[3]; + float scalefac = 1.0f; + + bGPDspoint *pt; + int i; + + + /* HACK: We need a scale factor for the drawing in the image editor, + * which seems to use 1 unit as it's maximum size, whereas everything + * else assumes 1 unit = 1 pixel. Otherwise, we only get a massive blob. + */ + if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) { + scalefac = 0.001f; + } + + /* get basic matrix */ + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); + copy_v3_v3(baseloc, modelview[3]); + + /* draw points */ + glPushMatrix(); + + for (i = 0, pt = points; i < totpoints; i++, pt++) { + /* set the transformed position */ + float co[2]; + + gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); + translate_m4(modelview, co[0], co[1], 0.0f); + + glLoadMatrixf((float *)modelview); + + /* draw the disk using the current state... */ + gluDisk(qobj, 0.0, pt->pressure * thickness * scalefac, 32, 1); + + /* restore matrix */ + copy_v3_v3(modelview[3], baseloc); + } + + glPopMatrix(); + gluDeleteQuadric(qobj); +} + +/* draw a 3D stroke in "volumetric" style */ +static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness, + short UNUSED(dflag), short UNUSED(sflag)) +{ + GLUquadricObj *qobj = gluNewQuadric(); + + float base_modelview[4][4], modelview[4][4]; + float base_loc[3]; + + bGPDspoint *pt; + int i; + + + /* Get the basic modelview matrix we use for performing calculations */ + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview); + copy_v3_v3(base_loc, base_modelview[3]); + + /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with: + * - We need to knock out the rotation so that we are + * simply left with a camera-facing billboard + * - The scale factors here are chosen so that the thickness + * is relatively reasonable. Otherwise, it gets far too + * large! + */ + scale_m4_fl(modelview, 0.1f); + + /* draw each point as a disk... */ + glPushMatrix(); + + for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + /* apply translation to base_modelview, so that the translated point is put in the right place */ + translate_m4(base_modelview, pt->x, pt->y, pt->z); + + /* copy the translation component to the billboard matrix we're going to use, + * then reset the base matrix to the original values so that we can do the same + * for the next point without accumulation/pollution effects + */ + copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */ + copy_v3_v3(base_modelview[3], base_loc); /* restore */ + + /* apply our billboard matrix for drawing... */ + glLoadMatrixf((float *)modelview); + + /* draw the disk using the current state... */ + gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); + } + + glPopMatrix(); + gluDeleteQuadric(qobj); +} + + +/* --------------- Stroke Fills ----------------- */ + +/* draw fills for shapes */ +static void gp_draw_stroke_fill(bGPDspoint *points, int totpoints, short UNUSED(thickness), + short UNUSED(dflag), short sflag, + int offsx, int offsy, int winx, int winy) +{ + bGPDspoint *pt; + int i; + + BLI_assert(totpoints >= 3); + + /* As an initial implementation, we use the OpenGL filled polygon drawing + * here since it's the easiest option to implement for this case. It does + * come with limitations (notably for concave shapes), though it shouldn't + * be much of an issue in most cases. + */ + glBegin(GL_POLYGON); + + for (i = 0, pt = points; i < totpoints; i++, pt++) { + if (sflag & GP_STROKE_3DSPACE) { + glVertex3fv(&pt->x); + } + else { + float co[2]; + + gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + + glEnd(); +} + /* ----- Existing Strokes Drawing (3D and Point) ------ */ /* draw a given stroke - just a single dot (only one point) */ @@ -160,18 +373,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla float co[2]; /* get coordinates of point */ - if (sflag & GP_STROKE_2DSPACE) { - co[0] = points->x; - co[1] = points->y; - } - else if (sflag & GP_STROKE_2DIMAGE) { - co[0] = (points->x * winx) + offsx; - co[1] = (points->y * winy) + offsy; - } - else { - co[0] = (points->x / 100 * winx) + offsx; - co[1] = (points->y / 100 * winy) + offsy; - } + gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co); /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok * - also mandatory in if Image Editor 'image-based' dot @@ -185,13 +387,13 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla } else { /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */ - GLUquadricObj *qobj = gluNewQuadric(); + GLUquadricObj *qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); + gluQuadricDrawStyle(qobj, GLU_FILL); /* need to translate drawing position, but must reset after too! */ glTranslatef(co[0], co[1], 0.0); - gluDisk(qobj, 0.0, thickness, 32, 1); + gluDisk(qobj, 0.0, thickness, 32, 1); glTranslatef(-co[0], -co[1], 0.0); gluDeleteQuadric(qobj); @@ -200,7 +402,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla } /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ -static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, short debug) +static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short UNUSED(sflag)) { bGPDspoint *pt; float curpressure = points[0].pressure; @@ -231,8 +433,9 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness } } glEnd(); - + /* draw debug points of curve on top? */ + /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */ if (debug) { glBegin(GL_POINTS); for (i = 0, pt = points; i < totpoints && pt; i++, pt++) @@ -244,46 +447,22 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness /* ----- Fancy 2D-Stroke Drawing ------ */ /* draw a given stroke in 2d */ -static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, - short debug, int offsx, int offsy, int winx, int winy) +static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, + bool debug, int offsx, int offsy, int winx, int winy) { /* otherwise thickness is twice that of the 3D view */ float thickness = (float)thickness_s * 0.5f; - - /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better - * - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke - */ - if ((thickness < GP_DRAWTHICKNESS_SPECIAL) || - ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D))) - { - bGPDspoint *pt; - int i; - - glBegin(GL_LINE_STRIP); - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - if (sflag & GP_STROKE_2DSPACE) { - glVertex2f(pt->x, pt->y); - } - else if (sflag & GP_STROKE_2DIMAGE) { - const float x = (pt->x * winx) + offsx; - const float y = (pt->y * winy) + offsy; - - glVertex2f(x, y); - } - else { - const float x = (pt->x / 100 * winx) + offsx; - const float y = (pt->y / 100 * winy) + offsy; - - glVertex2f(x, y); - } - } - glEnd(); + + /* strokes in Image Editor need a scale factor, since units there are not pixels! */ + float scalefac = 1.0f; + if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) { + scalefac = 0.001f; } /* tessellation code - draw stroke as series of connected quads with connection * edges rotated to minimize shrinking artifacts, and rounded endcaps */ - else { + { bGPDspoint *pt1, *pt2; float pm[2]; int i; @@ -299,22 +478,8 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, float pthick; /* thickness at segment point */ /* get x and y coordinates from points */ - if (sflag & GP_STROKE_2DSPACE) { - s0[0] = pt1->x; s0[1] = pt1->y; - s1[0] = pt2->x; s1[1] = pt2->y; - } - else if (sflag & GP_STROKE_2DIMAGE) { - s0[0] = (pt1->x * winx) + offsx; - s0[1] = (pt1->y * winy) + offsy; - s1[0] = (pt2->x * winx) + offsx; - s1[1] = (pt2->y * winy) + offsy; - } - else { - s0[0] = (pt1->x / 100 * winx) + offsx; - s0[1] = (pt1->y / 100 * winy) + offsy; - s1[0] = (pt2->x / 100 * winx) + offsx; - s1[1] = (pt2->y / 100 * winy) + offsy; - } + gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0); + gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1); /* calculate gradient and normal - 'angle'=(ny/nx) */ m1[1] = s1[1] - s0[1]; @@ -324,12 +489,12 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, m2[0] = m1[1]; /* always use pressure from first point here */ - pthick = (pt1->pressure * thickness); + pthick = (pt1->pressure * thickness * scalefac); /* if the first segment, start of segment is segment's normal */ if (i == 0) { - /* draw start cap first - * - make points slightly closer to center (about halfway across) + /* draw start cap first + * - make points slightly closer to center (about halfway across) */ mt[0] = m2[0] * pthick * 0.5f; mt[1] = m2[1] * pthick * 0.5f; @@ -369,7 +534,7 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, mb[1] = (pm[1] + m2[1]) / 2; normalize_v2(mb); - /* calculate gradient to apply + /* calculate gradient to apply * - as basis, use just pthick * bisector gradient * - if cross-section not as thick as it should be, add extra padding to fix it */ @@ -399,7 +564,7 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, /* if last segment, also draw end of segment (defined as segment's normal) */ if (i == totpoints - 2) { /* for once, we use second point's pressure (otherwise it won't be drawn) */ - pthick = (pt2->pressure * thickness); + pthick = (pt2->pressure * thickness * scalefac); /* calculate points for end of segment */ mt[0] = m2[0] * pthick; @@ -417,8 +582,8 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, glVertex2fv(t1); - /* draw end cap as last step - * - make points slightly closer to center (about halfway across) + /* draw end cap as last step + * - make points slightly closer to center (about halfway across) */ mt[0] = m2[0] * pthick * 0.5f; mt[1] = m2[1] * pthick * 0.5f; @@ -448,52 +613,57 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, glBegin(GL_POINTS); for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - if (sflag & GP_STROKE_2DSPACE) { - glVertex2fv(&pt->x); - } - else if (sflag & GP_STROKE_2DIMAGE) { - const float x = (float)((pt->x * winx) + offsx); - const float y = (float)((pt->y * winy) + offsy); - - glVertex2f(x, y); - } - else { - const float x = (float)(pt->x / 100 * winx) + offsx; - const float y = (float)(pt->y / 100 * winy) + offsy; - - glVertex2f(x, y); - } + float co[2]; + + gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); + glVertex2fv(co); } glEnd(); } } -/* ----- General Drawing ------ */ +/* ----- Strokes Drawing ------ */ + +/* Helper for doing all the checks on whether a stroke can be drawn */ +static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) +{ + /* skip stroke if it isn't in the right display space for this drawing context */ + /* 1) 3D Strokes */ + if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) + return false; + + /* 2) Screen Space 2D Strokes */ + if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) + return false; + + /* 3) Image Space (2D) */ + if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) + return false; + + + /* skip stroke if it doesn't have any valid data */ + if ((gps->points == NULL) || (gps->totpoints < 1)) + return false; + + /* stroke can be drawn */ + return true; +} /* draw a set of strokes */ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, - short debug, short lthick, const float color[4]) + bool debug, short lthick, const float color[4], const float fill_color[4]) { bGPDstroke *gps; - /* set color first (may need to reset it again later too) */ - glColor4fv(color); - for (gps = gpf->strokes.first; gps; gps = gps->next) { - /* check if stroke can be drawn - checks here generally fall into pairs */ - if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) - continue; - if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) - continue; - if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) - continue; - if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) - continue; - if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) - continue; - if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) - continue; - if ((gps->points == NULL) || (gps->totpoints < 1)) + /* check if stroke can be drawn */ + if (gp_can_draw_stroke(gps, dflag) == false) continue; /* check which stroke-drawer to use */ @@ -515,11 +685,27 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int #endif } - if (gps->totpoints == 1) { - gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + /* 3D Fill */ + if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) { + glColor4fv(fill_color); + gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + + /* 3D Stroke */ + glColor4fv(color); + + if (dflag & GP_DRAWDATA_VOLUMETRIC) { + /* volumetric stroke drawing */ + gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag); } else { - gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug); + /* 3D Lines - OpenGL primitives-based */ + if (gps->totpoints == 1) { + gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + else { + gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag); + } } if (no_xray) { @@ -534,116 +720,302 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int } } else { - if (gps->totpoints == 1) { - gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + /* 2D - Fill */ + if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) { + glColor4fv(fill_color); + gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + + /* 2D Strokes... */ + glColor4fv(color); + + if (dflag & GP_DRAWDATA_VOLUMETRIC) { + /* blob/disk-based "volumetric" drawing */ + gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); } else { - gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy); + /* normal 2D strokes */ + if (gps->totpoints == 1) { + gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + else { + gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy); + } } } } } -/* draw grease-pencil datablock */ -static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) +/* Draw selected verts for strokes being edited */ +static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3]) { - bGPDlayer *gpl; + bGPDstroke *gps; - /* reset line drawing style (in case previous user didn't reset) */ - setlinestyle(0); + const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY); + int mask_orig = 0; - /* turn on smooth lines (i.e. anti-aliasing) */ - glEnable(GL_LINE_SMOOTH); + /* set up depth masks... */ + if (dflag & GP_DRAWDATA_ONLY3D) { + if (no_xray) { + glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + glDepthMask(0); + glEnable(GL_DEPTH_TEST); + + /* first arg is normally rv3d->dist, but this isn't + * available here and seems to work quite well without */ + bglPolygonOffset(1.0f, 1.0f); +#if 0 + glEnable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(-1.0f, -1.0f); +#endif + } + } - /* turn on alpha-blending */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); + + /* draw stroke verts */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + float vsize, bsize; + int i; + + /* check if stroke can be drawn */ + if (gp_can_draw_stroke(gps, dflag) == false) + continue; - /* loop over layers, drawing them */ + /* Optimisation: only draw points for selected strokes + * We assume that selected points can only occur in + * strokes that are selected too. + */ + if ((gps->flag & GP_STROKE_SELECT) == 0) + continue; + + /* Get size of verts: + * - The selected state needs to be larger than the unselected state so that + * they stand out more. + * - We use the theme setting for size of the unselected verts + */ + bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); + if ((int)bsize > 8) { + vsize = 10.0f; + bsize = 8.0f; + } + else { + vsize = bsize + 2; + } + + /* First Pass: Draw all the verts (i.e. these become the unselected state) */ + if (tcolor != NULL) { + /* for now, we assume that the base color of the points is not too close to the real color */ + glColor3fv(tcolor); + } + else { + /* this doesn't work well with the default theme and black strokes... */ + UI_ThemeColor(TH_GP_VERTEX); + } + glPointSize(bsize); + + glBegin(GL_POINTS); + for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { + if (gps->flag & GP_STROKE_3DSPACE) { + glVertex3fv(&pt->x); + } + else { + float co[2]; + + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + glEnd(); + + + /* Second Pass: Draw only verts which are selected */ + UI_ThemeColor(TH_GP_VERTEX_SELECT); + glPointSize(vsize); + + glBegin(GL_POINTS); + for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + if (gps->flag & GP_STROKE_3DSPACE) { + glVertex3fv(&pt->x); + } + else { + float co[2]; + + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + } + glEnd(); + } + + + /* clear depth mask */ + if (dflag & GP_DRAWDATA_ONLY3D) { + if (no_xray) { + glDepthMask(mask_orig); + glDisable(GL_DEPTH_TEST); + + bglPolygonOffset(0.0, 0.0); +#if 0 + glDisable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(0, 0); +#endif + } + } +} + +/* ----- General Drawing ------ */ + +/* draw onion-skinning for a layer */ +static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, + int UNUSED(cfra), int dflag, short debug, short lthick) +{ + const float alpha = gpl->color[3]; + float color[4]; + + /* 1) Draw Previous Frames First */ + if (gpl->flag & GP_LAYER_GHOST_PREVCOL) { + copy_v3_v3(color, gpl->gcolor_prev); + } + else { + copy_v3_v3(color, gpl->color); + } + + if (gpl->gstep) { + bGPDframe *gf; + float fac; + + /* draw previous frames first */ + for (gf = gpf->prev; gf; gf = gf->prev) { + /* check if frame is drawable */ + if ((gpf->framenum - gf->framenum) <= gpl->gstep) { + /* alpha decreases with distance from curframe index */ + fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); + color[3] = alpha * fac * 0.66f; + gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); + } + else + break; + } + } + else { + /* draw the strokes for the ghost frames (at half of the alpha set by user) */ + if (gpf->prev) { + color[3] = (alpha / 7); + gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); + } + } + + + /* 2) Now draw next frames */ + if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) { + copy_v3_v3(color, gpl->gcolor_next); + } + else { + copy_v3_v3(color, gpl->color); + } + + if (gpl->gstep_next) { + bGPDframe *gf; + float fac; + + /* now draw next frames */ + for (gf = gpf->next; gf; gf = gf->next) { + /* check if frame is drawable */ + if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) { + /* alpha decreases with distance from curframe index */ + fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1)); + color[3] = alpha * fac * 0.66f; + gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); + } + else + break; + } + } + else { + /* draw the strokes for the ghost frames (at half of the alpha set by user) */ + if (gpf->next) { + color[3] = (alpha / 4); + gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); + } + } + + /* 3) restore alpha */ + glColor4fv(gpl->color); +} + +/* loop over gpencil data layers, drawing them */ +static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) +{ + bGPDlayer *gpl; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { bGPDframe *gpf; - short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0; + bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false; short lthick = gpl->thickness; - float color[4], tcolor[4]; /* don't draw layer if hidden */ - if (gpl->flag & GP_LAYER_HIDE) + if (gpl->flag & GP_LAYER_HIDE) continue; /* get frame to draw */ gpf = gpencil_layer_getframe(gpl, cfra, 0); - if (gpf == NULL) + if (gpf == NULL) continue; /* set color, stroke thickness, and point size */ glLineWidth(lthick); - copy_v4_v4(color, gpl->color); // just for copying 4 array elements - copy_v4_v4(tcolor, gpl->color); // additional copy of color (for ghosting) - glColor4fv(color); glPointSize((float)(gpl->thickness + 2)); - /* apply xray layer setting */ - if (gpl->flag & GP_LAYER_NO_XRAY) dflag |= GP_DRAWDATA_NO_XRAY; - else dflag &= ~GP_DRAWDATA_NO_XRAY; + /* Add layer drawing settings to the set of "draw flags" + * NOTE: If the setting doesn't apply, it *must* be cleared, + * as dflag's carry over from the previous layer + */ +#define GP_DRAWFLAG_APPLY(condition, draw_flag_value) { \ + if (condition) dflag |= (draw_flag_value); \ + else dflag &= ~(draw_flag_value); \ + } (void)0 + + /* xray... */ + GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY); + + /* volumetric strokes... */ + GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC); + + /* fill strokes... */ + // XXX: this is not a very good limit + GP_DRAWFLAG_APPLY((gpl->fill[3] > 0.001f), GP_DRAWDATA_FILL); +#undef GP_DRAWFLAG_APPLY /* draw 'onionskins' (frame left + right) */ - if (gpl->flag & GP_LAYER_ONIONSKIN) { - /* drawing method - only immediately surrounding (gstep = 0), - * or within a frame range on either side (gstep > 0)*/ - if (gpl->gstep) { - bGPDframe *gf; - float fac; - - /* draw previous frames first */ - for (gf = gpf->prev; gf; gf = gf->prev) { - /* check if frame is drawable */ - if ((gpf->framenum - gf->framenum) <= gpl->gstep) { - /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); - tcolor[3] = color[3] * fac * 0.66f; - gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - else - break; - } - - /* now draw next frames */ - for (gf = gpf->next; gf; gf = gf->next) { - /* check if frame is drawable */ - if ((gf->framenum - gpf->framenum) <= gpl->gstep) { - /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1)); - tcolor[3] = color[3] * fac * 0.66f; - gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - else - break; - } - - /* restore alpha */ - glColor4fv(color); - } - else { - /* draw the strokes for the ghost frames (at half of the alpha set by user) */ - if (gpf->prev) { - tcolor[3] = (color[3] / 7); - gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - - if (gpf->next) { - tcolor[3] = (color[3] / 4); - gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - - /* restore alpha */ - glColor4fv(color); - } + if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) { + /* Drawing method - only immediately surrounding (gstep = 0), + * or within a frame range on either side (gstep > 0) + */ + gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick); } /* draw the strokes already in active frame */ - tcolor[3] = color[3]; - gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); + gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill); + + /* Draw verts of selected strokes + * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering + * - locked layers can't be edited, so there's no point showing these verts + * as they will have no bearings on what gets edited + * - only show when in editmode, since operators shouldn't work otherwise + * (NOTE: doing it this way means that the toggling editmode shows visible change immediately) + */ + /* XXX: perhaps we don't want to show these when users are drawing... */ + if ((G.f & G_RENDER_OGL) == 0 && + (gpl->flag & GP_LAYER_LOCKED) == 0 && + (gpd->flag & GP_DATA_STROKE_EDITMODE)) + { + gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag, + (gpl->color[3] < 0.95f) ? gpl->color : NULL); + } /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) @@ -651,22 +1023,83 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) && (gpf->flag & GP_FRAME_PAINT)) { + /* Set color for drawing buffer stroke - since this may not be set yet */ + glColor4fv(gpl->color); + /* Buffer stroke needs to be drawn with a different linestyle - * to help differentiate them from normal strokes. */ - gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); + * to help differentiate them from normal strokes. + * + * It should also be noted that sbuffer contains temporary point types + * i.e. tGPspoints NOT bGPDspoints + */ + if (gpl->flag & GP_LAYER_VOLUMETRIC) { + gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); + } + else { + gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); + } } } +} + +/* draw grease-pencil datablock */ +static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) +{ + /* reset line drawing style (in case previous user didn't reset) */ + setlinestyle(0); + + /* turn on smooth lines (i.e. anti-aliasing) */ + glEnable(GL_LINE_SMOOTH); + + glEnable(GL_POLYGON_SMOOTH); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + + /* turn on alpha-blending */ + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + /* draw! */ + gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag); /* turn off alpha blending, then smooth lines */ glDisable(GL_BLEND); // alpha blending glDisable(GL_LINE_SMOOTH); // smooth lines - + glDisable(GL_POLYGON_SMOOTH); // smooth poly lines + /* restore initial gl conditions */ glLineWidth(1.0); glPointSize(1.0); glColor4f(0, 0, 0, 1); } +/* if we have strokes for scenes (3d view)/clips (movie clip editor) + * and objects/tracks, multiple data blocks have to be drawn */ +static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy, + int cfra, int dflag, const char spacetype) +{ + bGPdata *gpd_source = NULL; + + if (scene) { + if (spacetype == SPACE_VIEW3D) { + gpd_source = (scene->gpd ? scene->gpd : NULL); + } + else if (spacetype == SPACE_CLIP && scene->clip) { + /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */ + gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL); + } + + if (gpd_source) { + gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag); + } + } + + /* scene/clip data has already been drawn, only object/track data is drawn here + * if gpd_source == gpd, we don't have any object/track data and we can skip */ + if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { + gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag); + } +} + /* ----- Grease Pencil Sketches Drawing API ------ */ /* ............................ @@ -693,7 +1126,7 @@ void ED_gpencil_draw_2dimage(const bContext *C) case SPACE_IMAGE: /* image */ case SPACE_CLIP: /* clip */ { - + /* just draw using standard scaling (settings here are currently ignored anyways) */ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ offsx = 0; @@ -714,8 +1147,8 @@ void ED_gpencil_draw_2dimage(const bContext *C) sizex = ar->winx; sizey = ar->winy; - /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated - * and everything moved to standard View2d + /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated + * and everything moved to standard View2d */ dflag |= GP_DRAWDATA_ONLYV2D; break; @@ -732,10 +1165,10 @@ void ED_gpencil_draw_2dimage(const bContext *C) /* draw it! */ - gp_draw_data(gpd, offsx, offsy, sizex, sizey, CFRA, dflag); + gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype); } -/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly +/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, * second time with onlyv2d=0 for screen-aligned strokes */ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) @@ -758,10 +1191,10 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) /* draw it! */ if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS); - gp_draw_data(gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag); + gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype); } -/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly +/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, * second time with only3d=0 for screen-aligned strokes */ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d) @@ -770,17 +1203,17 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d) int dflag = 0; RegionView3D *rv3d = ar->regiondata; int offsx, offsy, winx, winy; - + /* check that we have grease-pencil stuff to draw */ gpd = ED_gpencil_data_get_active_v3d(scene, v3d); if (gpd == NULL) return; - + /* when rendering to the offscreen buffer we don't want to * deal with the camera border, otherwise map the coords to the camera border. */ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { rctf rectf; ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */ - + offsx = iroundf(rectf.xmin); offsy = iroundf(rectf.ymin); winx = iroundf(rectf.xmax - rectf.xmin); @@ -795,15 +1228,15 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d) /* draw it! */ if (only3d) dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); - - gp_draw_data(gpd, offsx, offsy, winx, winy, CFRA, dflag); + + gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); } -void ED_gpencil_draw_ex(bGPdata *gpd, int winx, int winy, const int cfra) +void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype) { int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D; - - gp_draw_data(gpd, 0, 0, winx, winy, cfra, dflag); + + gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype); } /* ************************************************** */ diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index dba80164e93..97adaea41a8 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -27,7 +27,7 @@ * \ingroup edgpencil */ - + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -49,8 +49,6 @@ #include "ED_keyframes_edit.h" #include "ED_markers.h" -#include "gpencil_intern.h" - /* ***************************************** */ /* NOTE ABOUT THIS FILE: * This file contains code for editing Grease Pencil data in the Action Editor @@ -75,7 +73,7 @@ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPD if (gpf_cb(gpf, scene)) return true; } - + /* nothing to return */ return false; } @@ -115,7 +113,7 @@ bool ED_gplayer_frame_select_check(bGPDlayer *gpl) bGPDframe *gpf; /* error checking */ - if (gpl == NULL) + if (gpl == NULL) return false; /* stop at the first one found */ @@ -153,9 +151,9 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode) bGPDframe *gpf; /* error checking */ - if (gpl == NULL) + if (gpl == NULL) return; - + /* handle according to mode */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { gpframe_select(gpf, select_mode); @@ -166,7 +164,7 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode) void ED_gplayer_frame_select_set(bGPDlayer *gpl, short mode) { /* error checking */ - if (gpl == NULL) + if (gpl == NULL) return; /* now call the standard function */ @@ -178,11 +176,11 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode) { bGPDframe *gpf; - if (gpl == NULL) + if (gpl == NULL) return; - + gpf = BKE_gpencil_layer_find_frame(gpl, selx); - + if (gpf) { gpframe_select(gpf, select_mode); } @@ -215,7 +213,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) /* error checking */ if (gpl == NULL) return false; - + /* check for frames to delete */ for (gpf = gpl->frames.first; gpf; gpf = gpfn) { gpfn = gpf->next; @@ -223,7 +221,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) if (gpf->flag & GP_FRAME_SELECT) changed |= gpencil_layer_delframe(gpl, gpf); } - + return changed; } @@ -242,7 +240,7 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl) /* duplicate this frame */ if (gpf->flag & GP_FRAME_SELECT) { - bGPDframe *gpfd; + bGPDframe *gpfd; /* duplicate frame, and deselect self */ gpfd = gpencil_frame_duplicate(gpf); @@ -253,6 +251,23 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl) } } +/* Set keyframe type for selected frames from given gp-layer + * \param type The type of keyframe (eBezTriple_KeyframeType) to set selected frames to + */ +void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type) +{ + bGPDframe *gpf; + + if (gpl == NULL) + return; + + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if (gpf->flag & GP_FRAME_SELECT) { + gpf->key_type = type; + } + } +} + #if 0 // XXX disabled until grease pencil code stabilises again /* -------------------------------------- */ /* Copy and Paste Tools */ @@ -263,7 +278,7 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl) * the current frame and the 'first keyframe' (i.e. the earliest one in all channels). * - The earliest frame is calculated per copy operation. */ - + /* globals for copy/paste data (like for other copy/paste buffers) */ ListBase gpcopybuf = {NULL, NULL}; static int gpcopy_firstframe = 999999999; @@ -271,7 +286,7 @@ static int gpcopy_firstframe = 999999999; /* This function frees any MEM_calloc'ed copy/paste buffer data */ void free_gpcopybuf() { - free_gpencil_layers(&gpcopybuf); + free_gpencil_layers(&gpcopybuf); BLI_listbase_clear(&gpcopybuf); gpcopy_firstframe = 999999999; @@ -398,8 +413,8 @@ void paste_gpdata(Scene *scene) //sa = gpencil_data_findowner((bGPdata *)ale->owner); sa = NULL; - /* this should be the right frame... as it may be a pre-existing frame, - * must make sure that only compatible stroke types get copied over + /* this should be the right frame... as it may be a pre-existing frame, + * must make sure that only compatible stroke types get copied over * - we cannot just add a duplicate frame, as that would cause errors * - need to check for compatible types to minimize memory usage (copying 'junk' over) */ @@ -418,14 +433,14 @@ void paste_gpdata(Scene *scene) if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE)) stroke_ok = 1; break; - + case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */ case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */ case SPACE_CLIP: /* Image Editor: either screen-aligned or view\image-aligned */ if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE)) stroke_ok = 1; break; - + case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */ if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE)) stroke_ok = 1; @@ -567,9 +582,9 @@ static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene) /* In order for this mirror function to work without * any extra arguments being added, we use the case - * of bezt==NULL to denote that we should find the + * of bezt==NULL to denote that we should find the * marker to mirror over. The static pointer is safe - * to use this way, as it will be set to null after + * to use this way, as it will be set to null after * each cycle in which this is called. */ diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c deleted file mode 100644 index a7635c12d56..00000000000 --- a/source/blender/editors/gpencil/gpencil_buttons.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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, Joshua Leung - * This is a new part of Blender - * - * Contributor(s): Joshua Leung - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/gpencil/gpencil_buttons.c - * \ingroup edgpencil - */ - - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stddef.h> - -#include "BLI_blenlib.h" - -#include "BLF_translation.h" - -#include "DNA_gpencil_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" - -#include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_gpencil.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_access.h" - -#include "ED_gpencil.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "gpencil_intern.h" - -/* ************************************************** */ -/* GREASE PENCIL PANEL-UI DRAWING */ - -/* Every space which implements Grease-Pencil functionality should have a panel - * for the settings. All of the space-dependent parts should be coded in the panel - * code for that space, but the rest is all handled by generic panel here. - */ - -/* ------- Callbacks ----------- */ -/* These are just 'dummy wrappers' around gpencil api calls */ - -/* make layer active one after being clicked on */ -static void gp_ui_activelayer_cb(bContext *C, void *gpd, void *gpl) -{ - /* make sure the layer we want to remove is the active one */ - gpencil_layer_setactive(gpd, gpl); - - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -/* delete 'active' layer */ -static void gp_ui_dellayer_cb(bContext *C, void *gpd, void *gpl) -{ - gpencil_layer_delete((bGPdata *)gpd, (bGPDlayer *)gpl); - - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -/* move layer up */ -static void gp_ui_layer_up_cb(bContext *C, void *gpd_v, void *gpl_v) -{ - bGPdata *gpd = gpd_v; - bGPDlayer *gpl = gpl_v; - - BLI_remlink(&gpd->layers, gpl); - BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl); - - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -/* move layer down */ -static void gp_ui_layer_down_cb(bContext *C, void *gpd_v, void *gpl_v) -{ - bGPdata *gpd = gpd_v; - bGPDlayer *gpl = gpl_v; - - BLI_remlink(&gpd->layers, gpl); - BLI_insertlinkafter(&gpd->layers, gpl->next, gpl); - - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -/* ------- Drawing Code ------- */ - -/* draw the controls for a given layer */ -static void gp_drawui_layer(uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl, const bool is_v3d) -{ - uiLayout *box = NULL, *split = NULL; - uiLayout *col = NULL; - uiLayout *row = NULL, *sub = NULL; - uiBlock *block; - uiBut *but; - PointerRNA ptr; - int icon; - - /* make pointer to layer data */ - RNA_pointer_create((ID *)gpd, &RNA_GPencilLayer, gpl, &ptr); - - /* unless button has own callback, it adds this callback to button */ - block = uiLayoutGetBlock(layout); - UI_block_func_set(block, gp_ui_activelayer_cb, gpd, gpl); - - /* draw header ---------------------------------- */ - /* get layout-row + UI-block for header */ - box = uiLayoutBox(layout); - - row = uiLayoutRow(box, false); - uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND); - block = uiLayoutGetBlock(row); /* err... */ - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - - /* left-align ............................... */ - sub = uiLayoutRow(row, false); - - /* active */ - block = uiLayoutGetBlock(sub); - icon = (gpl->flag & GP_LAYER_ACTIVE) ? ICON_RADIOBUT_ON : ICON_RADIOBUT_OFF; - but = uiDefIconButBitI(block, UI_BTYPE_TOGGLE, GP_LAYER_ACTIVE, 0, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y, - &gpl->flag, 0.0, 0.0, 0.0, 0.0, TIP_("Set active layer")); - UI_but_func_set(but, gp_ui_activelayer_cb, gpd, gpl); - - /* locked */ - icon = (gpl->flag & GP_LAYER_LOCKED) ? ICON_LOCKED : ICON_UNLOCKED; - uiItemR(sub, &ptr, "lock", 0, "", icon); - - /* when layer is locked or hidden, only draw header */ - if (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE)) { - char name[256]; /* gpl->info is 128, but we need space for 'locked/hidden' as well */ - - /* visibility button (only if hidden but not locked!) */ - if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED)) - uiItemR(sub, &ptr, "hide", 0, "", ICON_RESTRICT_VIEW_ON); - - /* name */ - if (gpl->flag & GP_LAYER_HIDE) - BLI_snprintf(name, sizeof(name), IFACE_("%s (Hidden)"), gpl->info); - else - BLI_snprintf(name, sizeof(name), IFACE_("%s (Locked)"), gpl->info); - uiItemL(sub, name, ICON_NONE); - - /* delete button (only if hidden but not locked!) */ - if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED)) { - /* right-align ............................... */ - sub = uiLayoutRow(row, true); - uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); - block = uiLayoutGetBlock(sub); /* XXX... err... */ - - but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete layer")); - UI_but_func_set(but, gp_ui_dellayer_cb, gpd, gpl); - } - UI_block_emboss_set(block, UI_EMBOSS); - } - else { - /* draw rest of header -------------------------------- */ - /* visibility button */ - uiItemR(sub, &ptr, "hide", 0, "", ICON_RESTRICT_VIEW_OFF); - - /* frame locking */ - /* TODO: this needs its own icons... */ - icon = (gpl->flag & GP_LAYER_FRAMELOCK) ? ICON_RENDER_STILL : ICON_RENDER_ANIMATION; - uiItemR(sub, &ptr, "lock_frame", 0, "", icon); - - UI_block_emboss_set(block, UI_EMBOSS); - - /* name */ - uiItemR(sub, &ptr, "info", 0, "", ICON_NONE); - - /* move up/down */ - UI_block_align_begin(block); - - if (gpl->prev) { - but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_UP, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer up")); - UI_but_func_set(but, gp_ui_layer_up_cb, gpd, gpl); - } - if (gpl->next) { - but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_DOWN, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer down")); - UI_but_func_set(but, gp_ui_layer_down_cb, gpd, gpl); - } - - UI_block_align_end(block); - - /* delete 'button' */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); - /* right-align ............................... */ - sub = uiLayoutRow(row, true); - uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); - block = uiLayoutGetBlock(sub); /* XXX... err... */ - - but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete layer")); - UI_but_func_set(but, gp_ui_dellayer_cb, gpd, gpl); - UI_block_emboss_set(block, UI_EMBOSS); - - /* new backdrop ----------------------------------- */ - box = uiLayoutBox(layout); - split = uiLayoutSplit(box, 0.5f, false); - - /* draw settings ---------------------------------- */ - /* left column ..................... */ - col = uiLayoutColumn(split, false); - - /* color */ - sub = uiLayoutColumn(col, true); - uiItemR(sub, &ptr, "color", 0, "", ICON_NONE); - uiItemR(sub, &ptr, "alpha", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - - /* stroke thickness */ - uiItemR(col, &ptr, "line_width", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - - /* debugging options */ - if (G.debug & G_DEBUG) { - uiItemR(col, &ptr, "show_points", 0, NULL, ICON_NONE); - } - - /* right column ................... */ - col = uiLayoutColumn(split, false); - - /* onion-skinning */ - sub = uiLayoutColumn(col, true); - uiItemR(sub, &ptr, "use_onion_skinning", 0, NULL, ICON_NONE); - uiItemR(sub, &ptr, "ghost_range_max", 0, IFACE_("Frames"), ICON_NONE); - - /* 3d-view specific drawing options */ - if (is_v3d) { - uiItemR(col, &ptr, "show_x_ray", 0, NULL, ICON_NONE); - } - } -} - -/* stroke drawing options available */ -typedef enum eGP_Stroke_Ops { - STROKE_OPTS_NORMAL = 0, - STROKE_OPTS_V3D_OFF, - STROKE_OPTS_V3D_ON, -} eGP_Stroke_Ops; - -static void draw_gpencil_space_specials(const bContext *C, uiLayout *layout) -{ - uiLayout *col, *row; - SpaceClip *sc = CTX_wm_space_clip(C); - - col = uiLayoutColumn(layout, false); - - if (sc) { - bScreen *screen = CTX_wm_screen(C); - PointerRNA sc_ptr; - - RNA_pointer_create(&screen->id, &RNA_SpaceClipEditor, sc, &sc_ptr); - row = uiLayoutRow(col, true); - uiItemR(row, &sc_ptr, "grease_pencil_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - } -} - -/* Draw the contents for a grease-pencil panel*/ -static void draw_gpencil_panel(bContext *C, uiLayout *layout, bGPdata *gpd, PointerRNA *ctx_ptr) -{ - PointerRNA gpd_ptr; - bGPDlayer *gpl; - uiLayout *col, *row; - SpaceClip *sc = CTX_wm_space_clip(C); - short v3d_stroke_opts = STROKE_OPTS_NORMAL; - const bool is_v3d = CTX_wm_view3d(C) != NULL; - - /* make new PointerRNA for Grease Pencil block */ - RNA_id_pointer_create((ID *)gpd, &gpd_ptr); - - /* draw gpd settings first ------------------------------------- */ - col = uiLayoutColumn(layout, false); - - /* current Grease Pencil block */ - /* TODO: show some info about who owns this? */ - uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_add", NULL, "GPENCIL_OT_data_unlink"); - - /* add new layer button - can be used even when no data, since it can add a new block too */ - uiItemO(col, IFACE_("New Layer"), ICON_NONE, "GPENCIL_OT_layer_add"); - row = uiLayoutRow(col, true); - uiItemO(row, IFACE_("Delete Frame"), ICON_NONE, "GPENCIL_OT_active_frame_delete"); - uiItemO(row, IFACE_("Convert"), ICON_NONE, "GPENCIL_OT_convert"); - - /* sanity checks... */ - if (gpd == NULL) - return; - - /* draw each layer --------------------------------------------- */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - col = uiLayoutColumn(layout, true); - gp_drawui_layer(col, gpd, gpl, is_v3d); - } - - /* draw gpd drawing settings first ------------------------------------- */ - col = uiLayoutColumn(layout, true); - /* label */ - uiItemL(col, IFACE_("Drawing Settings:"), ICON_NONE); - - /* check whether advanced 3D-View drawing space options can be used */ - if (is_v3d) { - if (gpd->flag & (GP_DATA_DEPTH_STROKE | GP_DATA_DEPTH_VIEW)) - v3d_stroke_opts = STROKE_OPTS_V3D_ON; - else - v3d_stroke_opts = STROKE_OPTS_V3D_OFF; - } - - /* drawing space options */ - row = uiLayoutRow(col, true); - uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "VIEW", NULL, ICON_NONE); - uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "CURSOR", NULL, ICON_NONE); - - if (sc == NULL) { - row = uiLayoutRow(col, true); - uiLayoutSetActive(row, v3d_stroke_opts); - uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "SURFACE", NULL, ICON_NONE); - uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "STROKE", NULL, ICON_NONE); - - row = uiLayoutRow(col, false); - uiLayoutSetActive(row, v3d_stroke_opts == STROKE_OPTS_V3D_ON); - uiItemR(row, &gpd_ptr, "use_stroke_endpoints", 0, NULL, ICON_NONE); - } -} - -void ED_gpencil_panel_standard_header(const bContext *C, Panel *pa) -{ - PointerRNA ptr; - RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, CTX_wm_space_data(C), &ptr); - - uiItemR(pa->layout, &ptr, "show_grease_pencil", 0, "", ICON_NONE); -} - -/* Standard panel to be included wherever Grease Pencil is used... */ -void ED_gpencil_panel_standard(const bContext *C, Panel *pa) -{ - bGPdata **gpd_ptr = NULL; - PointerRNA ptr; - - /* if (v3d->flag2 & V3D_DISPGP)... etc. */ - - draw_gpencil_space_specials(C, pa->layout); - - /* get pointer to Grease Pencil Data */ - gpd_ptr = ED_gpencil_data_get_pointers((bContext *)C, &ptr); - - if (gpd_ptr) - draw_gpencil_panel((bContext *)C, pa->layout, *gpd_ptr, &ptr); -} - -/* ************************************************** */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 13334448941..3dae25263e8 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -27,6 +27,7 @@ * \ingroup edgpencil */ + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -86,50 +87,59 @@ /* ************************************************ */ /* Context Wrangling... */ -/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */ -bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) +/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it, + * when context info is not available. + */ +bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr) { - ID *screen_id = (ID *)CTX_wm_screen(C); - Scene *scene = CTX_data_scene(C); - ScrArea *sa = CTX_wm_area(C); - /* if there's an active area, check if the particular editor may * have defined any special Grease Pencil context for editing... */ if (sa) { + SpaceLink *sl = sa->spacedata.first; + switch (sa->spacetype) { case SPACE_VIEW3D: /* 3D-View */ + case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */ { - Object *ob = CTX_data_active_object(C); - - /* TODO: we can include other data-types such as bones later if need be... */ - - /* just in case no active/selected object */ - if (ob && (ob->flag & SELECT)) { - /* for now, as long as there's an object, default to using that in 3D-View */ - if (ptr) RNA_id_pointer_create(&ob->id, ptr); - return &ob->gpd; + BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src, + GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT)); + + if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) { + /* legacy behaviour for usage with old addons requiring object-linked to objects */ + + /* just in case no active/selected object... */ + if (ob && (ob->flag & SELECT)) { + /* for now, as long as there's an object, default to using that in 3D-View */ + if (ptr) RNA_id_pointer_create(&ob->id, ptr); + return &ob->gpd; + } + /* else: defaults to scene... */ + } + else { + if (ptr) RNA_id_pointer_create(&scene->id, ptr); + return &scene->gpd; } break; } case SPACE_NODE: /* Nodes Editor */ { - SpaceNode *snode = (SpaceNode *)CTX_wm_space_data(C); - + SpaceNode *snode = (SpaceNode *)sl; + /* return the GP data for the active node block/node */ if (snode && snode->nodetree) { /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */ if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr); return &snode->nodetree->gpd; } - + /* even when there is no node-tree, don't allow this to flow to scene */ return NULL; } case SPACE_SEQ: /* Sequencer */ { - SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C); - + SpaceSeq *sseq = (SpaceSeq *)sl; + /* for now, Grease Pencil data is associated with the space (actually preview region only) */ /* XXX our convention for everything else is to link to data though... */ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr); @@ -137,8 +147,8 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) } case SPACE_IMAGE: /* Image/UV Editor */ { - SpaceImage *sima = (SpaceImage *)CTX_wm_space_data(C); - + SpaceImage *sima = (SpaceImage *)sl; + /* for now, Grease Pencil data is associated with the space... */ /* XXX our convention for everything else is to link to data though... */ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr); @@ -146,25 +156,25 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) } case SPACE_CLIP: /* Nodes Editor */ { - SpaceClip *sc = (SpaceClip *)CTX_wm_space_data(C); + SpaceClip *sc = (SpaceClip *)sl; MovieClip *clip = ED_space_clip_get_clip(sc); - + if (clip) { if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking); - + if (!track) return NULL; - + if (ptr) RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr); - + return &track->gpd; } else { if (ptr) RNA_id_pointer_create(&clip->id, ptr); - + return &clip->gpd; } } @@ -174,12 +184,32 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) return NULL; } } - + /* just fall back on the scene's GP data */ if (ptr) RNA_id_pointer_create((ID *)scene, ptr); return (scene) ? &scene->gpd : NULL; } +/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */ +bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) +{ + ID *screen_id = (ID *)CTX_wm_screen(C); + Scene *scene = CTX_data_scene(C); + ScrArea *sa = CTX_wm_area(C); + Object *ob = CTX_data_active_object(C); + + return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr); +} + +/* -------------------------------------------------------- */ + +/* Get the active Grease Pencil datablock, when context is not available */ +bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob) +{ + bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL); + return (gpd_ptr) ? *(gpd_ptr) : NULL; +} + /* Get the active Grease Pencil datablock */ bGPdata *ED_gpencil_data_get_active(const bContext *C) { @@ -187,6 +217,9 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C) return (gpd_ptr) ? *(gpd_ptr) : NULL; } +/* -------------------------------------------------------- */ + +// XXX: this should be removed... We really shouldn't duplicate logic like this! bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d) { Base *base = scene->basact; @@ -194,7 +227,7 @@ bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d) /* We have to make sure active object is actually visible and selected, else we must use default scene gpd, * to be consistent with ED_gpencil_data_get_active's behavior. */ - + if (base && TESTBASE(v3d, base)) { gpd = base->object->gpd; } @@ -211,13 +244,22 @@ static int gp_add_poll(bContext *C) return ED_gpencil_data_get_pointers(C, NULL) != NULL; } +/* poll callback for checking if there is an active layer */ +static int gp_active_layer_poll(bContext *C) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + + return (gpl != NULL); +} + /* ******************* Add New Data ************************ */ /* add new datablock - wrapper around API */ static int gp_data_add_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); return OPERATOR_CANCELLED; @@ -225,14 +267,14 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) else { /* decrement user count and add new datablock */ bGPdata *gpd = (*gpd_ptr); - + id_us_min(&gpd->id); *gpd_ptr = gpencil_data_addnew(DATA_("GPencil")); } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -243,7 +285,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot) ot->idname = "GPENCIL_OT_data_add"; ot->description = "Add new Grease Pencil datablock"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_data_add_exec; ot->poll = gp_add_poll; @@ -255,7 +297,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot) static int gp_data_unlink_poll(bContext *C) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + /* if we have access to some active data, make sure there's a datablock before enabling this */ return (gpd_ptr && *gpd_ptr); } @@ -265,7 +307,7 @@ static int gp_data_unlink_poll(bContext *C) static int gp_data_unlink_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); return OPERATOR_CANCELLED; @@ -277,10 +319,10 @@ static int gp_data_unlink_exec(bContext *C, wmOperator *op) id_us_min(&gpd->id); *gpd_ptr = NULL; } - + /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; } @@ -291,7 +333,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) ot->idname = "GPENCIL_OT_data_unlink"; ot->description = "Unlink active Grease Pencil datablock"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_data_unlink_exec; ot->poll = gp_data_unlink_poll; @@ -303,7 +345,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) static int gp_layer_add_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + /* if there's no existing Grease-Pencil data there, add some */ if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); @@ -311,13 +353,13 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op) } if (*gpd_ptr == NULL) *gpd_ptr = gpencil_data_addnew(DATA_("GPencil")); - + /* add new layer now */ gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1); - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -327,20 +369,497 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot) ot->name = "Add New Layer"; ot->idname = "GPENCIL_OT_layer_add"; ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_layer_add_exec; ot->poll = gp_add_poll; } +/* ******************* Remove Active Layer ************************* */ + +static int gp_layer_remove_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + + /* sanity checks */ + if (ELEM(NULL, gpd, gpl)) + return OPERATOR_CANCELLED; + + if (gpl->flag & GP_LAYER_LOCKED) { + BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers"); + return OPERATOR_CANCELLED; + } + + /* make the layer before this the new active layer + * - use the one after if this is the first + * - if this is the only layer, this naturally becomes NULL + */ + if (gpl->prev) + gpencil_layer_setactive(gpd, gpl->prev); + else + gpencil_layer_setactive(gpd, gpl->next); + + /* delete the layer now... */ + gpencil_layer_delete(gpd, gpl); + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_layer_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Layer"; + ot->idname = "GPENCIL_OT_layer_remove"; + ot->description = "Remove active Grease Pencil layer"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* callbacks */ + ot->exec = gp_layer_remove_exec; + ot->poll = gp_active_layer_poll; +} + +/* ******************* Move Layer Up/Down ************************** */ + +enum { + GP_LAYER_MOVE_UP = -1, + GP_LAYER_MOVE_DOWN = 1 +}; + +static int gp_layer_move_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + + int direction = RNA_enum_get(op->ptr, "type"); + + /* sanity checks */ + if (ELEM(NULL, gpd, gpl)) + return OPERATOR_CANCELLED; + + /* up or down? */ + if (direction == GP_LAYER_MOVE_UP) { + /* up */ + BLI_remlink(&gpd->layers, gpl); + BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl); + } + else { + /* down */ + BLI_remlink(&gpd->layers, gpl); + BLI_insertlinkafter(&gpd->layers, gpl->next, gpl); + } + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_layer_move(wmOperatorType *ot) +{ + static EnumPropertyItem slot_move[] = { + {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""}, + {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Move Grease Pencil Layer"; + ot->idname = "GPENCIL_OT_layer_move"; + ot->description = "Move the active Grease Pencil layer up/down in the list"; + + /* api callbacks */ + ot->exec = gp_layer_move_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", ""); +} + +/* ********************* Duplicate Layer ************************** */ + +static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + bGPDlayer *new_layer; + + /* sanity checks */ + if (ELEM(NULL, gpd, gpl)) + return OPERATOR_CANCELLED; + + /* make copy of layer, and add it immediately after the existing layer */ + new_layer = gpencil_layer_duplicate(gpl); + BLI_insertlinkafter(&gpd->layers, gpl, new_layer); + + /* ensure new layer has a unique name, and is now the active layer */ + BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info)); + gpencil_layer_setactive(gpd, new_layer); + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_layer_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Layer"; + ot->idname = "GPENCIL_OT_layer_duplicate"; + ot->description = "Make a copy of the active Grease Pencil layer"; + + /* callbacks */ + ot->exec = gp_layer_copy_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ************************************************ */ +/* Stroke Editing Operators */ + +/* poll callback for all stroke editing operators */ +static int gp_stroke_edit_poll(bContext *C) +{ + /* NOTE: this is a bit slower, but is the most accurate... */ + return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0; +} + +/* ************** Duplicate Selected Strokes **************** */ + +/* Make copies of selected point segments in a selected stroke */ +static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes) +{ + bGPDspoint *pt; + int i; + + int start_idx = -1; + + + /* Step through the original stroke's points: + * - We accumulate selected points (from start_idx to current index) + * and then convert that to a new stroke + */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + /* searching for start, are waiting for end? */ + if (start_idx == -1) { + /* is this the first selected point for a new island? */ + if (pt->flag & GP_SPOINT_SELECT) { + start_idx = i; + } + } + else { + size_t len = 0; + + /* is this the end of current island yet? + * 1) Point i-1 was the last one that was selected + * 2) Point i is the last in the array + */ + if ((pt->flag & GP_SPOINT_SELECT) == 0) { + len = i - start_idx; + } + else if (i == gps->totpoints - 1) { + len = i - start_idx + 1; + } + //printf("copying from %d to %d = %d\n", start_idx, i, len); + + /* make copies of the relevant data */ + if (len) { + bGPDstroke *gpsd; + + /* make a stupid copy first of the entire stroke (to get the flags too) */ + gpsd = MEM_dupallocN(gps); + + /* now, make a new points array, and copy of the relevant parts */ + gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy"); + memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len); + gpsd->totpoints = len; + + /* add to temp buffer */ + gpsd->next = gpsd->prev = NULL; + BLI_addtail(new_strokes, gpsd); + + /* cleanup + reset for next */ + start_idx = -1; + } + } + } +} + +static int gp_duplicate_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + + /* for each visible (and editable) layer's selected strokes, + * copy the strokes into a temporary buffer, then append + * once all done + */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + ListBase new_strokes = {NULL, NULL}; + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps; + + if (gpf == NULL) + continue; + + /* make copies of selected strokes, and deselect these once we're done */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + if (gps->flag & GP_STROKE_SELECT) { + if (gps->totpoints == 1) { + /* Special Case: If there's just a single point in this stroke... */ + bGPDstroke *gpsd; + + /* make direct copies of the stroke and its points */ + gpsd = MEM_dupallocN(gps); + gpsd->points = MEM_dupallocN(gps->points); + + /* add to temp buffer */ + gpsd->next = gpsd->prev = NULL; + BLI_addtail(&new_strokes, gpsd); + } + else { + /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */ + gp_duplicate_points(gps, &new_strokes); + } + + /* deselect original stroke, or else the originals get moved too + * (when using the copy + move macro) + */ + gps->flag &= ~GP_STROKE_SELECT; + } + } + + /* add all new strokes in temp buffer to the frame (preventing double-copies) */ + BLI_movelisttolist(&gpf->strokes, &new_strokes); + BLI_assert(new_strokes.first == NULL); + } + CTX_DATA_END; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Strokes"; + ot->idname = "GPENCIL_OT_duplicate"; + ot->description = "Duplicate the selected Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gp_duplicate_exec; + ot->poll = gp_stroke_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ******************* Copy/Paste Strokes ************************* */ +/* Grease Pencil stroke data copy/paste buffer: + * - The copy operation collects all segments of selected strokes, + * dumping "ready to be copied" copies of the strokes into the buffer. + * - The paste operation makes a copy of those elements, and adds them + * to the active layer. This effectively flattens down the strokes + * from several different layers into a single layer. + */ + +/* list of bGPDstroke instances */ +static ListBase gp_strokes_copypastebuf = {NULL, NULL}; + +/* Free copy/paste buffer data */ +void ED_gpencil_strokes_copybuf_free(void) +{ + bGPDstroke *gps, *gpsn; + + for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) { + gpsn = gps->next; + + MEM_freeN(gps->points); + BLI_freelinkN(&gp_strokes_copypastebuf, gps); + } + + gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL; +} + +/* --------------------- */ +/* Copy selected strokes */ + +static int gp_strokes_copy_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + + /* clear the buffer first */ + ED_gpencil_strokes_copybuf_free(); + + /* for each visible (and editable) layer's selected strokes, + * copy the strokes into a temporary buffer, then append + * once all done + */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps; + + if (gpf == NULL) + continue; + + /* make copies of selected strokes, and deselect these once we're done */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + if (gps->flag & GP_STROKE_SELECT) { + if (gps->totpoints == 1) { + /* Special Case: If there's just a single point in this stroke... */ + bGPDstroke *gpsd; + + /* make direct copies of the stroke and its points */ + gpsd = MEM_dupallocN(gps); + gpsd->points = MEM_dupallocN(gps->points); + + /* add to temp buffer */ + gpsd->next = gpsd->prev = NULL; + BLI_addtail(&gp_strokes_copypastebuf, gpsd); + } + else { + /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */ + gp_duplicate_points(gps, &gp_strokes_copypastebuf); + } + } + } + } + CTX_DATA_END; + + /* done - no updates needed */ + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_copy(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Copy Strokes"; + ot->idname = "GPENCIL_OT_copy"; + ot->description = "Copy selected Grease Pencil points and strokes"; + + /* callbacks */ + ot->exec = gp_strokes_copy_exec; + ot->poll = gp_stroke_edit_poll; + + /* flags */ + //ot->flag = OPTYPE_REGISTER; +} + +/* --------------------- */ +/* Paste selected strokes */ + +static int gp_strokes_paste_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + bGPDframe *gpf; + + /* check for various error conditions */ + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + else if (gp_strokes_copypastebuf.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again"); + return OPERATOR_CANCELLED; + } + else if (gpl == NULL) { + /* no active layer - let's just create one */ + gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), 1); + } + else if (gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) { + BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked"); + return OPERATOR_CANCELLED; + } + + /* Deselect all strokes first */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + + gps->flag &= ~GP_STROKE_SELECT; + } + CTX_DATA_END; + + /* Ensure we have a frame to draw into + * NOTE: Since this is an op which creates strokes, + * we are obliged to add a new frame if one + * doesn't exist already + */ + gpf = gpencil_layer_getframe(gpl, CFRA, true); + + if (gpf) { + bGPDstroke *gps; + + /* Copy each stroke into the layer */ + for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { + bGPDstroke *new_stroke = MEM_dupallocN(gps); + + new_stroke->points = MEM_dupallocN(gps->points); + new_stroke->next = new_stroke->prev = NULL; + + BLI_addtail(&gpf->strokes, new_stroke); + } + } + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_paste(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Paste Strokes"; + ot->idname = "GPENCIL_OT_paste"; + ot->description = "Paste previously copied strokes into active layer"; + + /* callbacks */ + ot->exec = gp_strokes_paste_exec; + ot->poll = gp_stroke_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ******************* Delete Active Frame ************************ */ static int gp_actframe_delete_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = gpencil_layer_getactive(gpd); - + /* only if there's an active layer with an active frame */ return (gpl && gpl->actframe); } @@ -352,7 +871,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = gpencil_layer_getactive(gpd); bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); - + /* if there's no existing Grease-Pencil data there, add some */ if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No grease pencil data"); @@ -362,13 +881,13 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No active frame to delete"); return OPERATOR_CANCELLED; } - + /* delete it... */ gpencil_layer_delframe(gpl, gpf); - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -378,13 +897,315 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) ot->name = "Delete Active Frame"; ot->idname = "GPENCIL_OT_active_frame_delete"; ot->description = "Delete the active frame for the active Grease Pencil datablock"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_actframe_delete_exec; ot->poll = gp_actframe_delete_poll; } +/* ******************* Delete Operator ************************ */ + +typedef enum eGP_DeleteMode { + /* delete selected stroke points */ + GP_DELETEOP_POINTS = 0, + /* delete selected strokes */ + GP_DELETEOP_STROKES = 1, + /* delete active frame */ + GP_DELETEOP_FRAME = 2, + /* delete selected stroke points (without splitting stroke) */ + GP_DELETEOP_POINTS_DISSOLVE = 3, +} eGP_DeleteMode; + + +/* Delete selected strokes */ +static int gp_delete_selected_strokes(bContext *C) +{ + bool changed = false; + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps, *gpsn; + + if (gpf == NULL) + continue; + + /* simply delete strokes which are selected */ + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + if (gps->flag & GP_STROKE_SELECT) { + /* free stroke memory arrays, then stroke itself */ + if (gps->points) MEM_freeN(gps->points); + BLI_freelinkN(&gpf->strokes, gps); + + changed = true; + } + } + } + CTX_DATA_END; + + if (changed) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +/* Delete selected points but keep the stroke */ +static int gp_dissolve_selected_points(bContext *C) +{ + bool changed = false; + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps, *gpsn; + + if (gpf == NULL) + continue; + + /* simply delete points from selected strokes + * NOTE: we may still have to remove the stroke if it ends up having no points! + */ + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + int tot = gps->totpoints; /* number of points in new buffer */ + + /* First Pass: Count how many points are selected (i.e. how many to remove) */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + /* selected point - one of the points to remove */ + tot--; + } + } + + /* if no points are left, we simply delete the entire stroke */ + if (tot <= 0) { + /* remove the entire stroke */ + MEM_freeN(gps->points); + BLI_freelinkN(&gpf->strokes, gps); + } + else { + /* just copy all unselected into a smaller buffer */ + bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy"); + bGPDspoint *npt = new_points; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if ((pt->flag & GP_SPOINT_SELECT) == 0) { + *npt = *pt; + npt++; + } + } + + /* free the old buffer */ + MEM_freeN(gps->points); + + /* save the new buffer */ + gps->points = new_points; + gps->totpoints = tot; + + /* deselect the stroke, since none of its selected points will still be selected */ + gps->flag &= ~GP_STROKE_SELECT; + } + + changed = true; + } + } + } + CTX_DATA_END; + + if (changed) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +/* Split selected strokes into segments, splitting on selected points */ +static int gp_delete_selected_points(bContext *C) +{ + bool changed = false; + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps, *gpsn; + + if (gpf == NULL) + continue; + + /* simply delete strokes which are selected */ + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + /* The algorithm used here is as follows: + * 1) We firstly identify the number of "islands" of non-selected points + * which will all end up being in new strokes. + * - In the most extreme case (i.e. every other vert is a 1-vert island), + * we have at most n / 2 islands + * - Once we start having larger islands than that, the number required + * becomes much less + * 2) Each island gets converted to a new stroke + */ + typedef struct tGPDeleteIsland { + int start_idx; + int end_idx; + } tGPDeleteIsland; + + tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); + bool in_island = false; + int num_islands = 0; + + /* First Pass: Identify start/end of islands */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + /* selected - stop accumulating to island */ + in_island = false; + } + else { + /* unselected - start of a new island? */ + int idx; + + if (in_island) { + /* extend existing island */ + idx = num_islands - 1; + islands[idx].end_idx = i; + } + else { + /* start of new island */ + in_island = true; + num_islands++; + + idx = num_islands - 1; + islands[idx].start_idx = islands[idx].end_idx = i; + } + } + } + + /* Watch out for special case where No islands = All points selected = Delete Stroke only */ + if (num_islands) { + /* there are islands, so create a series of new strokes, adding them before the "next" stroke */ + int idx; + + /* deselect old stroke, since it will be used as template for the new strokes */ + gps->flag &= ~GP_STROKE_SELECT; + + /* create each new stroke... */ + for (idx = 0; idx < num_islands; idx++) { + tGPDeleteIsland *island = &islands[idx]; + bGPDstroke *new_stroke = MEM_dupallocN(gps); + + /* compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */ + new_stroke->totpoints = island->end_idx - island->start_idx + 1; + new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment"); + + /* copy over the relevant points */ + memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints); + + /* add new stroke to the frame */ + if (gpsn) { + BLI_insertlinkbefore(&gpf->strokes, gpsn, new_stroke); + } + else { + BLI_addtail(&gpf->strokes, new_stroke); + } + } + } + + /* free islands */ + MEM_freeN(islands); + + /* Delete the old stroke */ + MEM_freeN(gps->points); + BLI_freelinkN(&gpf->strokes, gps); + + changed = true; + } + } + } + CTX_DATA_END; + + if (changed) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + + +static int gp_delete_exec(bContext *C, wmOperator *op) +{ + eGP_DeleteMode mode = RNA_enum_get(op->ptr, "type"); + int result = OPERATOR_CANCELLED; + + switch (mode) { + case GP_DELETEOP_STROKES: /* selected strokes */ + result = gp_delete_selected_strokes(C); + break; + + case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */ + result = gp_delete_selected_points(C); + break; + + case GP_DELETEOP_POINTS_DISSOLVE: /* selected points (without splitting the stroke) */ + result = gp_dissolve_selected_points(C); + break; + + case GP_DELETEOP_FRAME: /* active frame */ + result = gp_actframe_delete_exec(C, op); + break; + } + + return result; +} + +void GPENCIL_OT_delete(wmOperatorType *ot) +{ + static EnumPropertyItem prop_gpencil_delete_types[] = { + {GP_DELETEOP_POINTS, "POINTS", 0, "Points", "Delete selected points and split strokes into segments"}, + {GP_DELETEOP_STROKES, "STROKES", 0, "Strokes", "Delete selected strokes"}, + {GP_DELETEOP_FRAME, "FRAME", 0, "Frame", "Delete active frame"}, + {0, "", 0, NULL, NULL}, + {GP_DELETEOP_POINTS_DISSOLVE, "DISSOLVE_POINTS", 0, "Dissolve Points", + "Delete selected points without splitting strokes"}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Delete..."; + ot->idname = "GPENCIL_OT_delete"; + ot->description = "Delete selected Grease Pencil strokes, vertices, or frames"; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = gp_delete_exec; + ot->poll = gp_stroke_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* props */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_delete_types, 0, "Type", "Method used for deleting Grease Pencil data"); +} + /* ************************************************ */ /* Grease Pencil to Data Operator */ @@ -437,7 +1258,7 @@ static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRN /* --- */ -/* convert the coordinates from the given stroke point into 3d-coordinates +/* convert the coordinates from the given stroke point into 3d-coordinates * - assumes that the active space is the 3D-View */ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect) @@ -445,7 +1266,7 @@ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoin Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - + if (gps->flag & GP_STROKE_3DSPACE) { /* directly use 3d-coordinates */ copy_v3_v3(p3d, &pt->x); @@ -453,7 +1274,7 @@ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoin else { const float *fp = ED_view3d_cursor3d_get(scene, v3d); float mvalf[2]; - + /* get screen coordinate */ if (gps->flag & GP_STROKE_2DSPACE) { View2D *v2d = &ar->v2d; @@ -469,7 +1290,7 @@ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoin mvalf[1] = (float)pt->y / 100.0f * ar->winy; } } - + ED_view3d_win_to_3d(ar, fp, mvalf, p3d); } } @@ -485,19 +1306,19 @@ typedef struct tGpTimingData { bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */ float gap_duration, gap_randomness; /* To be used with CustomGap mode*/ int seed; - + /* Data set from points, used to compute final timing FCurve */ int num_points, cur_point; - + /* Distances */ float *dists; float tot_dist; - + /* Times */ float *times; /* Note: Gap times will be negative! */ float tot_time, gap_tot_time; double inittime; - + /* Only used during creation of dists & times lists. */ float offset_time; } tGpTimingData; @@ -508,9 +1329,9 @@ typedef struct tGpTimingData { static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) { float *tmp; - + BLI_assert(nbr > gtd->num_points); - + /* distances */ tmp = gtd->dists; gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__); @@ -518,7 +1339,7 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points); MEM_freeN(tmp); } - + /* times */ tmp = gtd->times; gtd->times = MEM_callocN(sizeof(float) * nbr, __func__); @@ -526,7 +1347,7 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points); MEM_freeN(tmp); } - + gtd->num_points = nbr; } @@ -536,7 +1357,7 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_ini { float delta_time = 0.0f; const int cur_point = gtd->cur_point; - + if (!cur_point) { /* Special case, first point, if time is not 0.0f we have to compensate! */ gtd->offset_time = -time; @@ -546,18 +1367,18 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_ini /* This is a gap, negative value! */ gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time); delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1]; - + gtd->gap_tot_time += delta_time; } else { gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time); delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]); } - + gtd->tot_time += delta_time; gtd->tot_dist += delta_dist; gtd->dists[cur_point] = gtd->tot_dist; - + gtd->cur_point++; } @@ -572,7 +1393,7 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx float *next_delta_time) { int j; - + for (j = idx + 1; j < gtd->num_points; j++) { if (gtd->times[j] < 0) { gtd->times[j] = -gtd->times[j]; @@ -591,16 +1412,16 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx } else { float delta, min, max; - + /* This code ensures that if the first gaps have been shorter than average gap_duration, * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa! */ delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps)); - + /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */ min = -gtd->gap_randomness - delta; CLAMP(min, -gtd->gap_randomness, 0.0f); - + /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */ max = gtd->gap_randomness - delta; CLAMP(max, 0.0f, gtd->gap_randomness); @@ -615,7 +1436,7 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx break; } } - + return j - 1; } @@ -623,7 +1444,7 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rn { int i; float delta_time = 0.0f; - + for (i = 0; i < gtd->num_points; i++) { if (gtd->times[i] < 0 && i) { (*nbr_gaps)++; @@ -636,7 +1457,7 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rn } } gtd->tot_time -= delta_time; - + *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration; gtd->tot_time += *tot_gaps_time; if (G.debug & G_DEBUG) { @@ -653,18 +1474,18 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR { /* Use actual recorded timing! */ const float time_start = (float)gtd->start_frame; - + float last_valid_time = 0.0f; int end_stroke_idx = -1, start_stroke_idx = 0; float end_stroke_time = 0.0f; - + /* CustomGaps specific */ float delta_time = 0.0f, next_delta_time = 0.0f; int nbr_done_gaps = 0; - + int i; float cfra; - + /* This is a bit tricky, as: * - We can't add arbitrarily close points on FCurve (in time). * - We *must* have all "caps" points of all strokes in FCurve, as much as possible! @@ -680,11 +1501,11 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR /* This one should *never* be negative! */ end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range); } - + /* Simple proportional stuff... */ cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen; cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range); - + /* And now, the checks about timing... */ if (i == start_stroke_idx) { /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and @@ -735,43 +1556,43 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu PointerRNA ptr; PropertyRNA *prop = NULL; int nbr_gaps = 0, i; - + if (gtd->mode == GP_STROKECONVERT_TIMING_NONE) return; - + /* gap_duration and gap_randomness are in frames, but we need seconds!!! */ gtd->gap_duration = FRA2TIME(gtd->gap_duration); gtd->gap_randomness = FRA2TIME(gtd->gap_randomness); - + /* Enable path! */ cu->flag |= CU_PATH; cu->pathlen = gtd->frame_range; - + /* Get RNA pointer to read/write path time values */ RNA_id_pointer_create((ID *)cu, &ptr); prop = RNA_struct_find_property(&ptr, "eval_time"); - + /* Ensure we have an F-Curve to add keyframes to */ act = verify_adt_action((ID *)cu, true); fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true); - + if (G.debug & G_DEBUG) { printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); for (i = 0; i < gtd->num_points; i++) { printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); } } - + if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) { float cfra; - + /* Linear extrapolation! */ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; - + cu->ctime = 0.0f; cfra = (float)gtd->start_frame; insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST); - + cu->ctime = cu->pathlen; if (gtd->realtime) { cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ @@ -785,35 +1606,35 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu /* Use actual recorded timing! */ RNG *rng = BLI_rng_new(0); float time_range; - + /* CustomGaps specific */ float tot_gaps_time = 0.0f; - + /* Pre-process gaps, in case we don't want to keep their original timing */ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time); } - + if (gtd->realtime) { time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ } else { time_range = (float)(gtd->end_frame - gtd->start_frame); } - + if (G.debug & G_DEBUG) { printf("GP Stroke Path Conversion: Starting keying!\n"); } - + gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range, nbr_gaps, tot_gaps_time); - + BLI_rng_free(rng); } - + /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */ calchandles_fcurve(fcu); - + if (G.debug & G_DEBUG) { printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); for (i = 0; i < gtd->num_points; i++) { @@ -821,9 +1642,9 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu } printf("\n\n"); } - + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - + /* send updates */ DAG_id_tag_update(&cu->id, 0); } @@ -843,7 +1664,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl { copy_v3_v3(bp->vec, p); bp->vec[3] = 1.0f; - + /* set settings */ bp->f1 = SELECT; bp->radius = width * rad_fac; @@ -855,7 +1676,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl else if (bp->weight > minmax_weights[1]) { minmax_weights[1] = bp->weight; } - + /* Update timing data */ if (do_gtd) { gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); @@ -872,7 +1693,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE); const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0); int i, old_nbp = 0; - + /* create new 'nurb' or extend current one within the curve */ if (nu) { old_nbp = nu->pntsu; @@ -884,7 +1705,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv } else { nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)"); - + nu->pntsu = gps->totpoints + add_start_end_points; nu->pntsv = 1; nu->orderu = 2; /* point-to-point! */ @@ -893,16 +1714,16 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv nu->resolu = cu->resolu; nu->resolv = cu->resolv; nu->knotsu = NULL; - + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints"); - + stitch = false; /* Security! */ } - + if (do_gtd) { gp_timing_data_set_nbr(gtd, nu->pntsu); } - + /* If needed, make the link between both strokes with two zero-radius additional points */ /* About "zero-radius" point interpolations: * - If we have at least two points in current curve (most common case), we linearly extrapolate @@ -915,16 +1736,16 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv if (curnu && !stitch && old_nbp) { float p1[3], p2[3], p[3], next_p[3]; float dt1 = 0.0f, dt2 = 0.0f; - + BLI_assert(gps->prev != NULL); - + prev_bp = NULL; if ((old_nbp > 1) && (gps->prev->totpoints > 1)) { /* Only use last curve segment if previous stroke was not a single-point one! */ prev_bp = &nu->bp[old_nbp - 2]; } bp = &nu->bp[old_nbp - 1]; - + /* First point */ gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect); if (prev_bp) { @@ -943,7 +1764,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv bp++; gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1, 0.0f, rad_fac, minmax_weights); - + /* Second point */ /* Note dt2 is always negative, which marks the gap. */ if (gps->totpoints > 1) { @@ -961,13 +1782,13 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv } bp++; gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights); - + old_nbp += 2; } else if (add_start_point) { float p[3], next_p[3]; float dt = 0.0f; - + gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect); if (gps->totpoints > 1) { gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect); @@ -985,14 +1806,14 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv * would not work (it would be *before* gtd->inittime, which is not supported currently). */ gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); - + old_nbp++; } - + if (old_nbp) { prev_bp = &nu->bp[old_nbp - 1]; } - + /* add points */ for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp]; i < gps->totpoints; @@ -1000,20 +1821,20 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv { float p[3]; float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC; - + /* get coordinates to add at */ gp_strokepoint_convertcoords(C, gps, pt, p, subrect); - + gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights); - + prev_bp = bp; } if (add_end_point) { float p[3]; float dt = 0.0f; - + if (gps->totpoints > 1) { interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC); if (do_gtd) { @@ -1029,7 +1850,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv /* Note bp has already been incremented in main loop above, so it points to the right place. */ gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); } - + /* add nurb to curve */ if (!curnu || !*curnu) { BLI_addtail(&cu->nurb, nu); @@ -1037,7 +1858,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv if (curnu) { *curnu = nu; } - + BKE_nurb_knot_calc_u(nu); } @@ -1052,7 +1873,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt, copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p); copy_v3_v3(bezt->vec[2], h2); - + /* set settings */ bezt->h1 = bezt->h2 = HD_FREE; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; @@ -1065,7 +1886,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt, else if (bezt->weight > minmax_weights[1]) { minmax_weights[1] = bezt->weight; } - + /* Update timing data */ if (do_gtd) { gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); @@ -1073,8 +1894,8 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt, } static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, - float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point, - const bool add_end_point, tGpTimingData *gtd) + float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point, + const bool add_end_point, tGpTimingData *gtd) { bGPDspoint *pt; Nurb *nu = (curnu) ? *curnu : NULL; @@ -1083,7 +1904,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0); float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3]; const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE); - + /* create new 'nurb' or extend current one within the curve */ if (nu) { old_nbezt = nu->pntsu; @@ -1095,22 +1916,22 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu } else { nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); - + nu->pntsu = gps->totpoints + add_start_end_points; nu->resolu = 12; nu->resolv = 12; nu->type = CU_BEZIER; nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts"); - + stitch = false; /* Security! */ } - + if (do_gtd) { gp_timing_data_set_nbr(gtd, nu->pntsu); } - + tot = gps->totpoints; - + /* get initial coordinates */ pt = gps->points; if (tot) { @@ -1122,11 +1943,11 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } } - + /* If needed, make the link between both strokes with two zero-radius additional points */ if (curnu && old_nbezt) { BLI_assert(gps->prev != NULL); - + /* Update last point's second handle */ if (stitch) { bezt = &nu->bezt[old_nbezt - 1]; @@ -1134,7 +1955,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu copy_v3_v3(bezt->vec[2], h2); pt++; } - + /* Create "link points" */ /* About "zero-radius" point interpolations: * - If we have at least two points in current curve (most common case), we linearly extrapolate @@ -1147,14 +1968,14 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu else { float p1[3], p2[3]; float dt1 = 0.0f, dt2 = 0.0f; - + prev_bezt = NULL; if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) { /* Only use last curve segment if previous stroke was not a single-point one! */ prev_bezt = &nu->bezt[old_nbezt - 2]; } bezt = &nu->bezt[old_nbezt - 1]; - + /* First point */ if (prev_bezt) { interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC); @@ -1169,7 +1990,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC); } } - + /* Second point */ /* Note dt2 is always negative, which marks the gap. */ if (tot > 1) { @@ -1184,25 +2005,25 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC); } } - + /* Second handle of last point of previous stroke. */ interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC); copy_v3_v3(bezt->vec[2], h2); - + /* First point */ interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC); bezt++; gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1, 0.0f, rad_fac, minmax_weights); - + /* Second point */ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC); bezt++; gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights); - + old_nbezt += 2; copy_v3_v3(p3d_prev, p2); } @@ -1210,7 +2031,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu else if (add_start_point) { float p[3]; float dt = 0.0f; - + if (gps->totpoints > 1) { interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC); if (do_gtd) { @@ -1227,51 +2048,51 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu bezt = &nu->bezt[old_nbezt]; gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); - + old_nbezt++; copy_v3_v3(p3d_prev, p); } - + if (old_nbezt) { prev_bezt = &nu->bezt[old_nbezt - 1]; } - + /* add points */ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) { float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC; - + if (i || old_nbezt) { interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC); } - + if (i < tot - 1) { interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC); } - + gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur, do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights); - + /* shift coord vects */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); - + if (i + 2 < tot) { gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } - + prev_bezt = bezt; } if (add_end_point) { float p[3]; float dt = 0.0f; - + if (gps->totpoints > 1) { interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC); if (do_gtd) { @@ -1284,11 +2105,11 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu p[0] += GAP_DFAC; /* Rather arbitrary... */ dt = GAP_DFAC; /* Rather arbitrary too! */ } - + /* Second handle of last point of this stroke. */ interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC); copy_v3_v3(prev_bezt->vec[2], h2); - + /* The end point */ interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC); @@ -1296,10 +2117,10 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); } - + /* must calculate handles or else we crash */ BKE_nurb_handles_calc(nu); - + if (!curnu || !*curnu) { BLI_addtail(&cu->nurb, nu); } @@ -1329,7 +2150,7 @@ static void gp_stroke_finalize_curve_endpoints(Curve *cu) bp[i].weight = bp[i].radius = 0.0f; } } - + /* end */ nu = cu->nurb.last; i = nu->pntsu - 1; @@ -1353,13 +2174,13 @@ static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2 const float delta = minmax_weights[0]; float fac; int i; - + /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */ if (IS_EQF(delta, minmax_weights[1])) fac = 1.0f; else fac = 1.0f / (minmax_weights[1] - delta); - + for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->bezt) { BezTriple *bezt = nu->bezt; @@ -1380,10 +2201,10 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) { View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - + if (v3d) { RegionView3D *rv3d = ar->regiondata; - + /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { Scene *scene = CTX_data_scene(C); @@ -1391,7 +2212,7 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) return 1; } } - + return 0; } @@ -1409,57 +2230,57 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG Nurb *nu = NULL; Base *base_orig = BASACT, *base_new = NULL; float minmax_weights[2] = {1.0f, 0.0f}; - + /* camera framing */ rctf subrect, *subrect_ptr = NULL; - + /* error checking */ if (ELEM(NULL, gpd, gpl, gpf)) return; - + /* only convert if there are any strokes on this layer's frame to convert */ if (BLI_listbase_is_empty(&gpf->strokes)) return; - + /* initialize camera framing */ if (gp_camera_view_subrect(C, &subrect)) { subrect_ptr = &subrect; } - + /* init the curve object (remove rotation and get curve data from it) * - must clear transforms set on object, as those skew our results */ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info); cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE); base_new = BKE_scene_base_add(scene, ob); - + cu->flag |= CU_3D; - + gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime; - + /* add points to curve */ for (gps = gpf->strokes.first; gps; gps = gps->next) { const bool add_start_point = (link_strokes && !(prev_gps)); const bool add_end_point = (link_strokes && !(gps->next)); - + /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */ bool stitch = false; if (prev_gps) { bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1]; bGPDspoint *pt2 = &gps->points[0]; - + if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) { stitch = true; } } - + /* Decide whether we connect this stroke to previous one */ if (!(stitch || link_strokes)) { nu = NULL; } - + switch (mode) { - case GP_STROKECONVERT_PATH: + case GP_STROKECONVERT_PATH: gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, add_start_point, add_end_point, gtd); break; @@ -1474,26 +2295,26 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG } prev_gps = gps; } - + /* If link_strokes, be sure first and last points have a zero weight/size! */ if (link_strokes) { gp_stroke_finalize_curve_endpoints(cu); } - + /* Update curve's weights, if needed */ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) { gp_stroke_norm_curve_weights(cu, minmax_weights); } - + /* Create the path animation, if needed */ gp_stroke_path_animation(C, reports, cu, gtd); - + if (mode == GP_STROKECONVERT_POLY) { for (nu = cu->nurb.first; nu; nu = nu->next) { BKE_nurb_type_convert(nu, CU_POLY, false); } } - + /* set the layer and select */ base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene); base_new->flag = ob->flag = base_new->flag | SELECT; @@ -1513,17 +2334,17 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe double base_time, cur_time, prev_time = -1.0; int i; bool valid = true; - + if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first)) return false; - + do { base_time = cur_time = gps->inittime; if (cur_time <= prev_time) { valid = false; break; } - + prev_time = cur_time; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { cur_time = base_time + (double)pt->time; @@ -1536,12 +2357,12 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe } prev_time = cur_time; } - + if (!valid) { break; } } while ((gps = gps->next)); - + if (op) { RNA_boolean_set(op->ptr, "use_timing_data", valid); } @@ -1553,7 +2374,7 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UN { int start_frame = RNA_int_get(ptr, "start_frame"); int end_frame = RNA_int_get(ptr, "end_frame"); - + if (end_frame <= start_frame) { RNA_int_set(ptr, "end_frame", start_frame + 1); } @@ -1566,7 +2387,7 @@ static int gp_convert_poll(bContext *C) bGPDframe *gpf = NULL; ScrArea *sa = CTX_wm_area(C); Scene *scene = CTX_data_scene(C); - + /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!), * and if we are not in edit mode! */ @@ -1589,19 +2410,19 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes"); bool valid_timing; tGpTimingData gtd; - + /* check if there's data to work with */ if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on"); return OPERATOR_CANCELLED; } - + if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) { BKE_report(op->reports, RPT_WARNING, "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!"); } valid_timing = RNA_property_boolean_get(op->ptr, prop); - + gtd.mode = RNA_enum_get(op->ptr, "timing_mode"); /* Check for illegal timing mode! */ if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) { @@ -1611,7 +2432,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) if (!link_strokes) { gtd.mode = GP_STROKECONVERT_TIMING_NONE; } - + /* grab all relevant settings */ gtd.frame_range = RNA_int_get(op->ptr, "frame_range"); gtd.start_frame = RNA_int_get(op->ptr, "start_frame"); @@ -1626,10 +2447,10 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f; gtd.inittime = 0.0; gtd.offset_time = 0.0f; - + /* perform conversion */ gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, >d); - + /* free temp memory */ if (gtd.dists) { MEM_freeN(gtd.dists); @@ -1639,11 +2460,11 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) MEM_freeN(gtd.times); gtd.times = NULL; } - + /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - + /* done */ return OPERATOR_FINISHED; } @@ -1657,7 +2478,7 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) float gap_duration = RNA_float_get(ptr, "gap_duration"); float gap_randomness = RNA_float_get(ptr, "gap_randomness"); const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data"); - + /* Always show those props */ if (strcmp(prop_id, "type") == 0 || strcmp(prop_id, "use_normalize_weights") == 0 || @@ -1666,16 +2487,16 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) { return true; } - + /* Never show this prop */ if (strcmp(prop_id, "use_timing_data") == 0) return false; - + if (link_strokes) { /* Only show when link_stroke is true */ if (strcmp(prop_id, "timing_mode") == 0) return true; - + if (timing_mode != GP_STROKECONVERT_TIMING_NONE) { /* Only show when link_stroke is true and stroke timing is enabled */ if (strcmp(prop_id, "frame_range") == 0 || @@ -1683,31 +2504,31 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) { return true; } - + /* Only show if we have valid timing data! */ if (valid_timing && strcmp(prop_id, "use_realtime") == 0) return true; - + /* Only show if realtime or valid_timing is false! */ if ((!realtime || !valid_timing) && strcmp(prop_id, "end_frame") == 0) return true; - + if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { /* Only show for custom gaps! */ if (strcmp(prop_id, "gap_duration") == 0) return true; - + /* Only show randomness for non-null custom gaps! */ if (strcmp(prop_id, "gap_randomness") == 0 && (gap_duration > 0.0f)) return true; - + /* Only show seed for randomize action! */ if (strcmp(prop_id, "seed") == 0 && (gap_duration > 0.0f) && (gap_randomness > 0.0f)) return true; } } } - + /* Else, hidden! */ return false; } @@ -1717,9 +2538,9 @@ static void gp_convert_ui(bContext *C, wmOperator *op) uiLayout *layout = op->layout; wmWindowManager *wm = CTX_wm_manager(C); PointerRNA ptr; - + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - + /* Main auto-draw call */ uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0'); } @@ -1727,35 +2548,35 @@ static void gp_convert_ui(bContext *C, wmOperator *op) void GPENCIL_OT_convert(wmOperatorType *ot) { PropertyRNA *prop; - + /* identifiers */ ot->name = "Convert Grease Pencil"; ot->idname = "GPENCIL_OT_convert"; ot->description = "Convert the active Grease Pencil layer to a new Curve Object"; - + /* callbacks */ ot->invoke = WM_menu_invoke; ot->exec = gp_convert_layer_exec; ot->poll = gp_convert_poll; ot->ui = gp_convert_ui; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to"); - + RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight", "Normalize weight (set from stroke width)"); RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac", "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f); RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes", "Whether to link strokes with zero-radius sections of curves"); - + prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL, "Timing Mode", "How to use timing data stored in strokes"); RNA_def_enum_funcs(prop, rna_GPConvert_mode_items); - + RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range", "The duration of evaluation of the path control curve", 1, 1000); RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame", @@ -1765,7 +2586,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot) prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame", "The end frame of the path control curve (if Realtime is not set)", 1, 100000); RNA_def_property_update_runtime(prop, gp_convert_set_end_frame); - + RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration", "Custom Gap mode: (Average) length of gaps, in frames " "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f); @@ -1773,7 +2594,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot) "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f); RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed", "Custom Gap mode: Random generator seed", 0, 100); - + /* Note: Internal use, this one will always be hidden by UI code... */ prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing", "Whether the converted Grease Pencil layer has valid timing data (internal use)"); diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 28eb1355caf..56420434494 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -31,15 +31,74 @@ #ifndef __GPENCIL_INTERN_H__ #define __GPENCIL_INTERN_H__ -/* internal exports only */ +#include "DNA_vec_types.h" -/* ***************************************************** */ -/* Operator Defines */ +/* internal exports only */ struct bGPdata; +struct bGPDstroke; +struct bGPDspoint; + +struct ARegion; +struct View2D; struct wmOperatorType; + +/* ***************************************************** */ +/* Internal API */ + +/* Stroke Coordinates API ------------------------------ */ +/* gpencil_utils.c */ + +typedef struct GP_SpaceConversion { + struct bGPdata *gpd; + struct bGPDlayer *gpl; + + struct ScrArea *sa; + struct ARegion *ar; + struct View2D *v2d; + + rctf *subrect; /* for using the camera rect within the 3d view */ + rctf subrect_data; + + float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */ +} GP_SpaceConversion; + + +/** + * Check whether a given stroke segment is inside a circular brush + * + * \param mval The current screen-space coordinates (midpoint) of the brush + * \param mvalo The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED) + * \param rad The radius of the brush + * + * \param x0, y0 The screen-space x and y coordinates of the start of the stroke segment + * \param x1, y1 The screen-space x and y coordinates of the end of the stroke segment + */ +bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]), + int rad, int x0, int y0, int x1, int y1); + + +/** + * Init settings for stroke point space conversions + * + * \param[out] r_gsc The space conversion settings struct, populated with necessary params + */ +void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc); + +/** + * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D) + * + * \param[out] r_x The screen-space x-coordinate of the point + * \param[out] r_y The screen-space y-coordinate of the point + */ +void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt, + int *r_x, int *r_y); + +/* ***************************************************** */ +/* Operator Defines */ + /* drawing ---------- */ void GPENCIL_OT_draw(struct wmOperatorType *ot); @@ -52,12 +111,32 @@ typedef enum eGPencil_PaintModes { GP_PAINTMODE_DRAW_POLY } eGPencil_PaintModes; +/* stroke editing ----- */ + +void GPENCIL_OT_select(struct wmOperatorType *ot); +void GPENCIL_OT_select_all(struct wmOperatorType *ot); +void GPENCIL_OT_select_circle(struct wmOperatorType *ot); +void GPENCIL_OT_select_border(struct wmOperatorType *ot); +void GPENCIL_OT_select_lasso(struct wmOperatorType *ot); + +void GPENCIL_OT_select_linked(struct wmOperatorType *ot); +void GPENCIL_OT_select_more(struct wmOperatorType *ot); +void GPENCIL_OT_select_less(struct wmOperatorType *ot); + +void GPENCIL_OT_duplicate(struct wmOperatorType *ot); +void GPENCIL_OT_delete(struct wmOperatorType *ot); +void GPENCIL_OT_copy(struct wmOperatorType *ot); +void GPENCIL_OT_paste(struct wmOperatorType *ot); + /* buttons editing --- */ void GPENCIL_OT_data_add(struct wmOperatorType *ot); void GPENCIL_OT_data_unlink(struct wmOperatorType *ot); void GPENCIL_OT_layer_add(struct wmOperatorType *ot); +void GPENCIL_OT_layer_remove(struct wmOperatorType *ot); +void GPENCIL_OT_layer_move(struct wmOperatorType *ot); +void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot); void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); @@ -76,17 +155,17 @@ void gpencil_undo_finish(void); /* This struct defines a structure used for quick access */ typedef struct bActListElem { struct bActListElem *next, *prev; - + void *data; /* source data this elem represents */ int type; /* one of the ACTTYPE_* values */ int flag; /* copy of elem's flags for quick access */ int index; /* copy of adrcode where applicable */ - + void *key_data; /* motion data - ipo or ipo-curve */ short datatype; /* type of motion data to expect */ - + struct bActionGroup *grp; /* action group that owns the channel */ - + void *owner; /* will either be an action channel or fake ipo-channel (for keys) */ short ownertype; /* type of owner */ } bActListElem; diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 75ff0895931..6bba7d4f17d 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -36,40 +36,189 @@ #include "BLI_blenlib.h" +#include "BKE_context.h" + +#include "DNA_gpencil_types.h" + #include "WM_api.h" #include "WM_types.h" #include "RNA_access.h" #include "ED_gpencil.h" +#include "ED_object.h" +#include "ED_transform.h" #include "gpencil_intern.h" /* ****************************************** */ -/* Generic Editing Keymap */ +/* Grease Pencil Keymaps */ -void ED_keymap_gpencil(wmKeyConfig *keyconf) +/* Generic Drawing Keymap */ +static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil", 0, 0); wmKeyMapItem *kmi; - /* Draw */ - + /* Draw --------------------------------------- */ /* draw */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); - + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + /* draw - straight lines */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT); - + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + /* draw - poly lines */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, KM_CTRL, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY); - + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + /* erase */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, 0, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + /* Viewport Tools ------------------------------- */ + + /* Enter EditMode */ + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, 0, DKEY); + RNA_string_set(kmi->ptr, "data_path", "gpencil_data.use_stroke_edit_mode"); + + /* Pie Menu - For standard tools */ + WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY); +} + +/* ==================== */ + +/* Poll callback for stroke editing mode */ +static int gp_stroke_editmode_poll(bContext *C) +{ + bGPdata *gpd = CTX_data_gpencil_data(C); + return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)); +} + +/* Stroke Editing Keymap - Only when editmode is enabled */ +static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */ + keymap->poll = gp_stroke_editmode_poll; + + /* ----------------------------------------------- */ + + /* Exit EditMode */ + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "gpencil_data.use_stroke_edit_mode"); + + /* Brush Settings */ + /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys + * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain + * that the only data being edited is that of the Grease Pencil strokes + */ + + /* FKEY = Eraser Radius */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius"); + + /* Selection ------------------------------------- */ + /* select all */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "action", SEL_INVERT); + + /* circle select */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select_circle", CKEY, KM_PRESS, 0, 0); + + /* border select */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0); + + /* lasso select */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "deselect", true); + + /* normal select */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "extend", true); + RNA_boolean_set(kmi->ptr, "toggle", true); + + /* whole stroke select */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "entire_strokes", true); + + /* select linked */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0); + + /* select more/less */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); + + + /* Editing ----------------------------------------- */ + + /* duplicate and move selected points */ + WM_keymap_add_item(keymap, "GPENCIL_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); + + /* delete */ + WM_keymap_add_item(keymap, "GPENCIL_OT_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_delete", DELKEY, KM_PRESS, 0, 0); + + /* copy + paste */ + WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); + +#ifdef __APPLE__ + WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0); +#endif + + /* Transform Tools */ + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_bend", WKEY, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + WM_keymap_add_item(keymap, "TRANSFORM_OT_tosphere", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + WM_keymap_add_item(keymap, "TRANSFORM_OT_shear", SKEY, KM_PRESS, KM_ALT | KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "gpencil_strokes", true); + + /* Proportional Editing */ + ED_keymap_proportional_cycle(keyconf, keymap); + ED_keymap_proportional_editmode(keyconf, keymap, true); +} + +/* ==================== */ + +void ED_keymap_gpencil(wmKeyConfig *keyconf) +{ + ed_keymap_gpencil_general(keyconf); + ed_keymap_gpencil_editing(keyconf); } /* ****************************************** */ @@ -80,18 +229,51 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_draw); + /* Editing (Strokes) ------------ */ + + WM_operatortype_append(GPENCIL_OT_select); + WM_operatortype_append(GPENCIL_OT_select_all); + WM_operatortype_append(GPENCIL_OT_select_circle); + WM_operatortype_append(GPENCIL_OT_select_border); + WM_operatortype_append(GPENCIL_OT_select_lasso); + + WM_operatortype_append(GPENCIL_OT_select_linked); + WM_operatortype_append(GPENCIL_OT_select_more); + WM_operatortype_append(GPENCIL_OT_select_less); + + WM_operatortype_append(GPENCIL_OT_duplicate); + WM_operatortype_append(GPENCIL_OT_delete); + WM_operatortype_append(GPENCIL_OT_copy); + WM_operatortype_append(GPENCIL_OT_paste); + /* Editing (Buttons) ------------ */ WM_operatortype_append(GPENCIL_OT_data_add); WM_operatortype_append(GPENCIL_OT_data_unlink); WM_operatortype_append(GPENCIL_OT_layer_add); + WM_operatortype_append(GPENCIL_OT_layer_remove); + WM_operatortype_append(GPENCIL_OT_layer_move); + WM_operatortype_append(GPENCIL_OT_layer_duplicate); WM_operatortype_append(GPENCIL_OT_active_frame_delete); WM_operatortype_append(GPENCIL_OT_convert); - + /* Editing (Time) --------------- */ } +void ED_operatormacros_gpencil(void) +{ + wmOperatorType *ot; + wmOperatorTypeMacro *otmacro; + + ot = WM_operatortype_append_macro("GPENCIL_OT_duplicate_move", "Duplicate Strokes", + "Make copies of the selected Grease Pencil strokes and move them", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "GPENCIL_OT_duplicate"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_boolean_set(otmacro->ptr, "gpencil_strokes", true); +} + /* ****************************************** */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 7c1976df3e0..e6f6644fd24 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -27,6 +27,7 @@ * \ingroup edgpencil */ + #include <stdio.h> #include <stddef.h> #include <stdlib.h> @@ -86,11 +87,13 @@ typedef struct tGPsdata { rctf *subrect; /* for using the camera rect within the 3d view */ rctf subrect_data; + GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */ + PointerRNA ownerPtr; /* pointer to owner of gp-datablock */ bGPdata *gpd; /* gp-datablock layer comes from */ bGPDlayer *gpl; /* layer we're working on */ bGPDframe *gpf; /* frame we're working on */ - + short status; /* current status of painting */ short paintmode; /* mode for painting */ @@ -110,7 +113,7 @@ typedef struct tGPsdata { double inittime; /* Used when converting to path */ double curtime; /* Used when converting to path */ double ocurtime; /* Used when converting to path */ - + float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space * to region space */ float mat[4][4]; @@ -219,7 +222,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3]) if (p->ownerPtr.type == &RNA_Object) { Object *ob = (Object *)p->ownerPtr.data; - /* active Object + /* active Object * - use relative distance of 3D-cursor from object center */ sub_v3_v3v3(vec, fp, ob->loc); @@ -244,13 +247,13 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) if (p->gpd->sbuffer_size == 0) return true; - /* check if mouse moved at least certain distance on both axes (best case) + /* check if mouse moved at least certain distance on both axes (best case) * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand */ else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) return true; - /* check if the distance since the last point is significant enough + /* check if the distance since the last point is significant enough * - prevents points being added too densely * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though */ @@ -280,7 +283,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] float rvec[3], dvec[3]; float mval_f[2] = {UNPACK2(mval)}; float zfac; - + /* Current method just converts each point in screen-coordinates to * 3D-coordinates using the 3D-cursor as reference. In general, this * works OK, but it could of course be improved. @@ -292,7 +295,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] gp_get_3d_reference(p, rvec); zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL); - + if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { sub_v2_v2v2(mval_f, mval_prj, mval_f); ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac); @@ -328,7 +331,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, { bGPdata *gpd = p->gpd; tGPspoint *pt; - + /* check painting mode */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { /* straight lines only - i.e. only store start and end point in buffer */ @@ -345,7 +348,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, gpd->sbuffer_size++; } else { - /* normally, we just reset the endpoint to the latest value + /* normally, we just reset the endpoint to the latest value * - assume that pointers for this are always valid... */ pt = ((tGPspoint *)(gpd->sbuffer) + 1); @@ -439,7 +442,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, return GP_STROKEADD_NORMAL; } - + /* return invalid state for now... */ return GP_STROKEADD_INVALID; } @@ -459,12 +462,12 @@ static void gp_stroke_smooth(tGPsdata *p) if ((cmx <= 2) || (gpd->sbuffer == NULL)) return; - /* Calculate smoothing coordinates using weighted-averages + /* Calculate smoothing coordinates using weighted-averages * WARNING: we do NOT smooth first and last points (to avoid shrinkage) */ spt = (tGPspoint *)gpd->sbuffer; - /* This (tmp_spt) small array stores the last two points' original coordinates, + /* This (tmp_spt) small array stores the last two points' original coordinates, * as we don't want to use already averaged ones! It is used as a cyclic buffer... */ tmp_spt[0] = *spt; @@ -483,7 +486,7 @@ static void gp_stroke_smooth(tGPsdata *p) } } -/* simplify a stroke (in buffer) before storing it +/* simplify a stroke (in buffer) before storing it * - applies a reverse Chaikin filter * - code adapted from etch-a-ton branch (editarmature_sketch.c) */ @@ -503,7 +506,7 @@ static void gp_stroke_simplify(tGPsdata *p) if ((num_points <= 4) || (old_points == NULL)) return; - /* clear buffer (but don't free mem yet) so that we can write to it + /* clear buffer (but don't free mem yet) so that we can write to it * - firstly set sbuffer to NULL, so a new one is allocated * - secondly, reset flag after, as it gets cleared auto */ @@ -570,7 +573,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0; - /* get total number of points to allocate space for + /* get total number of points to allocate space for * - drawing straight-lines only requires the endpoints */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) @@ -626,7 +629,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt++; } - + if (totelem == 2) { /* last point if applicable */ ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1); @@ -747,7 +750,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i) /* free stroke points, then stroke */ MEM_freeN(pt_tmp); BLI_freelinkN(&gpf->strokes, gps); - + /* nothing left in stroke, so stop */ return 1; } @@ -853,8 +856,7 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) } } -static bool gp_stroke_eraser_is_occluded(tGPsdata *p, - const bGPDspoint *pt, const int x, const int y) +static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y) { if ((p->sa->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) @@ -862,11 +864,11 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, RegionView3D *rv3d = p->ar->regiondata; const int mval[2] = {x, y}; float mval_3d[3]; - + if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) { const float depth_mval = view3d_point_depth(rv3d, mval_3d); const float depth_pt = view3d_point_depth(rv3d, &pt->x); - + if (depth_pt > depth_mval) { return true; } @@ -875,58 +877,6 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, return false; } -/* eraser tool - check if part of stroke occurs within last segment drawn by eraser */ -static short gp_stroke_eraser_strokeinside(const int mval[2], const int UNUSED(mvalo[2]), - int rad, int x0, int y0, int x1, int y1) -{ - /* simple within-radius check for now */ - const float mval_fl[2] = {mval[0], mval[1]}; - const float screen_co_a[2] = {x0, y0}; - const float screen_co_b[2] = {x1, y1}; - - if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) { - return true; - } - - /* not inside */ - return false; -} - -static void gp_point_to_xy(tGPsdata *p, bGPDstroke *gps, bGPDspoint *pt, - int *r_x, int *r_y) -{ - ARegion *ar = p->ar; - View2D *v2d = p->v2d; - rctf *subrect = p->subrect; - int xyval[2]; - - if (gps->flag & GP_STROKE_3DSPACE) { - if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - *r_x = xyval[0]; - *r_y = xyval[1]; - } - else { - *r_x = V2D_IS_CLIPPED; - *r_y = V2D_IS_CLIPPED; - } - } - else if (gps->flag & GP_STROKE_2DSPACE) { - float vec[3] = {pt->x, pt->y, 0.0f}; - mul_m4_v3(p->mat, vec); - UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y); - } - else { - if (subrect == NULL) { /* normal 3D view */ - *r_x = (int)(pt->x / 100 * ar->winx); - *r_y = (int)(pt->y / 100 * ar->winy); - } - else { /* camera view, use subrect */ - *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin; - *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin; - } - } -} - /* eraser tool - evaluation per stroke */ /* TODO: this could really do with some optimization (KD-Tree/BVH?) */ @@ -940,12 +890,12 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, if (gps->totpoints == 0) { /* just free stroke */ - if (gps->points) + if (gps->points) MEM_freeN(gps->points); BLI_freelinkN(&gpf->strokes, gps); } else if (gps->totpoints == 1) { - gp_point_to_xy(p, gps, gps->points, &x0, &y0); + gp_point_to_xy(&p->gsc, gps, gps->points, &x0, &y0); /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) { @@ -958,7 +908,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, } } else { - /* loop over the points in the stroke, checking for intersections + /* loop over the points in the stroke, checking for intersections * - an intersection will require the stroke to be split */ for (i = 0; (i + 1) < gps->totpoints; i++) { @@ -966,8 +916,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, pt1 = gps->points + i; pt2 = gps->points + i + 1; - gp_point_to_xy(p, gps, pt1, &x0, &y0); - gp_point_to_xy(p, gps, pt2, &x1, &y1); + gp_point_to_xy(&p->gsc, gps, pt1, &x0, &y0); + gp_point_to_xy(&p->gsc, gps, pt2, &x1, &y1); /* check that point segment of the boundbox of the eraser stroke */ if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) || @@ -977,7 +927,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, * eraser region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant */ - if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) { + if (gp_stroke_inside_circle(mval, mvalo, rad, x0, y0, x1, y1)) { if ((gp_stroke_eraser_is_occluded(p, pt1, x0, y0) == false) || (gp_stroke_eraser_is_occluded(p, pt2, x1, y1) == false)) { @@ -1003,16 +953,16 @@ static void gp_stroke_doeraser(tGPsdata *p) rect.ymin = p->mval[1] - p->radius; rect.xmax = p->mval[0] + p->radius; rect.ymax = p->mval[1] + p->radius; - + if (p->sa->spacetype == SPACE_VIEW3D) { if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) { View3D *v3d = p->sa->spacedata.first; - + view3d_region_operator_needs_opengl(p->win, p->ar); ED_view3d_autodist_init(p->scene, p->ar, v3d, 0); } } - + /* loop over strokes, checking segments for intersections */ for (gps = gpf->strokes.first; gps; gps = gpn) { gpn = gps->next; @@ -1043,7 +993,7 @@ static void gp_session_validatebuffer(tGPsdata *p) /* reset flags */ gpd->sbuffer_sflag = 0; - + /* reset inittime */ p->inittime = 0.0; } @@ -1066,8 +1016,9 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) /* pass on current scene and window */ p->scene = CTX_data_scene(C); p->win = CTX_wm_window(C); - + unit_m4(p->imat); + unit_m4(p->mat); switch (curarea->spacetype) { /* supported views first */ @@ -1076,7 +1027,7 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) /* View3D *v3d = curarea->spacedata.first; */ /* RegionView3D *rv3d = ar->regiondata; */ - /* set current area + /* set current area * - must verify that region data is 3D-view (and not something else) */ p->sa = curarea; @@ -1154,7 +1105,9 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) p->imat[3][0] -= marker->pos[0]; p->imat[3][1] -= marker->pos[1]; } + invert_m4_m4(p->mat, p->imat); + copy_m4_m4(p->gsc.mat, p->mat); break; } /* unsupported views */ @@ -1199,10 +1152,10 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) static tGPsdata *gp_session_initpaint(bContext *C) { tGPsdata *p = NULL; - + /* create new context data */ p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data"); - + gp_session_initdata(C, p); /* return context data for running paint operator */ @@ -1233,7 +1186,7 @@ static void gp_session_cleanup(tGPsdata *p) /* init new stroke */ static void gp_paint_initstroke(tGPsdata *p, short paintmode) -{ +{ /* get active layer (or add a new one if non-existent) */ p->gpl = gpencil_layer_getactive(p->gpd); if (p->gpl == NULL) { @@ -1248,7 +1201,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode) printf("Error: Cannot paint on locked layer\n"); return; } - + /* get active frame (add a new one if not matching frame) */ p->gpf = gpencil_layer_getframe(p->gpl, p->scene->r.cfra, 1); if (p->gpf == NULL) { @@ -1264,7 +1217,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode) p->paintmode = paintmode; if (p->paintmode == GP_PAINTMODE_ERASER) { p->gpd->sbuffer_sflag |= GP_STROKE_ERASER; - + /* check if we should respect depth while erasing */ if (p->sa->spacetype == SPACE_VIEW3D) { if (p->gpl->flag & GP_LAYER_NO_XRAY) { @@ -1272,11 +1225,11 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode) } } } - + /* set 'initial run' flag, which is only used to denote when a new stroke is starting */ p->flags |= GP_PAINTFLAG_FIRSTRUN; - + /* when drawing in the camera view, in 2D space, set the subrect */ if (!(p->gpd->flag & GP_DATA_VIEWALIGN)) { if (p->sa->spacetype == SPACE_VIEW3D) { @@ -1290,7 +1243,21 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode) } } } - + + /* init stroke point space-conversion settings... */ + p->gsc.gpd = p->gpd; + p->gsc.gpl = p->gpl; + + p->gsc.sa = p->sa; + p->gsc.ar = p->ar; + p->gsc.v2d = p->v2d; + + p->gsc.subrect_data = p->subrect_data; + p->gsc.subrect = p->subrect; + + copy_m4_m4(p->gsc.mat, p->mat); + + /* check if points will need to be made in view-aligned space */ if (p->gpd->flag & GP_DATA_VIEWALIGN) { switch (p->sa->spacetype) { @@ -1340,7 +1307,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode) /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */ static void gp_paint_strokeend(tGPsdata *p) { - /* for surface sketching, need to set the right OpenGL context stuff so that + /* for surface sketching, need to set the right OpenGL context stuff so that * the conversions will project the values correctly... */ if (gpencil_project_check(p)) { @@ -1395,13 +1362,18 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) glTranslatef((float)x, (float)y, 0.0f); - glColor4ub(255, 255, 255, 128); - glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); + glColor4ub(255, 100, 100, 20); + glutil_draw_filled_arc(0.0, M_PI * 2.0, p->radius, 40); + + setlinestyle(6); + + glColor4ub(255, 100, 100, 200); glutil_draw_lined_arc(0.0, M_PI * 2.0, p->radius, 40); + setlinestyle(0); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); @@ -1419,7 +1391,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en } else if (enable) { /* enable cursor */ - p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), + p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), NULL, /* XXX */ gpencil_draw_eraser, p); } @@ -1526,13 +1498,13 @@ static void gpencil_draw_status_indicators(tGPsdata *p) ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | " "ESC/Enter to end")); break; - + default: /* unhandled future cases */ ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end")); break; } break; - + case GP_STATUS_ERROR: case GP_STATUS_DONE: /* clear status string */ @@ -1626,15 +1598,6 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) else p->pressure = 1.0f; - /* fill in stroke data (not actually used directly by gpencil_draw_apply) */ - RNA_collection_add(op->ptr, "stroke", &itemptr); - - mousef[0] = p->mval[0]; - mousef[1] = p->mval[1]; - RNA_float_set_array(&itemptr, "mouse", mousef); - RNA_float_set(&itemptr, "pressure", p->pressure); - RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN)); - /* special exception for start of strokes (i.e. maybe for just a dot) */ if (p->flags & GP_PAINTFLAG_FIRSTRUN) { p->flags &= ~GP_PAINTFLAG_FIRSTRUN; @@ -1651,6 +1614,15 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) return; } + /* fill in stroke data (not actually used directly by gpencil_draw_apply) */ + RNA_collection_add(op->ptr, "stroke", &itemptr); + + mousef[0] = p->mval[0]; + mousef[1] = p->mval[1]; + RNA_float_set_array(&itemptr, "mouse", mousef); + RNA_float_set(&itemptr, "pressure", p->pressure); + RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN)); + RNA_float_set(&itemptr, "time", p->curtime - p->inittime); /* apply the current latest drawing point */ @@ -1721,7 +1693,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) gpencil_draw_apply(op, p); } RNA_END; - + /* printf("\tGP - done\n"); */ /* cleanup */ @@ -1747,7 +1719,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* try to initialize context data needed while drawing */ if (!gpencil_draw_init(C, op)) { - if (op->customdata) + if (op->customdata) MEM_freeN(op->customdata); if (G.debug & G_DEBUG) printf("\tGP - no valid data\n"); @@ -1755,12 +1727,12 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event } else p = op->customdata; - + /* TODO: set any additional settings that we can take from the events? * TODO? if tablet is erasing, force eraser to be on? */ - + /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */ - + /* if eraser is on, draw radial aid */ if (p->paintmode == GP_PAINTMODE_ERASER) { gpencil_draw_toggle_eraser_cursor(C, p, true); @@ -1772,11 +1744,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event else WM_cursor_modal_set(win, BC_PAINTBRUSHCURSOR); - /* special hack: if there was an initial event, then we were invoked via a hotkey, and - * painting should start immediately. Otherwise, this was called from a toolbar, in which - * case we should wait for the mouse to be clicked. - */ - if (event->val == KM_PRESS) { + /* only start drawing immediately if we're allowed to do so... */ + if (RNA_boolean_get(op->ptr, "wait_for_input") == false) { /* hotkey invoked - start drawing */ /* printf("\tGP - set first spot\n"); */ p->status = GP_STATUS_PAINTING; @@ -1833,15 +1802,15 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) static void gpencil_stroke_end(wmOperator *op) { tGPsdata *p = op->customdata; - + gp_paint_cleanup(p); - + gpencil_undo_push(p->gpd); - + gp_session_cleanup(p); - + p->status = GP_STATUS_IDLING; - + p->gpd = NULL; p->gpl = NULL; p->gpf = NULL; @@ -1865,11 +1834,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * better in tools that immediately apply * in 3D space. */ - + /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */ if (ISKEYBOARD(event->type)) { - if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) { - /* allow some keys - for frame changing: [#33412] */ + if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) { + /* allow some keys: + * - for frame changing [#33412] + * - for undo (during sketching sessions) + */ } else { estate = OPERATOR_RUNNING_MODAL; @@ -1878,7 +1850,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) //printf("\tGP - handle modal event...\n"); - /* exit painting mode (and/or end current stroke) + /* exit painting mode (and/or end current stroke) * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] */ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) { @@ -1888,7 +1860,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_FINISHED; } - /* toggle painting mode upon mouse-button movement + /* toggle painting mode upon mouse-button movement * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only) * - RIGHTMOUSE = polyline (hotkey) / eraser (all) * (Disabling RIGHTMOUSE case here results in bugs like [#32647]) @@ -1898,7 +1870,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) if (p->status == GP_STATUS_PAINTING) { int sketch = 0; - /* basically, this should be mouse-button up = end stroke + /* basically, this should be mouse-button up = end stroke * BUT what happens next depends on whether we 'painting sessions' is enabled */ sketch |= GPENCIL_SKETCH_SESSIONS_ON(p->scene); @@ -1967,12 +1939,12 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) case PADPLUSKEY: p->radius += 5; break; - + case WHEELUPMOUSE: /* smaller */ case PADMINUS: p->radius -= 5; - if (p->radius < 0) + if (p->radius < 0) p->radius = 0; break; } @@ -1983,7 +1955,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* event handled, so just tag as running modal */ estate = OPERATOR_RUNNING_MODAL; } - /* there shouldn't be any other events, but just in case there are, let's swallow them + /* there shouldn't be any other events, but just in case there are, let's swallow them * (i.e. to prevent problems with undo) */ else { @@ -2006,7 +1978,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) gpencil_draw_exit(C, op); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); break; - + case OPERATOR_CANCELLED: gpencil_draw_exit(C, op); break; @@ -2053,6 +2025,8 @@ void GPENCIL_OT_draw(wmOperatorType *ot) /* settings for drawing */ ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements"); - RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + + /* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */ + RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately"); } diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c new file mode 100644 index 00000000000..7967d6a4d95 --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -0,0 +1,943 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/gpencil/gpencil_select.c + * \ingroup edgpencil + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_lasso.h" +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_library.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_screen.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_view2d.h" + +#include "ED_gpencil.h" +#include "ED_view3d.h" +#include "ED_keyframing.h" + +#include "gpencil_intern.h" + +/* ********************************************** */ +/* Polling callbacks */ + +static int gpencil_select_poll(bContext *C) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + + /* only if there's an active layer with an active frame */ + return (gpl && gpl->actframe); +} + +/* ********************************************** */ +/* Select All Operator */ + +static int gpencil_select_all_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + int action = RNA_enum_get(op->ptr, "action"); + + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + + /* for "toggle", test for existing selected strokes */ + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if (gps->flag & GP_STROKE_SELECT) { + action = SEL_DESELECT; + break; // XXX: this only gets out of the inner loop... + } + } + CTX_DATA_END; + } + + /* if deselecting, we need to deselect strokes across all frames + * - Currently, an exception is only given for deselection + * Selecting and toggling should only affect what's visible, + * while deselecting helps clean up unintended/forgotten + * stuff on other frames + */ + if (action == SEL_DESELECT) { + /* deselect strokes across editable layers + * NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden + * nothing should be able to touch it + */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *gpf; + + /* deselect all strokes on all frames */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + bGPDstroke *gps; + + for (gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + + gps->flag &= ~GP_STROKE_SELECT; + } + } + } + CTX_DATA_END; + } + else { + /* select or deselect all strokes */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + bGPDspoint *pt; + int i; + bool selected = false; + + /* Change selection status of all points, then make the stroke match */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + switch (action) { + case SEL_SELECT: + pt->flag |= GP_SPOINT_SELECT; + break; + //case SEL_DESELECT: + // pt->flag &= ~GP_SPOINT_SELECT; + // break; + case SEL_INVERT: + pt->flag ^= GP_SPOINT_SELECT; + break; + } + + if (pt->flag & GP_SPOINT_SELECT) + selected = true; + } + + /* Change status of stroke */ + if (selected) + gps->flag |= GP_STROKE_SELECT; + else + gps->flag &= ~GP_STROKE_SELECT; + } + CTX_DATA_END; + } + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "(De)select All Strokes"; + ot->idname = "GPENCIL_OT_select_all"; + ot->description = "Change selection of all Grease Pencil strokes currently visible"; + + /* callbacks */ + ot->exec = gpencil_select_all_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + WM_operator_properties_select_all(ot); +} + +/* ********************************************** */ +/* Select Linked */ + +static int gpencil_select_linked_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + + /* select all points in selected strokes */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag |= GP_SPOINT_SELECT; + } + } + } + CTX_DATA_END; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Linked"; + ot->idname = "GPENCIL_OT_select_linked"; + ot->description = "Select all points in same strokes as already selected points"; + + /* callbacks */ + ot->exec = gpencil_select_linked_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ********************************************** */ +/* Select More */ + +static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) +{ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + bool prev_sel; + + /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)... + * - This pass covers the "after" edges of selection islands + */ + prev_sel = false; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + /* selected point - just set flag for next point */ + prev_sel = true; + } + else { + /* unselected point - expand selection if previous was selected... */ + if (prev_sel) { + pt->flag |= GP_SPOINT_SELECT; + } + prev_sel = false; + } + } + + /* Second Pass: Go in reverse order, doing the same as before (except in opposite order) + * - This pass covers the "before" edges of selection islands + */ + prev_sel = false; + for (pt -= 1; i > 0; i--, pt--) { + if (pt->flag & GP_SPOINT_SELECT) { + prev_sel = true; + } + else { + /* unselected point - expand selection if previous was selected... */ + if (prev_sel) { + pt->flag |= GP_SPOINT_SELECT; + } + prev_sel = false; + } + } + } + } + CTX_DATA_END; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_more(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select More"; + ot->idname = "GPENCIL_OT_select_more"; + ot->description = "Grow sets of selected Grease Pencil points"; + + /* callbacks */ + ot->exec = gpencil_select_more_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ********************************************** */ +/* Select Less */ + +static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) +{ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + bool prev_sel; + + /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)... + * - This pass covers the "after" edges of selection islands + */ + prev_sel = false; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + /* shrink if previous wasn't selected */ + if (prev_sel == false) { + pt->flag &= ~GP_SPOINT_SELECT; + } + prev_sel = true; + } + else { + /* mark previous as being unselected - and hence, is trigger for shrinking */ + prev_sel = false; + } + } + + /* Second Pass: Go in reverse order, doing the same as before (except in opposite order) + * - This pass covers the "before" edges of selection islands + */ + prev_sel = false; + for (pt -= 1; i > 0; i--, pt--) { + if (pt->flag & GP_SPOINT_SELECT) { + /* shrink if previous wasn't selected */ + if (prev_sel == false) { + pt->flag &= ~GP_SPOINT_SELECT; + } + prev_sel = true; + } + else { + /* mark previous as being unselected - and hence, is trigger for shrinking */ + prev_sel = false; + } + } + } + } + CTX_DATA_END; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_less(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Less"; + ot->idname = "GPENCIL_OT_select_less"; + ot->description = "Shrink sets of selected Grease Pencil points"; + + /* callbacks */ + ot->exec = gpencil_select_less_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ********************************************** */ +/* Circle Select Operator */ + +/* Helper to check if a given stroke is within the area */ +/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke() + * It would be great to de-duplicate the logic here sometime, but that can wait... + */ +static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc, + const int mx, const int my, const int radius, + const bool select, rcti *rect) +{ + bGPDspoint *pt1, *pt2; + int x0 = 0, y0 = 0, x1 = 0, y1 = 0; + int i; + bool changed = false; + + if (gps->totpoints == 1) { + gp_point_to_xy(gsc, gps, gps->points, &x0, &y0); + + /* do boundbox check first */ + if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) { + /* only check if point is inside */ + if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) { + /* change selection */ + if (select) { + gps->points->flag |= GP_SPOINT_SELECT; + gps->flag |= GP_STROKE_SELECT; + } + else { + gps->points->flag &= ~GP_SPOINT_SELECT; + gps->flag &= ~GP_STROKE_SELECT; + } + + return true; + } + } + } + else { + /* Loop over the points in the stroke, checking for intersections + * - an intersection means that we touched the stroke + */ + for (i = 0; (i + 1) < gps->totpoints; i++) { + /* get points to work with */ + pt1 = gps->points + i; + pt2 = gps->points + i + 1; + + gp_point_to_xy(gsc, gps, pt1, &x0, &y0); + gp_point_to_xy(gsc, gps, pt2, &x1, &y1); + + /* check that point segment of the boundbox of the selection stroke */ + if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) || + ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) + { + int mval[2] = {mx, my}; + int mvalo[2] = {mx, my}; /* dummy - this isn't used... */ + + /* check if point segment of stroke had anything to do with + * eraser region (either within stroke painted, or on its lines) + * - this assumes that linewidth is irrelevant + */ + if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) { + /* change selection of stroke, and then of both points + * (as the last point otherwise wouldn't get selected + * as we only do n-1 loops through) + */ + if (select) { + pt1->flag |= GP_SPOINT_SELECT; + pt2->flag |= GP_SPOINT_SELECT; + + changed = true; + } + else { + pt1->flag &= ~GP_SPOINT_SELECT; + pt2->flag &= ~GP_SPOINT_SELECT; + + changed = true; + } + } + } + } + + /* Ensure that stroke selection is in sync with its points */ + gpencil_stroke_sync_selection(gps); + } + + return changed; +} + + +static int gpencil_circle_select_exec(bContext *C, wmOperator *op) +{ + ScrArea *sa = CTX_wm_area(C); + + const int mx = RNA_int_get(op->ptr, "x"); + const int my = RNA_int_get(op->ptr, "y"); + const int radius = RNA_int_get(op->ptr, "radius"); + + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + const bool select = (gesture_mode == GESTURE_MODAL_SELECT); + + GP_SpaceConversion gsc = {NULL}; + rcti rect = {0}; /* for bounding rect around circle (for quicky intersection testing) */ + + bool changed = false; + + + /* sanity checks */ + if (sa == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active area"); + return OPERATOR_CANCELLED; + } + + /* init space conversion stuff */ + gp_point_conversion_init(C, &gsc); + + + /* rect is rectangle of selection circle */ + rect.xmin = mx - radius; + rect.ymin = my - radius; + rect.xmax = mx + radius; + rect.ymax = my + radius; + + + /* find visible strokes, and select if hit */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + changed |= gp_stroke_do_circle_sel(gps, &gsc, mx, my, radius, select, &rect); + } + CTX_DATA_END; + + /* updates */ + if (changed) { + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_circle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Circle Select"; + ot->description = "Select Grease Pencil strokes using brush selection"; + ot->idname = "GPENCIL_OT_select_circle"; + + /* callbacks */ + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = gpencil_circle_select_exec; + ot->poll = gpencil_select_poll; + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX); + RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX); +} + +/* ********************************************** */ +/* Box Selection */ + +static int gpencil_border_select_exec(bContext *C, wmOperator *op) +{ + ScrArea *sa = CTX_wm_area(C); + + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + const bool select = (gesture_mode == GESTURE_MODAL_SELECT); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + + GP_SpaceConversion gsc = {NULL}; + rcti rect = {0}; + + bool changed = false; + + + /* sanity checks */ + if (sa == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active area"); + return OPERATOR_CANCELLED; + } + + /* init space conversion stuff */ + gp_point_conversion_init(C, &gsc); + + + /* deselect all strokes first? */ + if (select && !extend) { + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + + gps->flag &= ~GP_STROKE_SELECT; + } + CTX_DATA_END; + } + + /* get settings from operator */ + WM_operator_properties_border_to_rcti(op, &rect); + + /* select/deselect points */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + int x0, y0; + + /* convert point coords to screenspace */ + gp_point_to_xy(&gsc, gps, pt, &x0, &y0); + + /* test if in selection rect */ + if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) { + if (select) { + pt->flag |= GP_SPOINT_SELECT; + } + else { + pt->flag &= ~GP_SPOINT_SELECT; + } + + changed = true; + } + } + + /* Ensure that stroke selection is in sync with its points */ + gpencil_stroke_sync_selection(gps); + } + CTX_DATA_END; + + /* updates */ + if (changed) { + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_border(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Border Select"; + ot->description = "Select Grease Pencil strokes within a rectangular region"; + ot->idname = "GPENCIL_OT_select_border"; + + /* callbacks */ + ot->invoke = WM_border_select_invoke; + ot->exec = gpencil_border_select_exec; + ot->modal = WM_border_select_modal; + ot->cancel = WM_border_select_cancel; + + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* rna */ + WM_operator_properties_gesture_border(ot, true); +} + +/* ********************************************** */ +/* Lasso */ + +static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) +{ + GP_SpaceConversion gsc = {NULL}; + rcti rect = {0}; + + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool select = !RNA_boolean_get(op->ptr, "deselect"); + + int mcords_tot; + const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + + bool changed = false; + + /* sanity check */ + if (mcords == NULL) + return OPERATOR_PASS_THROUGH; + + /* compute boundbox of lasso (for faster testing later) */ + BLI_lasso_boundbox(&rect, mcords, mcords_tot); + + /* init space conversion stuff */ + gp_point_conversion_init(C, &gsc); + + /* deselect all strokes first? */ + if (select && !extend) { + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + + gps->flag &= ~GP_STROKE_SELECT; + } + CTX_DATA_END; + } + + /* select/deselect points */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + int x0, y0; + + /* convert point coords to screenspace */ + gp_point_to_xy(&gsc, gps, pt, &x0, &y0); + + /* test if in lasso boundbox + within the lasso noose */ + if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) && + BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX)) + { + if (select) { + pt->flag |= GP_SPOINT_SELECT; + } + else { + pt->flag &= ~GP_SPOINT_SELECT; + } + + changed = true; + } + } + + /* Ensure that stroke selection is in sync with its points */ + gpencil_stroke_sync_selection(gps); + } + CTX_DATA_END; + + /* cleanup */ + MEM_freeN((void *)mcords); + + /* updates */ + if (changed) { + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_lasso(wmOperatorType *ot) +{ + ot->name = "Lasso Select Strokes"; + ot->description = "Select Grease Pencil strokes using lasso selection"; + ot->idname = "GPENCIL_OT_select_lasso"; + + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = gpencil_lasso_select_exec; + ot->poll = gpencil_select_poll; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items"); + RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first"); +} + +/* ********************************************** */ +/* Mouse Click to Select */ + +static int gpencil_select_exec(bContext *C, wmOperator *op) +{ + ScrArea *sa = CTX_wm_area(C); + + /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ + const float radius = 0.75f * U.widget_unit; + const int radius_squared = (int)(radius * radius); + + bool extend = RNA_boolean_get(op->ptr, "extend"); + bool deselect = RNA_boolean_get(op->ptr, "deselect"); + bool toggle = RNA_boolean_get(op->ptr, "toggle"); + bool whole = RNA_boolean_get(op->ptr, "entire_strokes"); + + int location[2] = {0}; + int mx, my; + + GP_SpaceConversion gsc = {NULL}; + + bGPDstroke *hit_stroke = NULL; + bGPDspoint *hit_point = NULL; + + /* sanity checks */ + if (sa == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active area"); + return OPERATOR_CANCELLED; + } + + /* init space conversion stuff */ + gp_point_conversion_init(C, &gsc); + + /* get mouse location */ + RNA_int_get_array(op->ptr, "location", location); + + mx = location[0]; + my = location[1]; + + /* First Pass: Find stroke point which gets hit */ + /* XXX: maybe we should go from the top of the stack down instead... */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + bGPDspoint *pt; + int i; + int hit_index = -1; + + /* firstly, check for hit-point */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + int x0, y0; + + gp_point_to_xy(&gsc, gps, pt, &x0, &y0); + + /* do boundbox check first */ + if (!ELEM(V2D_IS_CLIPPED, x0, x0)) { + /* only check if point is inside */ + if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius_squared) { + hit_stroke = gps; + hit_point = pt; + break; + } + } + } + + /* skip to next stroke if nothing found */ + if (hit_index == -1) + continue; + } + CTX_DATA_END; + + /* Abort if nothing hit... */ + if (ELEM(NULL, hit_stroke, hit_point)) { + return OPERATOR_CANCELLED; + } + + /* adjust selection behaviour - for toggle option */ + if (toggle) { + deselect = (hit_point->flag & GP_SPOINT_SELECT) != 0; + } + + /* If not extending selection, deselect everything else */ + if (extend == false) { + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + /* deselect stroke and its points if selected */ + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + /* deselect points */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + + /* deselect stroke itself too */ + gps->flag &= ~GP_STROKE_SELECT; + } + } + CTX_DATA_END; + } + + /* Perform selection operations... */ + if (whole) { + bGPDspoint *pt; + int i; + + /* entire stroke's points */ + for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) { + if (deselect == false) + pt->flag |= GP_SPOINT_SELECT; + else + pt->flag &= ~GP_SPOINT_SELECT; + } + + /* stroke too... */ + if (deselect == false) + hit_stroke->flag |= GP_STROKE_SELECT; + else + hit_stroke->flag &= ~GP_STROKE_SELECT; + } + else { + /* just the point (and the stroke) */ + if (deselect == false) { + /* we're adding selection, so selection must be true */ + hit_point->flag |= GP_SPOINT_SELECT; + hit_stroke->flag |= GP_STROKE_SELECT; + } + else { + /* deselect point */ + hit_point->flag &= ~GP_SPOINT_SELECT; + + /* ensure that stroke is selected correctly */ + gpencil_stroke_sync_selection(hit_stroke); + } + } + + /* updates */ + if (hit_point != NULL) { + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + } + + return OPERATOR_FINISHED; +} + +static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + RNA_int_set_array(op->ptr, "location", event->mval); + return gpencil_select_exec(C, op); +} + +void GPENCIL_OT_select(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select"; + ot->description = "Select Grease Pencil strokes and/or stroke points"; + ot->idname = "GPENCIL_OT_select"; + + /* callbacks */ + ot->invoke = gpencil_select_invoke; + ot->exec = gpencil_select_exec; + ot->poll = gpencil_select_poll; + + /* flag */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_mouse_select(ot); + + prop = RNA_def_boolean(ot->srna, "entire_strokes", false, "Entire Strokes", "Select entire strokes instead of just the nearest stroke vertex"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); +} + +/* ********************************************** */ diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index ff92d69f39d..5f0647fb43d 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -29,6 +29,7 @@ * \ingroup edgpencil */ + #include <stdlib.h> #include <string.h> @@ -53,7 +54,7 @@ typedef struct bGPundonode { struct bGPundonode *next, *prev; - + char name[BKE_UNDO_STR_MAX]; struct bGPdata *gpd; } bGPundonode; @@ -69,9 +70,9 @@ int ED_gpencil_session_active(void) int ED_undo_gpencil_step(bContext *C, int step, const char *name) { bGPdata **gpd_ptr = NULL, *new_gpd = NULL; - + gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + if (step == 1) { /* undo */ //printf("\t\tGP - undo step\n"); if (cur_node->prev) { @@ -90,18 +91,18 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) } } } - + if (new_gpd) { if (gpd_ptr) { if (*gpd_ptr) { bGPdata *gpd = *gpd_ptr; bGPDlayer *gpl, *gpld; - + free_gpencil_layers(&gpd->layers); - + /* copy layers */ BLI_listbase_clear(&gpd->layers); - + for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) { /* make a copy of source layer and its data */ gpld = gpencil_layer_duplicate(gpl); @@ -110,9 +111,9 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) } } } - + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -124,46 +125,56 @@ void gpencil_undo_init(bGPdata *gpd) void gpencil_undo_push(bGPdata *gpd) { bGPundonode *undo_node; - + //printf("\t\tGP - undo push\n"); - + if (cur_node) { /* remove all un-done nodes from stack */ undo_node = cur_node->next; - + while (undo_node) { bGPundonode *next_node = undo_node->next; - + + /* HACK: animdata wasn't duplicated, so it shouldn't be freed here, + * or else the real copy will segfault when accessed + */ + undo_node->gpd->adt = NULL; + BKE_gpencil_free(undo_node->gpd); MEM_freeN(undo_node->gpd); - + BLI_freelinkN(&undo_nodes, undo_node); - + undo_node = next_node; } } - + /* create new undo node */ undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node"); - undo_node->gpd = gpencil_data_duplicate(gpd); - + undo_node->gpd = gpencil_data_duplicate(gpd, true); + cur_node = undo_node; - + BLI_addtail(&undo_nodes, undo_node); } void gpencil_undo_finish(void) { bGPundonode *undo_node = undo_nodes.first; - + while (undo_node) { + /* HACK: animdata wasn't duplicated, so it shouldn't be freed here, + * or else the real copy will segfault when accessed + */ + undo_node->gpd->adt = NULL; + BKE_gpencil_free(undo_node->gpd); MEM_freeN(undo_node->gpd); - + undo_node = undo_node->next; } - + BLI_freelistN(&undo_nodes); - + cur_node = NULL; } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c new file mode 100644 index 00000000000..4a913c3d2e5 --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -0,0 +1,166 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014, Blender Foundation + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/gpencil/gpencil_utils.c + * \ingroup edgpencil + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_library.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_screen.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_view2d.h" + +#include "ED_gpencil.h" +#include "ED_view3d.h" + +#include "gpencil_intern.h" + +/* ******************************************************** */ + +/* Check if part of stroke occurs within last segment drawn by eraser */ +bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]), + int rad, int x0, int y0, int x1, int y1) +{ + /* simple within-radius check for now */ + const float mval_fl[2] = {mval[0], mval[1]}; + const float screen_co_a[2] = {x0, y0}; + const float screen_co_b[2] = {x1, y1}; + + if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) { + return true; + } + + /* not inside */ + return false; +} + +/* ******************************************************** */ + +/* Init handling for space-conversion function (from passed-in parameters) */ +void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) +{ + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + + /* zero out the storage (just in case) */ + memset(r_gsc, 0, sizeof(GP_SpaceConversion)); + unit_m4(r_gsc->mat); + + /* store settings */ + r_gsc->sa = sa; + r_gsc->ar = ar; + r_gsc->v2d = &ar->v2d; + + /* init region-specific stuff */ + if (sa->spacetype == SPACE_VIEW3D) { + wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); + View3D *v3d = (View3D *)CTX_wm_space_data(C); + RegionView3D *rv3d = ar->regiondata; + + /* init 3d depth buffers */ + view3d_operator_needs_opengl(C); + + view3d_region_operator_needs_opengl(win, ar); + ED_view3d_autodist_init(scene, ar, v3d, 0); + + /* for camera view set the subrect */ + if (rv3d->persp == RV3D_CAMOB) { + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */ + r_gsc->subrect = &r_gsc->subrect_data; + } + } +} + + +/* Convert Grease Pencil points to screen-space values */ +void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, + int *r_x, int *r_y) +{ + ARegion *ar = gsc->ar; + View2D *v2d = gsc->v2d; + rctf *subrect = gsc->subrect; + int xyval[2]; + + if (gps->flag & GP_STROKE_3DSPACE) { + if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + *r_x = xyval[0]; + *r_y = xyval[1]; + } + else { + *r_x = V2D_IS_CLIPPED; + *r_y = V2D_IS_CLIPPED; + } + } + else if (gps->flag & GP_STROKE_2DSPACE) { + float vec[3] = {pt->x, pt->y, 0.0f}; + mul_m4_v3(gsc->mat, vec); + UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y); + } + else { + if (subrect == NULL) { /* normal 3D view */ + *r_x = (int)(pt->x / 100 * ar->winx); + *r_y = (int)(pt->y / 100 * ar->winy); + } + else { /* camera view, use subrect */ + *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin; + *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin; + } + } +} + +/* ******************************************************** */ diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h index 2acba04368c..b06af01bab6 100644 --- a/source/blender/editors/include/BIF_gl.h +++ b/source/blender/editors/include/BIF_gl.h @@ -56,14 +56,20 @@ void cpack(unsigned int x); # define glMultMatrixf(x) \ glMultMatrixf(_Generic((x), \ float *: (float *)(x), \ + float [16]: (float *)(x), \ float (*)[4]: (float *)(x), \ + float [4][4]: (float *)(x), \ const float *: (float *)(x), \ - const float (*)[4]: (float *)(x)) \ + const float [16]: (float *)(x), \ + const float (*)[4]: (float *)(x), \ + const float [4][4]: (float *)(x)) \ ) # define glLoadMatrixf(x) \ glLoadMatrixf(_Generic((x), \ float *: (float *)(x), \ - float (*)[4]: (float *)(x)) \ + float [16]: (float *)(x), \ + float (*)[4]: (float *)(x), \ + float [4][4]: (float *)(x)) \ ) #else # define glMultMatrixf(x) glMultMatrixf((float *)(x)) diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 956ec308daa..50581429700 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -159,6 +159,7 @@ typedef enum eAnim_ChannelType { ANIMTYPE_DSLAT, ANIMTYPE_DSLINESTYLE, ANIMTYPE_DSSPK, + ANIMTYPE_DSGPENCIL, ANIMTYPE_SHAPEKEY, @@ -457,7 +458,7 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level); /* Draw the given channel */ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc); /* Draw the widgets for the given channel */ -void ANIM_channel_draw_widgets(struct bContext *C, bAnimContext *ac, bAnimListElem *ale, struct uiBlock *block, float yminc, float ymaxc, size_t channel_index); +void ANIM_channel_draw_widgets(const struct bContext *C, bAnimContext *ac, bAnimListElem *ale, struct uiBlock *block, float yminc, float ymaxc, size_t channel_index); /* ------------------------ Editing API -------------------------- */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 05fb76b7aea..b0d1be1bf5d 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -30,6 +30,7 @@ #ifndef __ED_GPENCIL_H__ #define __ED_GPENCIL_H__ +struct ID; struct ListBase; struct bContext; struct bScreen; @@ -38,11 +39,11 @@ struct ARegion; struct View3D; struct SpaceNode; struct SpaceSeq; +struct Object; struct bGPdata; struct bGPDlayer; struct bGPDframe; struct PointerRNA; -struct Panel; struct ImBuf; struct wmKeyConfig; @@ -65,14 +66,32 @@ typedef struct tGPspoint { /* ----------- Grease Pencil Tools/Context ------------- */ +/* Context-dependent */ struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr); struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C); + +/* Context independent (i.e. each required part is passed in instead) */ +struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ID *screen_id, struct Scene *scene, + struct ScrArea *sa, struct Object *ob, + struct PointerRNA *ptr); +struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct Scene *scene, + struct ScrArea *sa, struct Object *ob); + +/* 3D View */ struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d); /* ----------- Grease Pencil Operators ----------------- */ void ED_keymap_gpencil(struct wmKeyConfig *keyconf); + void ED_operatortypes_gpencil(void); +void ED_operatormacros_gpencil(void); + +/* ------------- Copy-Paste Buffers -------------------- */ + +/* Strokes copybuf */ +void ED_gpencil_strokes_copybuf_free(void); + /* ------------ Grease-Pencil Drawing API ------------------ */ /* drawgpencil.c */ @@ -80,10 +99,8 @@ void ED_operatortypes_gpencil(void); void ED_gpencil_draw_2dimage(const struct bContext *C); void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d); void ED_gpencil_draw_view3d(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d); -void ED_gpencil_draw_ex(struct bGPdata *gpd, int winx, int winy, const int cfra); - -void ED_gpencil_panel_standard_header(const struct bContext *C, struct Panel *pa); -void ED_gpencil_panel_standard(const struct bContext *C, struct Panel *pa); +void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy, + const int cfra, const char spacetype); /* ----------- Grease-Pencil AnimEdit API ------------------ */ bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene, @@ -99,6 +116,8 @@ void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode bool ED_gplayer_frames_delete(struct bGPDlayer *gpl); void ED_gplayer_frames_duplicate(struct bGPDlayer *gpl); +void ED_gplayer_frames_keytype_set(struct bGPDlayer *gpl, short type); + void ED_gplayer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode); #if 0 diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index a9995de068e..1188ecd0aa5 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -79,5 +79,7 @@ int ED_space_image_maskedit_mask_poll(struct bContext *C); void ED_image_draw_info(struct Scene *scene, struct ARegion *ar, bool color_manage, bool use_default_view, int channels, int x, int y, const unsigned char cp[4], const float fp[4], const float linearcol[4], int *zp, float *zpf); +bool ED_space_image_show_cache(struct SpaceImage *sima); + #endif /* __ED_IMAGE_H__ */ diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index 58a262e150a..0359153317b 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -120,8 +120,9 @@ void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Obje void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos); /* DopeSheet Summary */ void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos); -/* Grease Pencil Layer */ -// XXX not restored +/* Grease Pencil datablock summary */ +void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos); +/* Grease Pencil Layer */ void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos); /* Mask Layer */ void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos); @@ -139,11 +140,11 @@ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); /* DopeSheet Summary */ void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); +/* Grease Pencil datablock summary */ +void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys); /* Grease Pencil Layer */ -// XXX not restored void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys); /* Mask */ -// XXX not restored void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay, struct DLRBT_Tree *keys); /* ActKeyColumn API ---------------- */ diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 197191b4f96..adf82acb399 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -58,6 +58,7 @@ typedef enum eEditKeyframes_Validate { BEZT_OK_VALUERANGE, BEZT_OK_REGION, BEZT_OK_REGION_LASSO, + BEZT_OK_REGION_CIRCLE, } eEditKeyframes_Validate; /* ------------ */ @@ -107,6 +108,14 @@ struct KeyframeEdit_LassoData { int mcords_tot; }; +/* use with BEZT_OK_REGION_CIRCLE */ +struct KeyframeEdit_CircleData { + const rctf *rectf_scaled; + const rctf *rectf_view; + float mval[2]; + float radius_squared; +}; + /* ************************************************ */ /* Non-Destuctive Editing API (keyframes_edit.c) */ @@ -261,7 +270,7 @@ void sample_fcurve(struct FCurve *fcu); void free_anim_copybuf(void); short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data); short paste_animedit_keys(struct bAnimContext *ac, ListBase *anim_data, - const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode); + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip); /* ************************************************ */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 5c7b3c531be..e5b5e79875d 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -293,7 +293,7 @@ bool ANIM_paste_driver(struct ReportList *reports, struct ID *id, const char rna (U.autokey_flag & AUTOKEY_FLAG_##flag)) /* auto-keyframing feature - checks for whether anything should be done for the current frame */ -int autokeyframe_cfra_can_key(struct Scene *scene, struct ID *id); +bool autokeyframe_cfra_can_key(struct Scene *scene, struct ID *id); /* ************ Keyframe Checking ******************** */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 2b4fa1b9196..8eb7fdf0c40 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -220,14 +220,8 @@ void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store); #define WEIGHT_SUBTRACT 3 bool ED_vgroup_sync_from_pose(struct Object *ob); -struct bDeformGroup *ED_vgroup_add(struct Object *ob); -struct bDeformGroup *ED_vgroup_add_name(struct Object *ob, const char *name); -void ED_vgroup_delete(struct Object *ob, struct bDeformGroup *defgroup); -void ED_vgroup_clear(struct Object *ob); void ED_vgroup_select_by_name(struct Object *ob, const char *name); -bool ED_vgroup_data_create(struct ID *id); void ED_vgroup_data_clamp_range(struct ID *id, const int total); -bool ED_vgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot); bool ED_vgroup_array_copy(struct Object *ob, struct Object *ob_from); bool ED_vgroup_parray_alloc(struct ID *id, struct MDeformVert ***dvert_arr, int *dvert_tot, const bool use_vert_sel); @@ -244,8 +238,6 @@ void ED_vgroup_mirror(struct Object *ob, const bool all_vgroups, const bool use_topology, int *r_totmirr, int *r_totfail); -bool ED_vgroup_object_is_edit_mode(struct Object *ob); - void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode); void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum); float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 39586039e8f..900da3ee07c 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -209,12 +209,6 @@ bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v) /* object_select.c */ void ED_object_select_linked_by_id(struct bContext *C, struct ID *id); - -bool *ED_vgroup_subset_from_select_type(struct Object *ob, enum eVGroupSelect subset_type, - int *r_vgroup_tot, int *r_subset_count); -void ED_vgroup_subset_to_index_array(const bool *vgroup_validmap, const int vgroup_tot, - int *r_vgroup_subset_map); - struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper( const struct bContext *C, struct PointerRNA *ptr, diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index ab1dbabe793..de3843c91eb 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -40,6 +40,7 @@ struct ScrArea; struct RegionView3D; struct RenderEngine; struct View3D; +struct wmWindowManager; /* render_ops.c */ @@ -52,7 +53,7 @@ void ED_render_engine_changed(struct Main *bmain); void ED_render_engine_area_exit(struct ScrArea *sa); void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated); -void ED_viewport_render_kill_jobs(const struct bContext *C, bool free_database); +void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database); struct Scene *ED_render_job_get_scene(const struct bContext *C); /* Render the preview @@ -71,8 +72,9 @@ void ED_preview_init_dbase(void); void ED_preview_free_dbase(void); void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, struct ID *parent, struct MTex *slot, int sizex, int sizey, int method); +void ED_preview_icon_render(struct Scene *scene, struct ID *id, unsigned int *rect, int sizex, int sizey); void ED_preview_icon_job(const struct bContext *C, void *owner, struct ID *id, unsigned int *rect, int sizex, int sizey); -void ED_preview_kill_jobs(const struct bContext *C); +void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain); void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index ed2465647da..b790c656b61 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -107,6 +107,7 @@ void ED_screen_set_subwinactive(struct bContext *C, struct wmEvent *event); void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen); void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable); void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh); +void ED_screen_retore_temp_type(struct bContext *C, ScrArea *sa, bool is_screen_change); ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type); void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa); void ED_screen_full_restore(struct bContext *C, ScrArea *sa); diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 85ff9b5d246..d3b1a824104 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -34,6 +34,7 @@ struct ARegion; struct bContext; struct Object; struct RegionView3D; +struct Scene; struct ViewContext; struct rcti; @@ -41,8 +42,6 @@ struct rcti; void ED_operatortypes_sculpt(void); void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob); -void ED_sculpt_stroke_get_average(struct Object *ob, float stroke[3]); -bool ED_sculpt_minmax(struct bContext *C, float min[3], float max[3]); int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend); #endif /* __ED_SCULPT_H__ */ diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h index 4e9d67df61e..94885c2abe0 100644 --- a/source/blender/editors/include/ED_sequencer.h +++ b/source/blender/editors/include/ED_sequencer.h @@ -27,6 +27,7 @@ #ifndef __ED_SEQUENCER_H__ #define __ED_SEQUENCER_H__ +struct bContext; struct Scene; struct Sequence; struct SpaceSeq; @@ -39,7 +40,12 @@ bool ED_space_sequencer_check_show_maskedit(struct SpaceSeq *sseq, struct Scene int ED_space_sequencer_maskedit_poll(struct bContext *C); bool ED_space_sequencer_check_show_imbuf(struct SpaceSeq *sseq); +bool ED_space_sequencer_check_show_strip(struct SpaceSeq *sseq); void ED_operatormacros_sequencer(void); +Sequence *ED_sequencer_special_preview_get(void); +void ED_sequencer_special_preview_set(struct bContext *C, const int mval[2]); +void ED_sequencer_special_preview_clear(void); + #endif /* __ED_SEQUENCER_H__ */ diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h index 9a36cb3d6ab..5df7d9cfaef 100644 --- a/source/blender/editors/include/ED_text.h +++ b/source/blender/editors/include/ED_text.h @@ -31,8 +31,11 @@ #define __ED_TEXT_H__ struct bContext; +struct SpaceText; +struct ARegion; void ED_text_undo_step(struct bContext *C, int step); +bool ED_text_region_location_from_cursor(struct SpaceText *st, struct ARegion *ar, const int cursor_co[2], int r_pixel_co[2]); #endif /* __ED_TEXT_H__ */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index daa6864b5aa..cf848098188 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -99,6 +99,7 @@ enum TfmMode { #define CTX_MOVIECLIP (1 << 6) #define CTX_MASK (1 << 7) #define CTX_PAINT_CURVE (1 << 8) +#define CTX_GPENCIL_STROKES (1 << 9) /* Standalone call to get the transformation center corresponding to the current situation * returns 1 if successful, 0 otherwise (usually means there's no selection) @@ -146,6 +147,7 @@ int BIF_countTransformOrientation(const struct bContext *C); #define P_CORRECT_UV (1 << 8) #define P_NO_DEFAULTS (1 << 10) #define P_NO_TEXSPACE (1 << 11) +#define P_GPENCIL_EDIT (1 << 12) void Transform_Properties(struct wmOperatorType *ot, int flags); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index bf3b18e143e..3e8f234e979 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -94,6 +94,8 @@ void uvedit_uv_select_disable(struct BMEditMesh *em, struct Scene *scene, struct bool ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima, const float co[2], float r_uv[2]); +void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy); + /* uvedit_unwrap_ops.c */ void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit); void ED_uvedit_live_unwrap_re_solve(void); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index bd4f37cfb1e..76ad4ba7bdb 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -309,7 +309,7 @@ void ED_view3d_draw_offscreen(struct Scene *scene, struct View3D *v3d, struct AR struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag, bool draw_background, int alpha_mode, char err_out[256]); struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, - bool use_solid_tex, bool draw_background, int alpha_mode, char err_out[256]); + bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]); void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]); struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 618fa44349e..fa349c4f006 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -589,8 +589,8 @@ DEF_ICON(MOD_WARP) DEF_ICON(MOD_SKIN) DEF_ICON(MOD_TRIANGULATE) DEF_ICON(MOD_WIREFRAME) +DEF_ICON(MOD_DATA_TRANSFER) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK167) DEF_ICON(BLANK168) DEF_ICON(BLANK169) DEF_ICON(BLANK170) @@ -876,8 +876,8 @@ DEF_ICON(FORWARD) DEF_ICON(BLANK312) DEF_ICON(BLANK313) DEF_ICON(BLANK314) - DEF_ICON(BLANK315) #endif +DEF_ICON(FILE_HIDDEN) DEF_ICON(FILE_BACKUP) DEF_ICON(DISK_DRIVE) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index d93872d81ff..8789e837f17 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -159,31 +159,32 @@ enum { /* but->flag - general state flags. */ enum { /* warning, the first 6 flags are internal */ - UI_BUT_ICON_SUBMENU = (1 << 6), - UI_BUT_ICON_PREVIEW = (1 << 7), - - UI_BUT_NODE_LINK = (1 << 8), - UI_BUT_NODE_ACTIVE = (1 << 9), - UI_BUT_DRAG_LOCK = (1 << 10), - UI_BUT_DISABLED = (1 << 11), - UI_BUT_COLOR_LOCK = (1 << 12), - UI_BUT_ANIMATED = (1 << 13), - UI_BUT_ANIMATED_KEY = (1 << 14), - UI_BUT_DRIVEN = (1 << 15), - UI_BUT_REDALERT = (1 << 16), - UI_BUT_INACTIVE = (1 << 17), - UI_BUT_LAST_ACTIVE = (1 << 18), - UI_BUT_UNDO = (1 << 19), - UI_BUT_IMMEDIATE = (1 << 20), - UI_BUT_NO_UTF8 = (1 << 21), - - UI_BUT_VEC_SIZE_LOCK = (1 << 22), /* used to flag if color hsv-circle should keep luminance */ - UI_BUT_COLOR_CUBIC = (1 << 23), /* cubic saturation for the color wheel */ - UI_BUT_LIST_ITEM = (1 << 24), /* This but is "inside" a list item (currently used to change theme colors). */ - UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */ - UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */ - UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */ - UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */ + UI_BUT_ICON_SUBMENU = (1 << 6), + UI_BUT_ICON_PREVIEW = (1 << 7), + + UI_BUT_NODE_LINK = (1 << 8), + UI_BUT_NODE_ACTIVE = (1 << 9), + UI_BUT_DRAG_LOCK = (1 << 10), + UI_BUT_DISABLED = (1 << 11), + UI_BUT_COLOR_LOCK = (1 << 12), + UI_BUT_ANIMATED = (1 << 13), + UI_BUT_ANIMATED_KEY = (1 << 14), + UI_BUT_DRIVEN = (1 << 15), + UI_BUT_REDALERT = (1 << 16), + UI_BUT_INACTIVE = (1 << 17), + UI_BUT_LAST_ACTIVE = (1 << 18), + UI_BUT_UNDO = (1 << 19), + UI_BUT_IMMEDIATE = (1 << 20), + UI_BUT_NO_UTF8 = (1 << 21), + + UI_BUT_VEC_SIZE_LOCK = (1 << 22), /* used to flag if color hsv-circle should keep luminance */ + UI_BUT_COLOR_CUBIC = (1 << 23), /* cubic saturation for the color wheel */ + UI_BUT_LIST_ITEM = (1 << 24), /* This but is "inside" a list item (currently used to change theme colors). */ + UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */ + UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */ + UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */ + UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */ + UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */ }; #define UI_PANEL_WIDTH 340 @@ -266,12 +267,12 @@ typedef enum { UI_BTYPE_CURVE = (32 << 9), UI_BTYPE_LISTBOX = (36 << 9), UI_BTYPE_LISTROW = (37 << 9), + UI_BTYPE_HSVCIRCLE = (38 << 9), UI_BTYPE_TRACK_PREVIEW = (40 << 9), /* buttons with value >= UI_BTYPE_SEARCH_MENU don't get undo pushes */ UI_BTYPE_SEARCH_MENU = (41 << 9), UI_BTYPE_EXTRA = (42 << 9), - UI_BTYPE_HSVCIRCLE = (43 << 9), UI_BTYPE_HOTKEY_EVENT = (46 << 9), UI_BTYPE_IMAGE = (47 << 9), /* non-interactive image, used for splash screen */ UI_BTYPE_HISTOGRAM = (48 << 9), @@ -313,6 +314,7 @@ void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad); void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown); void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight); +void UI_draw_text_underline(int pos_x, int pos_y, int len, int height); /* state for scrolldrawing */ #define UI_SCROLL_PRESSED (1 << 0) @@ -945,6 +947,7 @@ void uiItemS(uiLayout *layout); /* separator */ void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg); void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, const char *propname, const char *name, int icon); +void uiItemMenuEnumR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon); void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon); /* UI Operators */ @@ -999,6 +1002,7 @@ void UI_butstore_free(uiBlock *block, uiButStore *bs); bool UI_butstore_is_valid(uiButStore *bs); bool UI_butstore_is_registered(uiBlock *block, uiBut *but); void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p); +bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src); void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 6104505ef58..74927428363 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -33,6 +33,7 @@ #define __UI_INTERFACE_ICONS_H__ struct bContext; +struct ID; struct Image; struct ImBuf; struct World; @@ -63,6 +64,9 @@ void UI_icons_init(int first_dyn_id); int UI_icon_get_width(int icon_id); int UI_icon_get_height(int icon_id); +void UI_id_icon_render( + const struct bContext *C, struct Scene *scene, struct ID *id, const bool big, const bool use_job); + void UI_icon_draw(float x, float y, int icon_id); void UI_icon_draw_preview(float x, float y, int icon_id); void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 8e37e871501..d289e90c257 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -111,6 +111,8 @@ enum { TH_FACE_DOT, TH_FACEDOT_SIZE, TH_CFRAME, + TH_TIME_KEYFRAME, + TH_TIME_GP_KEYFRAME, TH_NURB_ULINE, TH_NURB_VLINE, TH_NURB_SEL_ULINE, @@ -207,6 +209,10 @@ enum { TH_HANDLE_VERTEX_SELECT, TH_HANDLE_VERTEX_SIZE, + TH_GP_VERTEX, + TH_GP_VERTEX_SELECT, + TH_GP_VERTEX_SIZE, + TH_DOPESHEET_CHANNELOB, TH_DOPESHEET_CHANNELSUBOB, @@ -266,7 +272,7 @@ enum { TH_NLA_SOUND, TH_NLA_SOUND_SEL, - TH_EMBOSS, + TH_WIDGET_EMBOSS, TH_AXIS_X, /* X/Y/Z Axis */ TH_AXIS_Y, @@ -295,6 +301,11 @@ enum { struct bTheme; struct PointerRNA; +struct bThemeState { + struct bTheme *theme; + int spacetype, regionid; +}; + // THE CODERS API FOR THEMES: // sets the color @@ -354,6 +365,9 @@ void UI_SetTheme(int spacetype, int regionid); // get current theme struct bTheme *UI_GetTheme(void); +void UI_Theme_Store(struct bThemeState *theme_state); +void UI_Theme_Restore(struct bThemeState *theme_state); + // return shadow width outside menus and popups */ int UI_ThemeMenuShadowWidth(void); diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index b921d17104c..972eca747b9 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -71,6 +71,12 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() +if(WIN32) + if(WITH_INPUT_IME) + add_definitions(-DWITH_INPUT_IME) + endif() +endif() + add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript index 303ab7ff286..5af8bba5a9f 100644 --- a/source/blender/editors/interface/SConscript +++ b/source/blender/editors/interface/SConscript @@ -48,6 +48,10 @@ incs = [ defs = env['BF_GL_DEFINITIONS'] +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'): + if env['WITH_BF_IME']: + defs.append('WITH_INPUT_IME') + if env['WITH_BF_INTERNATIONAL']: defs.append('WITH_INTERNATIONAL') diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 93f5a8e58d6..0b1d1c8c30c 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -209,6 +209,11 @@ void ui_window_to_region(const ARegion *ar, int *x, int *y) *y -= ar->winrct.ymin; } +void ui_region_to_window(const ARegion *ar, int *x, int *y) +{ + *x += ar->winrct.xmin; + *y += ar->winrct.ymin; +} /* ******************* block calc ************************* */ void ui_block_translate(uiBlock *block, int x, int y) @@ -723,6 +728,10 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu ui_but_update_linklines(block, oldbut, but); + if (!BLI_listbase_is_empty(&block->butstore)) { + UI_butstore_register_update(block, oldbut, but); + } + /* move/copy string from the new button to the old */ /* needed for alt+mouse wheel over enums */ if (but->str != but->strdata) { @@ -1712,6 +1721,9 @@ bool ui_but_is_bool(const uiBut *but) if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN) return true; + if ((but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM) && (but->type == UI_BTYPE_ROW)) + return true; + return false; } @@ -2152,6 +2164,32 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double return ok; } +/* just the assignment/free part */ +static void ui_but_string_set_internal(uiBut *but, const char *str, size_t str_len) +{ + BLI_assert(str_len == strlen(str)); + BLI_assert(but->str == NULL); + str_len += 1; + + if (str_len > UI_MAX_NAME_STR) { + but->str = MEM_mallocN(str_len, "ui_def_but str"); + } + else { + but->str = but->strdata; + } + memcpy(but->str, str, str_len); +} + +static void ui_but_string_free_internal(uiBut *but) +{ + if (but->str) { + if (but->str != but->strdata) { + MEM_freeN(but->str); + } + /* must call 'ui_but_string_set_internal' after */ + but->str = NULL; + } +} bool ui_but_string_set(bContext *C, uiBut *but, const char *str) { @@ -2599,9 +2637,13 @@ void ui_but_update(uiBut *but) UI_GET_BUT_VALUE_INIT(but, value); if (value < (double)but->hardmin) ui_but_value_set(but, but->hardmin); else if (value > (double)but->hardmax) ui_but_value_set(but, but->hardmax); + + /* max must never be smaller than min! Both being equal is allowed though */ + BLI_assert(but->softmin <= but->softmax && + but->hardmin <= but->hardmax); break; - case UI_BTYPE_ICON_TOGGLE: + case UI_BTYPE_ICON_TOGGLE: case UI_BTYPE_ICON_TOGGLE_N: if (!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) { if (but->flag & UI_SELECT) but->iconadd = 1; @@ -2631,7 +2673,9 @@ void ui_but_update(uiBut *but) if (RNA_property_enum_name_gettexted(but->block->evil_C, &but->rnapoin, but->rnaprop, value, &buf)) { - BLI_strncpy(but->str, buf, sizeof(but->strdata)); + size_t slen = strlen(buf); + ui_but_string_free_internal(but); + ui_but_string_set_internal(but, buf, slen); } } } @@ -3039,13 +3083,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, but->retval = retval; slen = strlen(str); - if (slen >= UI_MAX_NAME_STR) { - but->str = MEM_mallocN(slen + 1, "ui_def_but str"); - } - else { - but->str = but->strdata; - } - memcpy(but->str, str, slen + 1); + ui_but_string_set_internal(but, str, slen); but->rect.xmin = x; but->rect.ymin = y; diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 7e7806f6ada..24a30ebe3d8 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -34,13 +34,11 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_animsys.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_nla.h" diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 4dd952f0753..bcd9b9a5547 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -395,6 +395,12 @@ void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad) ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA); } +void UI_draw_text_underline(int pos_x, int pos_y, int len, int height) +{ + int ofs_y = 4 * U.pixelsize; + glRecti(pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize)); +} + /* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect) diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 7fed3772389..d7a4720d595 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -40,6 +40,7 @@ #include "BKE_screen.h" #include "BKE_report.h" #include "BKE_idcode.h" +#include "BKE_unit.h" #include "RNA_access.h" @@ -64,6 +65,42 @@ #include "ED_screen.h" #include "ED_view3d.h" +/* -------------------------------------------------------------------- */ +/* Utility Functions + */ +/** \name Generic Shared Functions + * \{ */ + +static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name) +{ + int width; + wmWindow *win = CTX_wm_window(C); + int x = win->eventstate->x; + int y = win->eventstate->y; + + if ((name[0] == '\0') || + (BLI_rcti_isect_pt(&ar->winrct, x, y) == false)) + { + return; + } + + width = UI_fontstyle_string_width(name); + x = x - ar->winrct.xmin; + y = y - ar->winrct.ymin; + + y += 20; + + glColor4ub(0, 0, 0, 50); + + UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA); + UI_draw_roundbox(x, y, x + width + 8, y + 15, 4); + + glColor4ub(255, 255, 255, 255); + UI_draw_string(x + 4, y + 4, name); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /* Eyedropper @@ -328,7 +365,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot) /* identifiers */ ot->name = "Eyedropper"; ot->idname = "UI_OT_eyedropper_color"; - ot->description = "Sample a color from the Blender Window to store in a property"; + ot->description = "Sample a data-block from the 3D view"; /* api callbacks */ ot->invoke = eyedropper_invoke; @@ -369,31 +406,7 @@ typedef struct DataDropper { static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) { DataDropper *ddr = arg; - int width; - const char *name = ddr->name; - wmWindow *win = CTX_wm_window(C); - int x = win->eventstate->x; - int y = win->eventstate->y; - - if ((name[0] == '\0') || - (BLI_rcti_isect_pt(&ar->winrct, x, y) == false)) - { - return; - } - - width = UI_fontstyle_string_width(name); - x = x - ar->winrct.xmin; - y = y - ar->winrct.ymin; - - y += 20; - - glColor4ub(0, 0, 0, 50); - - UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA); - UI_draw_roundbox(x, y, x + width + 8, y + 15, 4); - - glColor4ub(255, 255, 255, 255); - UI_draw_string(x + 4, y + 4, name); + eyedropper_draw_cursor_text(C, ar, ddr->name); } @@ -643,3 +656,309 @@ void UI_OT_eyedropper_id(wmOperatorType *ot) } /** \} */ + +/* -------------------------------------------------------------------- */ +/* Depth Dropper + * + * note: depthdropper is only internal name to avoid confusion in this file + */ + +/** \name Eyedropper (Depth) + * \{ */ + +typedef struct DepthDropper { + PointerRNA ptr; + PropertyRNA *prop; + + bool accum_start; /* has mouse been presed */ + float accum_depth; + int accum_tot; + + ARegionType *art; + void *draw_handle_pixel; + char name[200]; +} DepthDropper; + + +static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) +{ + DepthDropper *ddr = arg; + eyedropper_draw_cursor_text(C, ar, ddr->name); +} + + +static int depthdropper_init(bContext *C, wmOperator *op) +{ + DepthDropper *ddr; + int index_dummy; + + SpaceType *st; + ARegionType *art; + + st = BKE_spacetype_from_id(SPACE_VIEW3D); + art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); + + op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper"); + + UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); + + /* fallback to the active camera's dof */ + if (ddr->prop == NULL) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && (((ID *)v3d->camera->data)->lib == NULL)) { + RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); + ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); + } + } + } + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_type(ddr->prop) != PROP_FLOAT)) + { + return false; + } + + ddr->art = art; + ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); + + return true; +} + +static void depthdropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + DepthDropper *ddr = (DepthDropper *)op->customdata; + + if (ddr->art) { + ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); + } + + MEM_freeN(op->customdata); + + op->customdata = NULL; + } +} + +static void depthdropper_cancel(bContext *C, wmOperator *op) +{ + depthdropper_exit(C, op); +} + +/* *** depthdropper id helper functions *** */ +/** + * \brief get the ID from the screen. + * + */ +static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth) +{ + + /* we could use some clever */ + wmWindow *win = CTX_wm_window(C); + ScrArea *sa; + Scene *scene = win->screen->scene; + UnitSettings *unit = &scene->unit; + const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; + + ScrArea *area_prev = CTX_wm_area(C); + ARegion *ar_prev = CTX_wm_region(C); + + ddr->name[0] = '\0'; + + for (sa = win->screen->areabase.first; sa; sa = sa->next) { + if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) { + if (sa->spacetype == SPACE_VIEW3D) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->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 - ar->winrct.xmin, + my - ar->winrct.ymin}; + float co[3]; + + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* grr, always draw else we leave stale text */ + ED_region_tag_redraw(ar); + + view3d_operator_needs_opengl(C); + + if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) { + const float mval_center_fl[2] = { + (float)ar->winx / 2, + (float)ar->winy / 2}; + float co_align[3]; + + /* quick way to get view-center aligned point */ + ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align); + + *r_depth = len_v3v3(view_co, co_align); + + bUnit_AsString(ddr->name, sizeof(ddr->name), + (double)*r_depth, + 4, unit->system, B_UNIT_LENGTH, do_split, false); + } + else { + BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name)); + } + break; + } + } + } + } + + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, ar_prev); +} + +/* sets the sample depth RGB, maintaining A */ +static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth) +{ + RNA_property_float_set(&ddr->ptr, ddr->prop, depth); + RNA_property_update(C, &ddr->ptr, ddr->prop); +} + +/* set sample from accumulated values */ +static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr) +{ + float depth; + depth = ddr->accum_depth * 1.0f / (float)ddr->accum_tot; + depthdropper_depth_set(C, ddr, depth); +} + +/* single point sample & set */ +static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my) +{ + float depth = -1.0f; + if (depth != -1.0f) { + depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + depthdropper_depth_set(C, ddr, depth); + } +} + +static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my) +{ + float depth = -1.0f; + depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + if (depth != -1.0f) { + ddr->accum_depth += depth; + ddr->accum_tot++; + } +} + +/* main modal status check */ +static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + DepthDropper *ddr = (DepthDropper *)op->customdata; + + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + depthdropper_cancel(C, op); + return OPERATOR_CANCELLED; + case LEFTMOUSE: + if (event->val == KM_RELEASE) { + if (ddr->accum_tot == 0) { + depthdropper_depth_sample(C, ddr, event->x, event->y); + } + else { + depthdropper_depth_set_accum(C, ddr); + } + depthdropper_exit(C, op); + return OPERATOR_FINISHED; + } + else if (event->val == KM_PRESS) { + /* enable accum and make first sample */ + ddr->accum_start = true; + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + } + break; + case MOUSEMOVE: + if (ddr->accum_start) { + /* button is pressed so keep sampling */ + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + depthdropper_depth_set_accum(C, ddr); + } + break; + case SPACEKEY: + if (event->val == KM_RELEASE) { + ddr->accum_tot = 0; + ddr->accum_depth = 0.0f; + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + depthdropper_depth_set_accum(C, ddr); + } + break; + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (depthdropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + depthdropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int depthdropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (depthdropper_init(C, op)) { + /* cleanup */ + depthdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int depthdropper_poll(bContext *C) +{ + if (!CTX_wm_window(C)) return 0; + else return 1; +} + +void UI_OT_eyedropper_depth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Depth"; + ot->idname = "UI_OT_eyedropper_depth"; + ot->description = "Sample depth from the 3D view"; + + /* api callbacks */ + ot->invoke = depthdropper_invoke; + ot->modal = depthdropper_modal; + ot->cancel = depthdropper_cancel; + ot->exec = depthdropper_exec; + ot->poll = depthdropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING; + + /* properties */ +} + +/** \} */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index c841370a8fd..98b065dabcf 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -87,6 +87,10 @@ #include "WM_api.h" #include "WM_types.h" +#ifdef WITH_INPUT_IME +# include "wm_window.h" +#endif + /* place the mouse at the scaled down location when un-grabbing */ #define USE_CONT_MOUSE_CORRECT /* support dragging toggle buttons */ @@ -103,6 +107,9 @@ #define UI_MAX_PASSWORD_STR 128 +/* This hack is needed because we don't have a good way to re-reference keymap items once added: T42944 */ +#define USE_KEYMAP_ADD_HACK + /* proto */ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to); static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to); @@ -777,11 +784,18 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data) ui_but_string_set(C, but, data->str); ui_but_update(but); - /* give butfunc the original text too */ - /* feature used for bone renaming, channels, etc */ - /* afterfunc frees origstr */ - but->rename_orig = data->origstr; - data->origstr = NULL; + /* give butfunc a copy of the original text too. + * feature used for bone renaming, channels, etc. + * afterfunc frees rename_orig */ + if (data->origstr && (but->flag & UI_BUT_TEXTEDIT_UPDATE)) { + /* In this case, we need to keep origstr available, to restore real org string in case we cancel after + * having typed something already. */ + but->rename_orig = BLI_strdup(data->origstr); + } + else { + but->rename_orig = data->origstr; + data->origstr = NULL; + } ui_apply_but_func(C, but); data->retval = but->retval; @@ -2425,8 +2439,52 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in return changed; } +#ifdef WITH_INPUT_IME +/* enable ime, and set up uibut ime data */ +static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but)) +{ + /* XXX Is this really needed? */ + int x, y; + + BLI_assert(win->ime_data == NULL); + + /* enable IME and position to cursor, it's a trick */ + x = win->eventstate->x; + /* flip y and move down a bit, prevent the IME panel cover the edit button */ + y = win->eventstate->y - 12; + + wm_window_IME_begin(win, x, y, 0, 0, true); +} + +/* disable ime, and clear uibut ime data */ +static void ui_textedit_ime_end(wmWindow *win, uiBut *UNUSED(but)) +{ + wm_window_IME_end(win); +} + +void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete) +{ + BLI_assert(but->active); + + ui_region_to_window(but->active->region, &x, &y); + wm_window_IME_begin(but->active->window, x, y - 4, 0, 0, complete); +} + +/* should be ui_but_ime_data_get */ +wmIMEData *ui_but_get_ime_data(uiBut *but) +{ + if (but->active && but->active->window) { + return but->active->window->ime_data; + } + else { + return NULL; + } +} +#endif /* WITH_INPUT_IME */ + static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) { + wmWindow *win = CTX_wm_window(C); int len; if (data->str) { @@ -2482,12 +2540,18 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) but->flag &= ~UI_BUT_REDALERT; ui_but_update(but); - - WM_cursor_modal_set(CTX_wm_window(C), BC_TEXTEDITCURSOR); + + WM_cursor_modal_set(win, BC_TEXTEDITCURSOR); + +#ifdef WITH_INPUT_IME + ui_textedit_ime_begin(win, but); +#endif } static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) { + wmWindow *win = CTX_wm_window(C); + if (but) { if (ui_but_is_utf8(but)) { int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr)); @@ -2518,7 +2582,13 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) but->pos = -1; } - WM_cursor_modal_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(win); + +#ifdef WITH_INPUT_IME + if (win->ime_data) { + ui_textedit_ime_end(win, but); + } +#endif } static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) @@ -2583,6 +2653,14 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle int retval = WM_UI_HANDLER_CONTINUE; bool changed = false, inbox = false, update = false; +#ifdef WITH_INPUT_IME + wmWindow *win = CTX_wm_window(C); + wmIMEData *ime_data = win->ime_data; + bool is_ime_composing = ime_data && ime_data->is_ime_composing; +#else + bool is_ime_composing = false; +#endif + switch (event->type) { case MOUSEMOVE: case MOUSEPAN: @@ -2603,6 +2681,12 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle case RIGHTMOUSE: case ESCKEY: if (event->val == KM_PRESS) { +#ifdef WITH_INPUT_IME + /* skips button handling since it is not wanted */ + if (is_ime_composing) { + break; + } +#endif data->cancel = true; data->escapecancel = true; button_activate_state(C, but, BUTTON_STATE_EXIT); @@ -2660,7 +2744,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle } } - if (event->val == KM_PRESS) { + if (event->val == KM_PRESS && !is_ime_composing) { switch (event->type) { case VKEY: case XKEY: @@ -2776,7 +2860,15 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle break; } - if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)) { + if ((event->ascii || event->utf8_buf[0]) && + (retval == WM_UI_HANDLER_CONTINUE) +#ifdef WITH_INPUT_IME + && + !is_ime_composing && + !WM_event_is_ime_switch(event) +#endif + ) + { char ascii = event->ascii; const char *utf8_buf = event->utf8_buf; @@ -2806,10 +2898,30 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle retval = WM_UI_HANDLER_BREAK; } - /* textbutton with magnifier icon: do live update for search button */ - if (but->icon == ICON_VIEWZOOM) + /* textbutton with this flag: do live update (e.g. for search buttons) */ + if (but->flag & UI_BUT_TEXTEDIT_UPDATE) { update = true; + } + } + +#ifdef WITH_INPUT_IME + if (event->type == WM_IME_COMPOSITE_START || event->type == WM_IME_COMPOSITE_EVENT) { + changed = true; + + if (event->type == WM_IME_COMPOSITE_START && but->selend > but->selsta) { + ui_textedit_delete_selection(but, data); + } + if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) { + ui_textedit_type_buf( + but, data, + ime_data->str_result, + ime_data->result_len); + } } + else if (event->type == WM_IME_COMPOSITE_END) { + changed = true; + } +#endif if (changed) { /* only update when typing for TAB key */ @@ -3063,10 +3175,10 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data } } else if (data->state == BUTTON_STATE_WAIT_KEY_EVENT) { - - if (event->type == MOUSEMOVE) + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { return WM_UI_HANDLER_CONTINUE; - + } + if (event->type == LEFTMOUSE && event->val == KM_PRESS) { /* only cancel if click outside the button */ if (ui_but_contains_point_px(but->active->region, but, event->x, event->y) == 0) { @@ -5694,6 +5806,10 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) return block; } +#ifdef USE_KEYMAP_ADD_HACK +static int g_kmi_id_hack; +#endif + static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg) { wmWindowManager *wm = CTX_wm_manager(C); @@ -5734,7 +5850,10 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg) uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE); UI_block_bounds_set_popup(block, 6, -50, 26); - + +#ifdef USE_KEYMAP_ADD_HACK + g_kmi_id_hack = kmi_id; +#endif return block; } @@ -5743,9 +5862,20 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1) uiBut *but = (uiBut *)arg1; wmKeyMap *km; wmKeyMapItem *kmi; - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); - +#ifndef USE_KEYMAP_ADD_HACK + IDProperty *prop; +#endif + int kmi_id; + +#ifdef USE_KEYMAP_ADD_HACK + km = WM_keymap_guess_opname(C, but->optype->idname); + kmi_id = g_kmi_id_hack; + UNUSED_VARS(but); +#else + prop = (but->opptr) ? but->opptr->data : NULL; + kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); +#endif + kmi = WM_keymap_item_find_id(km, kmi_id); WM_keymap_remove_item(km, kmi); } @@ -6161,6 +6291,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } } } + else if (but->type == UI_BTYPE_NUM) { + if (but->rnaprop && + (RNA_property_type(but->rnaprop) == PROP_FLOAT) && + (RNA_property_subtype(but->rnaprop) & PROP_UNIT_LENGTH) && + (RNA_property_array_check(but->rnaprop) == false)) + { + WM_operator_name_call(C, "UI_OT_eyedropper_depth", WM_OP_INVOKE_DEFAULT, NULL); + return WM_UI_HANDLER_BREAK; + } + } } } /* handle keyframing */ @@ -6256,6 +6396,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_TOGGLE_N: case UI_BTYPE_CHECKBOX: case UI_BTYPE_CHECKBOX_N: + case UI_BTYPE_ROW: retval = ui_do_but_TOG(C, but, data, event); break; case UI_BTYPE_SCROLL: @@ -6278,7 +6419,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * break; case UI_BTYPE_ROUNDBOX: case UI_BTYPE_LABEL: - case UI_BTYPE_ROW: case UI_BTYPE_IMAGE: case UI_BTYPE_PROGRESS_BAR: case UI_BTYPE_NODE_SOCKET: @@ -9087,6 +9227,7 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata) ui_popup_block_free(C, menu); UI_popup_handlers_remove(&win->modalhandlers, menu); + CTX_wm_menu_set(C, NULL); #ifdef USE_DRAG_TOGGLE { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 51dd9166e46..679681cb372 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -51,6 +51,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_icons.h" +#include "BKE_appdir.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -587,7 +588,7 @@ static void init_internal_icons(void) #if 0 // temp disabled if ((btheme != NULL) && btheme->tui.iconfile[0]) { - char *icondir = BLI_get_folder(BLENDER_DATAFILES, "icons"); + char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); char iconfilestr[FILE_MAX]; if (icondir) { @@ -702,12 +703,12 @@ static void init_iconfile_list(struct ListBase *list) const char *icondir; BLI_listbase_clear(list); - icondir = BLI_get_folder(BLENDER_DATAFILES, "icons"); + icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); if (icondir == NULL) return; - totfile = BLI_dir_contents(icondir, &dir); + totfile = BLI_filelist_dir_contents(icondir, &dir); for (i = 0; i < totfile; i++) { if ((dir[i].type & S_IFREG)) { @@ -755,7 +756,7 @@ static void init_iconfile_list(struct ListBase *list) } } - BLI_free_filelist(dir, totfile); + BLI_filelist_free(dir, totfile, NULL); dir = NULL; } @@ -930,7 +931,8 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size) /* only called when icon has changed */ /* only call with valid pointer from UI_icon_draw */ -static void icon_set_image(bContext *C, ID *id, PreviewImage *prv_img, enum eIconSizes size) +static void icon_set_image( + const bContext *C, Scene *scene, ID *id, PreviewImage *prv_img, enum eIconSizes size, const bool use_job) { if (!prv_img) { if (G.debug & G_DEBUG) @@ -940,8 +942,17 @@ static void icon_set_image(bContext *C, ID *id, PreviewImage *prv_img, enum eIco icon_create_rect(prv_img, size); - ED_preview_icon_job(C, prv_img, id, prv_img->rect[size], - prv_img->w[size], prv_img->h[size]); + if (use_job) { + /* Job (background) version */ + ED_preview_icon_job(C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); + } + else { + if (!scene) { + scene = CTX_data_scene(C); + } + /* Immediate version */ + ED_preview_icon_render(scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); + } } PreviewImage *UI_icon_to_preview(int icon_id) @@ -1148,29 +1159,30 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al } } -static void ui_id_preview_image_render_size(bContext *C, ID *id, PreviewImage *pi, int size) +static void ui_id_preview_image_render_size( + const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job) { if ((pi->changed[size] || !pi->rect[size])) { /* changed only ever set by dynamic icons */ /* create the rect if necessary */ - icon_set_image(C, id, pi, size); + icon_set_image(C, scene, id, pi, size, use_job); pi->changed[size] = 0; } } -static void ui_id_icon_render(bContext *C, ID *id, const bool big) +void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job) { PreviewImage *pi = BKE_previewimg_get(id); if (pi) { if (big) - ui_id_preview_image_render_size(C, id, pi, ICON_SIZE_PREVIEW); /* bigger preview size */ + ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_PREVIEW, use_job); /* bigger preview size */ else - ui_id_preview_image_render_size(C, id, pi, ICON_SIZE_ICON); /* icon size */ + ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_ICON, use_job); /* icon size */ } } -static void ui_id_brush_render(bContext *C, ID *id) +static void ui_id_brush_render(const bContext *C, ID *id) { PreviewImage *pi = BKE_previewimg_get(id); enum eIconSizes i; @@ -1182,14 +1194,14 @@ static void ui_id_brush_render(bContext *C, ID *id) /* check if rect needs to be created; changed * only set by dynamic icons */ if ((pi->changed[i] || !pi->rect[i])) { - icon_set_image(C, id, pi, i); + icon_set_image(C, NULL, id, pi, i, true); pi->changed[i] = 0; } } } -static int ui_id_brush_get_icon(bContext *C, ID *id) +static int ui_id_brush_get_icon(const bContext *C, ID *id) { Brush *br = (Brush *)id; @@ -1242,7 +1254,7 @@ static int ui_id_brush_get_icon(bContext *C, ID *id) return id->icon_id; } -int ui_id_icon_get(bContext *C, ID *id, const bool big) +int ui_id_icon_get(const bContext *C, ID *id, const bool big) { int iconid = 0; @@ -1258,7 +1270,7 @@ int ui_id_icon_get(bContext *C, ID *id, const bool big) case ID_LA: /* fall through */ iconid = BKE_icon_getid(id); /* checks if not exists, or changed */ - ui_id_icon_render(C, id, big); + UI_id_icon_render(C, NULL, id, big, true); break; default: break; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 328822e47ef..54ba3d784d1 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -433,6 +433,7 @@ extern void ui_block_to_window_rctf(const struct ARegion *ar, uiBlock *block, rc extern void ui_window_to_block_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y); extern void ui_window_to_block(const struct ARegion *ar, uiBlock *block, int *x, int *y); extern void ui_window_to_region(const ARegion *ar, int *x, int *y); +extern void ui_region_to_window(const struct ARegion *ar, int *x, int *y); extern double ui_but_value_get(uiBut *but); extern void ui_but_value_set(uiBut *but, double value); @@ -627,6 +628,11 @@ void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa); uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new); uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new); +#ifdef WITH_INPUT_IME +void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete); +struct wmIMEData *ui_but_get_ime_data(uiBut *but); +#endif + /* interface_widgets.c */ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha); @@ -653,7 +659,7 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na void uiStyleInit(void); /* interface_icons.c */ -int ui_id_icon_get(struct bContext *C, struct ID *id, const bool big); +int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big); /* resources.c */ void init_userdef_do_versions(void); @@ -688,5 +694,6 @@ void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, fl /* interface_eyedropper.c */ void UI_OT_eyedropper_color(struct wmOperatorType *ot); void UI_OT_eyedropper_id(struct wmOperatorType *ot); +void UI_OT_eyedropper_depth(struct wmOperatorType *ot); #endif /* __INTERFACE_INTERN_H__ */ diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 2d952d66638..f02c6a234a9 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -904,7 +904,7 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname if (prop && RNA_property_type(prop) == PROP_ENUM) { EnumPropertyItem *item, *item_array = NULL; bool free; - uiLayout *split; + uiLayout *split = NULL; uiLayout *target; if (radial) { @@ -1450,8 +1450,8 @@ typedef struct CollItemSearch { static int sort_search_items_list(const void *a, const void *b) { - CollItemSearch *cis1 = (CollItemSearch *)a; - CollItemSearch *cis2 = (CollItemSearch *)b; + const CollItemSearch *cis1 = (CollItemSearch *)a; + const CollItemSearch *cis2 = (CollItemSearch *)b; if (BLI_strcasecmp(cis1->name, cis2->name) > 0) return 1; @@ -1492,7 +1492,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, const char *s BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui)); #endif name = BLI_strdup(name_ui); - iconid = ui_id_icon_get((bContext *)C, id, false); + iconid = ui_id_icon_get(C, id, false); } else { name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */ @@ -1922,17 +1922,9 @@ static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void layout->root->block->flag |= UI_BLOCK_IS_FLIP; } -void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon) +void uiItemMenuEnumR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon) { MenuItemLevel *lvl; - PropertyRNA *prop; - - prop = RNA_struct_find_property(ptr, propname); - if (!prop) { - ui_item_disabled(layout, propname); - RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); - return; - } if (!name) name = RNA_property_ui_name(prop); @@ -1941,12 +1933,26 @@ void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propn lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); lvl->rnapoin = *ptr; - BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname)); + BLI_strncpy(lvl->propname, RNA_property_identifier(prop), sizeof(lvl->propname)); lvl->opcontext = layout->root->opcontext; ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl, RNA_property_description(prop), false); } +void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon) +{ + PropertyRNA *prop; + + prop = RNA_struct_find_property(ptr, propname); + if (!prop) { + ui_item_disabled(layout, propname); + RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + return; + } + + uiItemMenuEnumR_prop(layout, ptr, prop, name, icon); +} + /**************************** Layout Items ***************************/ /* single-row layout */ diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 4cb587bc1be..074faaa86bc 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -45,7 +45,6 @@ #include "BKE_global.h" #include "BKE_text.h" /* for UI_OT_reports_to_text */ #include "BKE_report.h" -#include "BKE_paint.h" #include "RNA_access.h" #include "RNA_define.h" @@ -950,4 +949,5 @@ void ED_button_operatortypes(void) /* external */ WM_operatortype_append(UI_OT_eyedropper_color); WM_operatortype_append(UI_OT_eyedropper_id); + WM_operatortype_append(UI_OT_eyedropper_depth); } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index fc39b63a71d..e68c86353a3 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -753,9 +753,13 @@ static int find_highest_panel(const void *a1, const void *a2) const PanelSort *ps1 = a1, *ps2 = a2; /* stick uppermost header-less panels to the top of the region - - * prevent them from being sorted */ - if (ps1->pa->sortorder < ps2->pa->sortorder && ps1->pa->type->flag & PNL_NO_HEADER) return -1; - + * prevent them from being sorted (multiple header-less panels have to be sorted though) */ + if (ps1->pa->type->flag & PNL_NO_HEADER && ps2->pa->type->flag & PNL_NO_HEADER) { + /* skip and check for ofs and sortorder below */ + } + else if (ps1->pa->type->flag & PNL_NO_HEADER) return -1; + else if (ps2->pa->type->flag & PNL_NO_HEADER) return 1; + if (ps1->pa->ofsy + ps1->pa->sizey < ps2->pa->ofsy + ps2->pa->sizey) return 1; else if (ps1->pa->ofsy + ps1->pa->sizey > ps2->pa->ofsy + ps2->pa->sizey) return -1; else if (ps1->pa->sortorder > ps2->pa->sortorder) return 1; @@ -1226,7 +1230,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in bool UI_panel_category_is_visible(ARegion *ar) { - /* more then one */ + /* more than one */ return ar->panels_category.first && ar->panels_category.first != ar->panels_category.last; } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 6a4bf230591..0ec59e4e4cd 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -27,8 +27,6 @@ * \ingroup edinterface */ - - #include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -54,7 +52,6 @@ #include "WM_types.h" #include "wm_draw.h" #include "wm_subwindow.h" -#include "wm_window.h" #include "RNA_access.h" @@ -365,7 +362,8 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) /* special case enum rna buttons */ if ((but->type & UI_BTYPE_ROW) && but->rnaprop && RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) { - BLI_strncpy(data->lines[data->totline], IFACE_("(Shift-click to select multiple)"), sizeof(data->lines[0])); + BLI_strncpy(data->lines[data->totline], IFACE_("(Shift-Click/Drag to select multiple)"), + sizeof(data->lines[0])); data->format[data->totline].color_id = UI_TIP_LC_NORMAL; data->totline++; diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index d2aa463e3ff..8b2ce90dcf5 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -47,7 +47,9 @@ #include "BLF_api.h" -#include "BLF_translation.h" +#ifdef WITH_INTERNATIONAL +# include "BLF_translation.h" +#endif #include "UI_interface.h" diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 95cb36a4672..407843d663c 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -31,7 +31,6 @@ #include "MEM_guardedalloc.h" -#include "DNA_dynamicpaint_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -74,7 +73,6 @@ #include "ED_util.h" #include "RNA_access.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -156,7 +154,7 @@ static void id_search_cb(const bContext *C, void *arg_template, const char *str, char name_ui[MAX_ID_NAME + 1]; name_uiprefix_id(name_ui, id); - iconid = ui_id_icon_get((bContext *)C, id, template->preview); + iconid = ui_id_icon_get(C, id, template->preview); if (false == UI_search_item_add(items, name_ui, id, iconid)) break; @@ -352,6 +350,8 @@ static const char *template_id_browse_tip(StructRNA *type) case ID_BR: return N_("Browse Brush to be linked"); case ID_PA: return N_("Browse Particle Settings to be linked"); case ID_GD: return N_("Browse Grease Pencil Data to be linked"); + case ID_MC: return N_("Browse Movie Clip to be linked"); + case ID_MSK: return N_("Browse Mask to be linked"); case ID_PAL: return N_("Browse Palette Data to be linked"); case ID_PC: return N_("Browse Paint Curve Data to be linked"); } @@ -390,6 +390,10 @@ static const char *template_id_context(StructRNA *type) case ID_BR: return BLF_I18NCONTEXT_ID_BRUSH; case ID_PA: return BLF_I18NCONTEXT_ID_PARTICLESETTINGS; case ID_GD: return BLF_I18NCONTEXT_ID_GPENCIL; + case ID_MC: return BLF_I18NCONTEXT_ID_MOVIECLIP; + case ID_MSK: return BLF_I18NCONTEXT_ID_MASK; + case ID_PAL: return BLF_I18NCONTEXT_ID_PALETTE; + case ID_PC: return BLF_I18NCONTEXT_ID_PAINTCURVE; } } return BLF_I18NCONTEXT_DEFAULT; @@ -473,11 +477,12 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str if (id->us > 1) { char numstr[32]; + short numstr_len; - BLI_snprintf(numstr, sizeof(numstr), "%d", id->us); + numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", id->us); - but = uiDefBut(block, UI_BTYPE_BUT, 0, numstr, 0, 0, UI_UNIT_X + ((id->us < 10) ? 0 : 10), UI_UNIT_Y, - NULL, 0, 0, 0, 0, + but = uiDefBut(block, UI_BTYPE_BUT, 0, numstr, 0, 0, + numstr_len * 0.2f * UI_UNIT_X + UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Display number of users of this data (click to make a single-user copy)")); but->flag |= UI_BUT_UNDO; @@ -2667,7 +2672,7 @@ static void uilist_filter_items_default(struct uiList *ui_list, struct bContext names = MEM_callocN(sizeof(StringCmp) * len, "StringCmp"); } if (filter_raw[0]) { - size_t idx = 0, slen = strlen(filter_raw); + size_t slen = strlen(filter_raw); dyn_data->items_filter_flags = MEM_callocN(sizeof(int) * len, "items_filter_flags"); dyn_data->items_shown = 0; @@ -2679,15 +2684,7 @@ static void uilist_filter_items_default(struct uiList *ui_list, struct bContext else { filter = filter_dyn = MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn"); } - if (filter_raw[idx] != '*') { - filter[idx++] = '*'; - } - memcpy(filter + idx, filter_raw, slen); - idx += slen; - if (filter[idx - 1] != '*') { - filter[idx++] = '*'; - } - filter[idx] = '\0'; + BLI_strncpy_ensure_pad(filter, filter_raw, '*', slen + 3); } RNA_PROP_BEGIN (dataptr, itemptr, prop) diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 854f1763370..28bd637ae59 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -83,13 +83,21 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind int arraylen = RNA_property_array_length(ptr, prop); if (arraylen && index == -1) { - if (ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA)) + if (ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA)) { but = uiDefButR_prop(block, UI_BTYPE_COLOR, 0, name, x1, y1, x2, y2, ptr, prop, -1, 0, 0, -1, -1, NULL); + } + else { + return NULL; + } } else if (RNA_property_subtype(prop) == PROP_PERCENTAGE || RNA_property_subtype(prop) == PROP_FACTOR) but = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); else but = uiDefButR_prop(block, UI_BTYPE_NUM, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); + + if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { + UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); + } break; } case PROP_ENUM: @@ -107,6 +115,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind but = uiDefIconTextButR_prop(block, UI_BTYPE_TEXT, 0, icon, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); else but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); + + if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { + UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); + } break; case PROP_POINTER: { @@ -390,6 +402,27 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p) } /** + * Update the pointer for a registered button. + */ +bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src) +{ + uiButStore *bs_handle; + bool found = false; + + for (bs_handle = block->butstore.first; bs_handle; bs_handle = bs_handle->next) { + uiButStoreElem *bs_elem; + for (bs_elem = bs_handle->items.first; bs_elem; bs_elem = bs_elem->next) { + if (*bs_elem->but_p == but_src) { + *bs_elem->but_p = but_dst; + found = true; + } + } + } + + return found; +} + +/** * NULL all pointers, don't free since the owner needs to be able to inspect. */ void UI_butstore_clear(uiBlock *block) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index c9def075666..04a886ba2a8 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -59,6 +59,10 @@ #include "interface_intern.h" +#ifdef WITH_INPUT_IME +# include "WM_types.h" +#endif + /* icons are 80% of height of button (16 pixels inside 20 height) */ #define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect)) @@ -757,10 +761,9 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2); /* emboss bottom shadow */ - UI_GetThemeColor4ubv(TH_EMBOSS, emboss); - if (wtb->emboss) { - UI_GetThemeColor4ubv(TH_EMBOSS, emboss); + UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss); + if (emboss[3]) { glColor4ubv(emboss); glVertexPointer(2, GL_FLOAT, 0, quad_strip_emboss); @@ -1232,6 +1235,50 @@ static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); } +#ifdef WITH_INPUT_IME +static void widget_draw_text_ime_underline( + uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, const rcti *rect, + const wmIMEData *ime_data, const char *drawstr) +{ + int ofs_x, width; + int rect_x = BLI_rcti_size_x(rect); + int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end; + + if (drawstr[0] != 0) { + if (but->pos >= but->ofs) { + ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs); + } + else { + ofs_x = 0; + } + + width = BLF_width(fstyle->uifont_id, drawstr + but->ofs, + ime_data->composite_len + but->pos - but->ofs); + + glColor4ubv((unsigned char *)wcol->text); + UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1); + + /* draw the thick line */ + if (sel_start != -1 && sel_end != -1) { + sel_end -= sel_start; + sel_start += but->pos; + + if (sel_start >= but->ofs) { + ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_start - but->ofs); + } + else { + ofs_x = 0; + } + + width = BLF_width(fstyle->uifont_id, drawstr + but->ofs, + sel_end + sel_start - but->ofs); + + UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2); + } + } +} +#endif /* WITH_INPUT_IME */ + static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect) { int drawstr_left_len = UI_MAX_DRAW_STR; @@ -1239,6 +1286,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b const char *drawstr_right = NULL; bool use_right_only = false; +#ifdef WITH_INPUT_IME + const wmIMEData *ime_data; +#endif + UI_fontstyle_set(fstyle); if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT)) @@ -1266,13 +1317,30 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b /* max length isn't used in this case, * we rely on string being NULL terminated. */ drawstr_left_len = INT_MAX; - drawstr = but->editstr; + +#ifdef WITH_INPUT_IME + /* FIXME, IME is modifying 'const char *drawstr! */ + ime_data = ui_but_get_ime_data(but); + + if (ime_data && ime_data->composite_len) { + /* insert composite string into cursor pos */ + BLI_snprintf((char *)drawstr, UI_MAX_DRAW_STR, "%s%s%s", + but->editstr, ime_data->str_composite, + but->editstr + but->pos); + } + else +#endif + { + drawstr = but->editstr; + } } } - /* text button selection and cursor */ + /* text button selection, cursor, composite underline */ if (but->editstr && but->pos != -1) { + int but_pos_ofs; + int tx, ty; /* text button selection */ if ((but->selend - but->selsta) > 0) { @@ -1298,18 +1366,44 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b } /* text cursor */ + but_pos_ofs = but->pos; + +#ifdef WITH_INPUT_IME + /* if is ime compositing, move the cursor */ + if (ime_data && ime_data->composite_len && ime_data->cursor_pos != -1) { + but_pos_ofs += ime_data->cursor_pos; + } +#endif + if (but->pos >= but->ofs) { int t; if (drawstr[0] != 0) { - t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs); + t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but_pos_ofs - but->ofs); } else { t = 0; } glColor3f(0.20, 0.6, 0.9); - glRecti(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2); + + tx = rect->xmin + t + 2; + ty = rect->ymin + 2; + + /* draw cursor */ + glRecti(rect->xmin + t, ty, tx, rect->ymax - 2); + } + +#ifdef WITH_INPUT_IME + if (ime_data && ime_data->composite_len) { + /* ime cursor following */ + if (but->pos >= but->ofs) { + ui_but_ime_reposition(but, tx + 5, ty + 3, false); + } + + /* composite underline */ + widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr); } +#endif } if (fstyle->kerning == 1) @@ -2780,7 +2874,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s uiWidgetBase wtb, wtb1; rcti rect1; double value; - float offs, toffs, fac; + float offs, toffs, fac = 0; char outline[3]; widget_init(&wtb); @@ -2811,7 +2905,9 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s rect1 = *rect; value = ui_but_value_get(but); - fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin); + if ((but->softmax - but->softmin) > 0) { + fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin); + } /* left part of slider, always rounded */ rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 5573515391d..aa5b2570952 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -45,6 +45,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BKE_appdir.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_main.h" @@ -60,9 +61,16 @@ /* global for themes */ typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha); -static bTheme *theme_active = NULL; -static int theme_spacetype = SPACE_VIEW3D; -static int theme_regionid = RGN_TYPE_WINDOW; +/* be sure to keep 'bThemeState' in sync */ +static struct bThemeState g_theme_state = { + NULL, + SPACE_VIEW3D, + RGN_TYPE_WINDOW, +}; + +#define theme_active g_theme_state.theme +#define theme_spacetype g_theme_state.spacetype +#define theme_regionid g_theme_state.regionid void ui_resources_init(void) { @@ -371,6 +379,10 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->keyborder_select; break; case TH_CFRAME: cp = ts->cframe; break; + case TH_TIME_KEYFRAME: + cp = ts->time_keyframe; break; + case TH_TIME_GP_KEYFRAME: + cp = ts->time_gp_keyframe; break; case TH_NURB_ULINE: cp = ts->nurb_uline; break; case TH_NURB_VLINE: @@ -505,6 +517,17 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo case TH_HANDLE_VERTEX_SIZE: cp = &ts->handle_vertex_size; break; + + case TH_GP_VERTEX: + cp = ts->gp_vertex; + break; + case TH_GP_VERTEX_SELECT: + cp = ts->gp_vertex_select; + break; + case TH_GP_VERTEX_SIZE: + cp = &ts->gp_vertex_size; + break; + case TH_DOPESHEET_CHANNELOB: cp = ts->ds_channel; break; @@ -619,8 +642,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->nla_sound_sel; break; - case TH_EMBOSS: - cp = btheme->tui.emboss; break; + case TH_WIDGET_EMBOSS: + cp = btheme->tui.widget_emboss; break; case TH_AXIS_X: cp = btheme->tui.xaxis; break; @@ -663,7 +686,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo } } - return (unsigned char *)cp; + return (const unsigned char *)cp; } /* use this call to init new bone color sets in Theme */ @@ -820,7 +843,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255); - rgba_char_args_set_fl(btheme->tui.emboss, 1.0f, 1.0f, 1.0f, 0.02f); + rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f); rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255); rgba_char_args_set(btheme->tui.yaxis, 0, 220, 0, 255); @@ -892,6 +915,9 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51); rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f); rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f); + rgba_char_args_set(btheme->tv3d.gp_vertex, 0, 0, 0, 255); + rgba_char_args_set(btheme->tv3d.gp_vertex_select, 255, 133, 0, 255); + btheme->tv3d.gp_vertex_size = 3; btheme->tv3d.facedot_size = 4; @@ -1111,6 +1137,9 @@ void ui_theme_init_default(void) rgba_char_args_set_fl(btheme->ttime.grid, 0.36, 0.36, 0.36, 1.0); rgba_char_args_set(btheme->ttime.shade1, 173, 173, 173, 255); /* sliders */ + rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 1.0); + rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0); + /* space node, re-uses syntax and console color storage */ btheme->tnode = btheme->tv3d; rgba_char_args_set(btheme->tnode.syntaxr, 115, 115, 115, 255); /* wire inner color */ @@ -1193,6 +1222,18 @@ bTheme *UI_GetTheme(void) return U.themes.first; } +/** + * for the rare case we need to temp swap in a different theme (offscreen render) + */ +void UI_Theme_Store(struct bThemeState *theme_state) +{ + *theme_state = g_theme_state; +} +void UI_Theme_Restore(struct bThemeState *theme_state) +{ + g_theme_state = *theme_state; +} + /* for space windows only */ void UI_ThemeColor(int colorid) { @@ -1534,7 +1575,7 @@ void init_userdef_do_versions(void) } if (U.mixbufsize == 0) U.mixbufsize = 2048; if (strcmp(U.tempdir, "/") == 0) { - BLI_system_temporary_dir(U.tempdir); + BKE_tempdir_system_init(U.tempdir); } if (U.autokey_mode == 0) { /* 'add/replace' but not on */ @@ -2498,10 +2539,36 @@ void init_userdef_do_versions(void) } } - if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) { + if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 3)) { bTheme *btheme; for (btheme = U.themes.first; btheme; btheme = btheme->next) { - rgba_char_args_set_fl(btheme->tui.emboss, 1.0f, 1.0f, 1.0f, 0.02f); + rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f); + } + } + + if (U.versionfile < 273 || (U.versionfile == 273 && U.subversionfile < 1)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + /* Grease Pencil vertex settings */ + rgba_char_args_set(btheme->tv3d.gp_vertex, 0, 0, 0, 255); + rgba_char_args_set(btheme->tv3d.gp_vertex_select, 255, 133, 0, 255); + btheme->tv3d.gp_vertex_size = 3; + + rgba_char_args_set(btheme->tseq.gp_vertex, 0, 0, 0, 255); + rgba_char_args_set(btheme->tseq.gp_vertex_select, 255, 133, 0, 255); + btheme->tseq.gp_vertex_size = 3; + + rgba_char_args_set(btheme->tima.gp_vertex, 0, 0, 0, 255); + rgba_char_args_set(btheme->tima.gp_vertex_select, 255, 133, 0, 255); + btheme->tima.gp_vertex_size = 3; + + rgba_char_args_set(btheme->tnode.gp_vertex, 0, 0, 0, 255); + rgba_char_args_set(btheme->tnode.gp_vertex_select, 255, 133, 0, 255); + btheme->tnode.gp_vertex_size = 3; + + /* Timeline Keyframe Indicators */ + rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 1.0); + rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0); } } diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f42e35945d7..de46d47e5a3 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -2305,7 +2305,7 @@ void UI_view2d_text_cache_add(View2D *v2d, float x, float y, BLI_LINKS_PREPEND(g_v2d_strings, v2s); - v2s->col.pack = *((int *)col); + v2s->col.pack = *((const int *)col); memset(&v2s->rect, 0, sizeof(v2s->rect)); @@ -2336,7 +2336,7 @@ void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view, BLI_LINKS_PREPEND(g_v2d_strings, v2s); - v2s->col.pack = *((int *)col); + v2s->col.pack = *((const int *)col); v2s->rect = rect; diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index bbf4447dd72..491152b02e5 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -298,7 +298,7 @@ void WM_OT_collada_export(wmOperatorType *ot) ot->ui = wm_collada_export_draw; - WM_operator_properties_filesel(ot, FOLDERFILE | COLLADAFILE, FILE_BLENDER, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, @@ -365,6 +365,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) { char filename[FILE_MAX]; int import_units; + int find_chains; + int fix_orientation; + int min_chain_length; if (!RNA_struct_property_is_set(op->ptr, "filepath")) { BKE_report(op->reports, RPT_ERROR, "No filename given"); @@ -372,10 +375,19 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) } /* Options panel */ - import_units = RNA_boolean_get(op->ptr, "import_units"); + import_units = RNA_boolean_get(op->ptr, "import_units"); + find_chains = RNA_boolean_get(op->ptr, "find_chains"); + fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation"); + min_chain_length = RNA_int_get(op->ptr, "min_chain_length"); RNA_string_get(op->ptr, "filepath", filename); - if (collada_import(C, filename, import_units)) { + if (collada_import( + C, filename, + import_units, + find_chains, + fix_orientation, + min_chain_length)) + { return OPERATOR_FINISHED; } else { @@ -395,6 +407,19 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, false); uiItemR(row, imfptr, "import_units", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Armature Options:"), ICON_MESH_DATA); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "fix_orientation", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "find_chains", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE); } static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op) @@ -419,13 +444,31 @@ void WM_OT_collada_import(wmOperatorType *ot) ot->ui = wm_collada_import_draw; - WM_operator_properties_filesel(ot, FOLDERFILE | COLLADAFILE, FILE_BLENDER, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, - "import_units", 0, "Import Units", - "If disabled match import to Blender's current Unit settings, " - "otherwise use the settings from the Imported scene"); + "import_units", 0, "Import Units", + "If disabled match import to Blender's current Unit settings, " + "otherwise use the settings from the Imported scene"); + + RNA_def_boolean(ot->srna, + "fix_orientation", 0, "Fix Leaf Bones", + "Fix Orientation of Leaf Bones (Collada does only support Joints)"); + + RNA_def_boolean(ot->srna, + "find_chains", 0, "Find Bone Chains", + "Find best matching Bone Chains and ensure bones in chain are connected"); + + RNA_def_int(ot->srna, + "min_chain_length", + 0, + 0, + INT_MAX, + "Minimum Chain Length", + "When searching Bone Chains disregard chains of length below this value", + 0, + INT_MAX); } #endif diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index a33340cc39a..a70a51a60be 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -28,16 +28,13 @@ * \ingroup collada */ - -#include "io_collada.h" - -#include "BLI_utildefines.h" - -#include "WM_types.h" -#include "WM_api.h" - #include "io_ops.h" /* own include */ +#ifdef WITH_COLLADA +# include "io_collada.h" +# include "WM_api.h" +#endif + void ED_operatortypes_io(void) { #ifdef WITH_COLLADA diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 93e59f3244e..929c4f74b2f 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -784,7 +784,7 @@ static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event) SlidePointData *slidedata; if (mask == NULL) { - return OPERATOR_CANCELLED; + return OPERATOR_PASS_THROUGH; } slidedata = slide_point_customdata(C, op, event); @@ -1286,7 +1286,7 @@ static int slide_spline_curvature_invoke(bContext *C, wmOperator *op, const wmEv SlideSplineCurvatureData *slide_data; if (mask == NULL) { - return OPERATOR_CANCELLED; + return OPERATOR_PASS_THROUGH; } /* Be sure we don't conflict with point slide here. */ diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c index e02561d839c..4e0aa8f84ae 100644 --- a/source/blender/editors/mask/mask_relationships.c +++ b/source/blender/editors/mask/mask_relationships.c @@ -39,7 +39,6 @@ #include "BKE_tracking.h" #include "DNA_mask_types.h" -#include "DNA_object_types.h" /* SELECT */ #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 87b429f1165..113f0f71b53 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -31,8 +31,6 @@ #include "BLI_math.h" #include "BLI_bitmap.h" -#include "BLF_translation.h" - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 3e403387a67..9b1b0b915c1 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -54,18 +54,6 @@ #include "mesh_intern.h" /* own include */ -/* allow accumulated normals to form a new direction but don't - * accept direct opposite directions else they will cancel each other out */ -static void add_normal_aligned(float nor[3], const float add[3]) -{ - if (dot_v3v3(nor, add) < -0.9999f) { - sub_v3_v3(nor, add); - } - else { - add_v3_v3(nor, add); - } -} - static void edbm_extrude_edge_exclude_mirror( Object *obedit, BMEditMesh *em, const char hflag, @@ -137,7 +125,7 @@ static void edbm_extrude_edge_exclude_mirror( /* individual face extrude */ /* will use vertex normals for extrusion directions, so *nor is unaffected */ -static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) +static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag) { BMOIter siter; BMIter liter; @@ -165,14 +153,14 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c } if (!EDBM_op_finish(em, &bmop, op, true)) { - return 0; + return false; } - return 's'; /* s is shrink/fatten */ + return true; } /* extrudes individual edges */ -static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) +static bool edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag) { BMesh *bm = em->bm; BMOperator bmop; @@ -191,14 +179,14 @@ static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); if (!EDBM_op_finish(em, &bmop, op, true)) { - return 0; + return false; } - return 'n'; /* n is normal grab */ + return true; } /* extrudes individual vertices */ -static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) +static bool edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag) { BMOperator bmop; @@ -214,27 +202,55 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true); if (!EDBM_op_finish(em, &bmop, op, true)) { - return 0; + return false; + } + + return true; +} + +static char edbm_extrude_htype_from_em_select(BMEditMesh *em) +{ + char htype = BM_ALL_NOLOOP; + + if (em->selectmode & SCE_SELECT_VERTEX) { + /* pass */ + } + else if (em->selectmode & SCE_SELECT_EDGE) { + htype &= ~BM_VERT; + } + else { + htype &= ~(BM_VERT | BM_EDGE); + } + + if (em->bm->totedgesel == 0) { + htype &= ~(BM_EDGE | BM_FACE); + } + else if (em->bm->totfacesel == 0) { + htype &= ~BM_FACE; } - return 'g'; /* g is grab */ + return htype; } -static short edbm_extrude_edge_ex( +static bool edbm_extrude_ex( Object *obedit, BMEditMesh *em, - const char hflag, float nor[3], + char htype, const char hflag, const bool use_mirror, const bool use_select_history) { BMesh *bm = em->bm; BMOIter siter; BMOperator extop; - BMFace *f; BMElem *ele; + /* needed to remove the faces left behind */ + if (htype & BM_FACE) { + htype |= BM_EDGE; + } + BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region"); BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history); - BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE, hflag); + BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag); if (use_mirror) { BMOpSlot *slot_edges_exclude; @@ -248,61 +264,14 @@ static short edbm_extrude_edge_ex( BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(bm, &extop); - - zero_v3(nor); - BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL) { + BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) { BM_elem_select_set(bm, ele, true); - - if (ele->head.htype == BM_FACE) { - f = (BMFace *)ele; - add_normal_aligned(nor, f->no); - } } - normalize_v3(nor); - BMO_op_finish(bm, &extop); - /* grab / normal constraint */ - return is_zero_v3(nor) ? 'g' : 'n'; -} - -static short edbm_extrude_edge( - Object *obedit, BMEditMesh *em, - const char hflag, float nor[3]) -{ - return edbm_extrude_edge_ex(obedit, em, hflag, nor, true, true); -} - -static short edbm_extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float nor[3]) -{ - BMIter iter; - BMEdge *eed; - - /* ensure vert flags are consistent for edge selections */ - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, hflag)) { - if (hflag & BM_ELEM_SELECT) { - BM_vert_select_set(em->bm, eed->v1, true); - BM_vert_select_set(em->bm, eed->v2, true); - } - - BM_elem_flag_enable(eed->v1, hflag & ~BM_ELEM_SELECT); - BM_elem_flag_enable(eed->v2, hflag & ~BM_ELEM_SELECT); - } - else { - if (BM_elem_flag_test(eed->v1, hflag) && BM_elem_flag_test(eed->v2, hflag)) { - if (hflag & BM_ELEM_SELECT) { - BM_edge_select_set(em->bm, eed, true); - } - - BM_elem_flag_enable(eed, hflag & ~BM_ELEM_SELECT); - } - } - } - - return edbm_extrude_edge(obedit, em, hflag, nor); + return true; } static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) @@ -314,7 +283,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) const int steps = RNA_int_get(op->ptr, "steps"); const float offs = RNA_float_get(op->ptr, "offset"); - float dvec[3], tmat[3][3], bmat[3][3], nor[3] = {0.0, 0.0, 0.0}; + float dvec[3], tmat[3][3], bmat[3][3]; short a; /* dvec */ @@ -327,7 +296,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) mul_m3_v3(tmat, dvec); for (a = 0; a < steps; a++) { - edbm_extrude_edge_ex(obedit, em, BM_ELEM_SELECT, nor, false, false); + edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false); BMO_op_callf( em->bm, BMO_FLAG_DEFAULTS, @@ -362,87 +331,58 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) } /* generic extern called extruder */ -static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin) +static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) { - short nr, transmode = 0; - float stacknor[3] = {0.0f, 0.0f, 0.0f}; - float *nor = norin ? norin : stacknor; - - zero_v3(nor); + bool changed = false; + const char htype = edbm_extrude_htype_from_em_select(em); + enum {NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY} nr; if (em->selectmode & SCE_SELECT_VERTEX) { - if (em->bm->totvertsel == 0) nr = 0; - else if (em->bm->totvertsel == 1) nr = 4; - else if (em->bm->totedgesel == 0) nr = 4; - else if (em->bm->totfacesel == 0) - nr = 3; - else if (em->bm->totfacesel == 1) - nr = 1; - else - nr = 1; + if (em->bm->totvertsel == 0) nr = NONE; + else if (em->bm->totvertsel == 1) nr = VERT_ONLY; + else if (em->bm->totedgesel == 0) nr = VERT_ONLY; + else nr = ELEM_FLAG; } else if (em->selectmode & SCE_SELECT_EDGE) { - if (em->bm->totedgesel == 0) nr = 0; - - nr = 1; + if (em->bm->totedgesel == 0) nr = NONE; + else if (em->bm->totfacesel == 0) nr = EDGE_ONLY; + else nr = ELEM_FLAG; } else { - if (em->bm->totfacesel == 0) nr = 0; - else if (em->bm->totfacesel == 1) nr = 1; - else - nr = 1; + if (em->bm->totfacesel == 0) nr = NONE; + else nr = ELEM_FLAG; } - if (nr < 1) return 'g'; - - if (nr == 1 && (em->selectmode & SCE_SELECT_VERTEX)) - transmode = edbm_extrude_vert(obedit, em, BM_ELEM_SELECT, nor); - else if (nr == 1) transmode = edbm_extrude_edge(obedit, em, BM_ELEM_SELECT, nor); - else if (nr == 4) transmode = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor); - else if (nr == 3) transmode = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor); - else transmode = edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT, nor); + switch (nr) { + case NONE: + return false; + case ELEM_FLAG: + changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, true, true); + break; + case VERT_ONLY: + changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); + break; + case EDGE_ONLY: + changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); + break; + } - if (transmode == 0) { - BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude"); + if (changed) { + return true; } else { - - /* We need to force immediate calculation here because - * transform may use derived objects (which are now stale). - * - * This shouldn't be necessary, derived queries should be - * automatically building this data if invalid. Or something. - */ -// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); - BKE_object_handle_update(G.main->eval_ctx, scene, obedit); - - /* individual faces? */ - if (nr == 2) { -// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR); -// Transform(); - } - else { -// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR); - if (transmode == 'n') { - mul_m4_v3(obedit->obmat, nor); - sub_v3_v3v3(nor, nor, obedit->obmat[3]); -// BIF_setSingleAxisConstraint(nor, "along normal"); - } -// Transform(); - } + BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude"); + return false; } - - return transmode; } /* extrude without transform */ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - edbm_extrude_mesh(scene, obedit, em, op, NULL); + edbm_extrude_mesh(obedit, em, op); /* This normally happens when pushing undo but modal operators * like this one don't push undo data until after modal mode is @@ -476,9 +416,8 @@ static int edbm_extrude_verts_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - float nor[3]; - edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor); + edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); EDBM_update_generic(em, true, true); @@ -507,9 +446,8 @@ static int edbm_extrude_edges_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - float nor[3]; - edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor); + edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); EDBM_update_generic(em, true, true); @@ -538,9 +476,8 @@ static int edbm_extrude_faces_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - float nor[3]; - edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT, nor); + edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); EDBM_update_generic(em, true, true); @@ -578,7 +515,6 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE)); @@ -593,6 +529,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w /* call extrude? */ if (done) { + const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em); const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source"); BMEdge *eed; float vec[3], cent[3], mat[3][3]; @@ -686,7 +623,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w EMBM_project_snap_verts(C, vc.ar, vc.em); } - edbm_extrude_edge(vc.obedit, vc.em, BM_ELEM_SELECT, nor); + edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, true, true); EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, cent, mat); EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index df6776950d7..e2e4638254b 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -38,7 +38,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "WM_api.h" #include "WM_types.h" #include "ED_mesh.h" @@ -334,7 +333,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op)) BMVert *v_other = BM_edge_other_vert(e, v); float e_dir[3]; - /* we wan't closest to zero */ + /* we want closest to zero */ float dot_best = FLT_MAX; sub_v3_v3v3(e_dir, v_other->co, v->co); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index b08f7ef9613..0a78f299159 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -75,10 +75,16 @@ #define KMAXDIST 10 /* max mouse distance from edge before not detecting it */ +/* WARNING: knife float precision is fragile: + * be careful before making changes here see: (T43229, T42864, T42459, T41164). + */ #define KNIFE_FLT_EPS 0.00001f #define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS) #define KNIFE_FLT_EPSBIG 0.0005f -#define KNIFE_FLT_EPS_PX 0.2f + +#define KNIFE_FLT_EPS_PX_VERT 0.5f +#define KNIFE_FLT_EPS_PX_EDGE 0.05f +#define KNIFE_FLT_EPS_PX_FACE 0.05f typedef struct KnifeColors { unsigned char line[3]; @@ -97,7 +103,7 @@ typedef struct KnifeVert { float co[3], cageco[3], sco[2]; /* sco is screen coordinates for cageco */ bool is_face, in_space; - bool draw; + bool is_cut; /* along a cut created by user input (will draw too) */ } KnifeVert; typedef struct Ref { @@ -111,7 +117,7 @@ typedef struct KnifeEdge { ListBase faces; BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */ - bool draw; + bool is_cut; /* along a cut created by user input (will draw too) */ } KnifeEdge; typedef struct KnifeLineHit { @@ -529,7 +535,7 @@ static KnifeVert *knife_split_edge( newkfe->v1 = kfe->v1; newkfe->v2 = new_knife_vert(kcd, co, cageco); - newkfe->v2->draw = 1; + newkfe->v2->is_cut = true; if (kfe->e) { knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e); } @@ -554,7 +560,7 @@ static KnifeVert *knife_split_edge( knife_add_to_vert_edges(kcd, newkfe); - newkfe->draw = kfe->draw; + newkfe->is_cut = kfe->is_cut; newkfe->e = kfe->e; *r_kfe = newkfe; @@ -603,6 +609,7 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd) { KnifeLineHit *linehits, *lhi, *lhj; int i, j, n; + bool is_double = false; n = kcd->totlinehit; linehits = kcd->linehits; @@ -626,7 +633,11 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd) { break; } - lhj->l = -1.0f; + + if (lhi->kfe == lhj->kfe) { + lhj->l = -1.0f; + is_double = true; + } } for (j = i + 1; j < n; j++) { lhj = &linehits[j]; @@ -635,37 +646,42 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd) { break; } - if (lhj->kfe || lhi->v == lhj->v) { + if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || + (lhi->v == lhj->v)) + { lhj->l = -1.0f; + is_double = true; } } } } - /* delete-in-place loop: copying from pos j to pos i+1 */ - i = 0; - j = 1; - while (j < n) { - lhi = &linehits[i]; - lhj = &linehits[j]; - if (lhj->l == -1.0f) { - j++; /* skip copying this one */ - } - else { - /* copy unless a no-op */ - if (lhi->l == -1.0f) { - /* could happen if linehits[0] is being deleted */ - memcpy(&linehits[i], &linehits[j], sizeof(KnifeLineHit)); + if (is_double) { + /* delete-in-place loop: copying from pos j to pos i+1 */ + i = 0; + j = 1; + while (j < n) { + lhi = &linehits[i]; + lhj = &linehits[j]; + if (lhj->l == -1.0f) { + j++; /* skip copying this one */ } else { - if (i + 1 != j) - memcpy(&linehits[i + 1], &linehits[j], sizeof(KnifeLineHit)); - i++; + /* copy unless a no-op */ + if (lhi->l == -1.0f) { + /* could happen if linehits[0] is being deleted */ + memcpy(&linehits[i], &linehits[j], sizeof(KnifeLineHit)); + } + else { + if (i + 1 != j) + memcpy(&linehits[i + 1], &linehits[j], sizeof(KnifeLineHit)); + i++; + } + j++; } - j++; } + kcd->totlinehit = i + 1; } - kcd->totlinehit = i + 1; } /* Add hit to list of hits in facehits[f], where facehits is a map, if not already there */ @@ -683,6 +699,7 @@ static void add_hit_to_facehits(KnifeTool_OpData *kcd, GHash *facehits, BMFace * static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, KnifeLineHit *lh2, BMFace *f) { KnifeEdge *kfe, *kfe2; + BMEdge *e_base; if ((lh1->v && lh1->v == lh2->v) || (lh1->kfe && lh1->kfe == lh2->kfe)) @@ -690,15 +707,25 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife return; } + /* if the cut is on an edge, just tag that its a cut and return */ + if ((lh1->v && lh2->v) && + (lh1->v->v && lh2->v && lh2->v->v) && + (e_base = BM_edge_exists(lh1->v->v, lh2->v->v))) + { + kfe = get_bm_knife_edge(kcd, e_base); + kfe->is_cut = true; + kfe->e = e_base; + return; + } /* Check if edge actually lies within face (might not, if this face is concave) */ - if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) { + else if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) { if (!knife_verts_edge_in_face(lh1->v, lh2->v, f)) { return; } } kfe = new_knife_edge(kcd); - kfe->draw = true; + kfe->is_cut = true; kfe->basef = f; if (lh1->v) { @@ -711,7 +738,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife else { BLI_assert(lh1->f); kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit); - kfe->v1->draw = true; + kfe->v1->is_cut = true; kfe->v1->is_face = true; knife_append_list(kcd, &kfe->v1->faces, lh1->f); lh1->v = kfe->v1; /* record the KnifeVert for this hit */ @@ -727,7 +754,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife else { BLI_assert(lh2->f); kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit); - kfe->v2->draw = true; + kfe->v2->is_cut = true; kfe->v2->is_face = true; knife_append_list(kcd, &kfe->v2->faces, lh2->f); lh2->v = kfe->v2; /* record the KnifeVert for this hit */ @@ -748,19 +775,13 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits) { Ref *r; - KnifeLineHit *lh, *prevlh; if (BLI_listbase_count_ex(hits, 2) != 2) return; - prevlh = NULL; - for (r = hits->first; r; r = r->next) { - lh = (KnifeLineHit *)r->ref; - if (prevlh) - knife_add_single_cut(kcd, prevlh, lh, f); - prevlh = lh; + for (r = hits->first; r->next; r = r->next) { + knife_add_single_cut(kcd, r->ref, r->next->ref, f); } - } /* User has just left-clicked after the first time. @@ -1076,7 +1097,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) BLI_mempool_iternew(kcd->kedges, &iter); for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { - if (!kfe->draw) + if (!kfe->is_cut) continue; glColor3ubv(kcd->colors.line); @@ -1098,7 +1119,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) glBegin(GL_POINTS); BLI_mempool_iternew(kcd->kverts, &iter); for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { - if (!kfv->draw) + if (!kfv->is_cut) continue; glColor3ubv(kcd->colors.point); @@ -1206,9 +1227,82 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) kcd->ortho_extent = max_xyz; } -/* Check if p is visible (not clipped, not occluded by another face). - * s in screen projection of p. */ -static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats) +static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe) +{ + BMElem *ele_test; + KnifeEdge *kfe = NULL; + + /* vert? */ + ele_test = (BMElem *)kfv->v; + + if (r_kfe || ele_test == NULL) { + if (kfv->v == NULL) { + Ref *ref; + for (ref = kfv->edges.first; ref; ref = ref->next) { + kfe = ref->ref; + if (kfe->e) { + *r_kfe = kfe; + break; + } + } + } + } + + /* edge? */ + if (ele_test == NULL) { + if (kfe) { + ele_test = (BMElem *)kfe->e; + } + } + + /* face? */ + if (ele_test == NULL) { + if (BLI_listbase_is_single(&kfe->faces)) { + ele_test = ((Ref *)kfe->faces.first)->ref; + } + } + + return ele_test; +} + +static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe) +{ + BMElem *ele_test; + + ele_test = (BMElem *)kfe->e; + + if (ele_test == NULL) { + ele_test = (BMElem *)kfe->basef; + } + + return ele_test; +} + +static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data) +{ + switch (((BMElem *)user_data)->head.htype) { + case BM_FACE: + return (BMFace *)user_data != f; + case BM_EDGE: + return !BM_edge_in_face((BMEdge *)user_data, f); + case BM_VERT: + return !BM_vert_in_face((BMVert *)user_data, f); + default: + return true; + } +} + + +/** + * Check if \a p is visible (not clipped, not occluded by another face). + * s in screen projection of p. + * + * \param ele_test Optional vert/edge/face to use when \a p is on the surface of the geometry, + * intersecting faces matching this face (or connected when an vert/edge) will be ignored. + */ +static bool point_is_visible( + KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats, + BMElem *ele_test) { BMFace *f_hit; @@ -1232,7 +1326,7 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa /* make p_ofs a little towards view, so ray doesn't hit p's face. */ sub_v3_v3(view, p); dist = normalize_v3(view); - madd_v3_v3v3fl(p_ofs, p, view, KNIFE_FLT_EPSBIG * 3.0f); + copy_v3_v3(p_ofs, p); /* avoid projecting behind the viewpoint */ if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { @@ -1251,9 +1345,19 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa } /* see if there's a face hit between p1 and the view */ - f_hit = BKE_bmbvh_ray_cast(kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL); - if (f_hit) + if (ele_test) { + f_hit = BKE_bmbvh_ray_cast_filter( + kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL, + bm_ray_cast_cb_elem_not_in_face_check, ele_test); + } + else { + f_hit = BKE_bmbvh_ray_cast( + kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL); + } + + if (f_hit) { return false; + } } return true; @@ -1295,6 +1399,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) SmallHashIter hiter; KnifeLineHit hit; void *val; + void **val_p; float plane_cos[12]; float s[2], se1[2], se2[2], sint[2]; float r1[3], r2[3]; @@ -1302,7 +1407,6 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) float vert_tol, vert_tol_sq; float line_tol, line_tol_sq; float face_tol, face_tol_sq; - float eps_scale; int isect_kind; unsigned int tot; int i; @@ -1383,6 +1487,11 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) ls = (BMLoop **)kcd->em->looptris[result->indexA]; f = ls[0]->f; set_lowest_face_tri(kcd, f, result->indexA); + + /* occlude but never cut unselected faces (when only_select is used) */ + if (kcd->only_select && !BM_elem_flag_test(f, BM_ELEM_SELECT)) { + continue; + } /* for faces, store index of lowest hit looptri in hash */ if (BLI_smallhash_haskey(&faces, (uintptr_t)f)) { continue; @@ -1397,27 +1506,18 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) continue; BLI_smallhash_insert(&kfes, (uintptr_t)kfe, kfe); v = kfe->v1; - if (!BLI_smallhash_haskey(&kfvs, (uintptr_t)v)) - BLI_smallhash_insert(&kfvs, (uintptr_t)v, v); + BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v); v = kfe->v2; - if (!BLI_smallhash_haskey(&kfvs, (uintptr_t)v)) - BLI_smallhash_insert(&kfvs, (uintptr_t)v, v); + BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v); } } /* Now go through the candidates and find intersections */ /* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */ - { - /* Scale the epsilon by the zoom level - * to compensate for projection imprecision, see T41164 */ - float zoom_xy[2] = {kcd->vc.rv3d->winmat[0][0], - kcd->vc.rv3d->winmat[1][1]}; - eps_scale = len_v2(zoom_xy); - } - vert_tol = KNIFE_FLT_EPS_PX * eps_scale; - line_tol = KNIFE_FLT_EPS_PX * eps_scale; - face_tol = max_ff(vert_tol, line_tol); + vert_tol = KNIFE_FLT_EPS_PX_VERT; + line_tol = KNIFE_FLT_EPS_PX_EDGE; + face_tol = KNIFE_FLT_EPS_PX_FACE; vert_tol_sq = vert_tol * vert_tol; line_tol_sq = line_tol * line_tol; @@ -1426,44 +1526,55 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) /* Assume these tolerances swamp floating point rounding errors in calculations below */ /* first look for vertex hits */ - for (val = BLI_smallhash_iternew(&kfvs, &hiter, (uintptr_t *)&v); val; - val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&v)) + for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p; + val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v)) { + KnifeEdge *kfe_hit = NULL; + knife_project_v2(kcd, v->cageco, s); d = dist_squared_to_line_segment_v2(s, s1, s2); - if (d <= vert_tol_sq) { - if (point_is_visible(kcd, v->cageco, s, &mats)) { - memset(&hit, 0, sizeof(hit)); - hit.v = v; + if ((d <= vert_tol_sq) && + (point_is_visible(kcd, v->cageco, s, &mats, bm_elem_from_knife_vert(v, &kfe_hit)))) + { + memset(&hit, 0, sizeof(hit)); + hit.v = v; - /* If this isn't from an existing BMVert, it may have been added to a BMEdge originally. + /* If this isn't from an existing BMVert, it may have been added to a BMEdge originally. * knowing if the hit comes from an edge is important for edge-in-face checks later on * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */ - if (v->v == NULL) { - for (ref = v->edges.first; ref; ref = ref->next) { - kfe = ref->ref; - if (kfe->e) { - hit.kfe = kfe; - break; - } - } - } - - copy_v3_v3(hit.hit, v->co); - copy_v3_v3(hit.cagehit, v->cageco); - copy_v2_v2(hit.schit, s); - set_linehit_depth(kcd, &hit); - BLI_array_append(linehits, hit); + if (kfe_hit) { + hit.kfe = kfe_hit; } + + copy_v3_v3(hit.hit, v->co); + copy_v3_v3(hit.cagehit, v->cageco); + copy_v2_v2(hit.schit, s); + set_linehit_depth(kcd, &hit); + BLI_array_append(linehits, hit); + } + else { + /* note that these vertes aren't used */ + *val_p = NULL; } } + /* now edge hits; don't add if a vertex at end of edge should have hit */ for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val; val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) { + int kfe_verts_in_cut; + /* if we intersect both verts, don't attempt to intersect the edge */ + + kfe_verts_in_cut = (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) != NULL) + + (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2) != NULL); + + if (kfe_verts_in_cut == 2) { + continue; + } + knife_project_v2(kcd, kfe->v1->cageco, se1); knife_project_v2(kcd, kfe->v2->cageco, se2); - isect_kind = isect_seg_seg_v2_point(s1, s2, se1, se2, sint); + isect_kind = (kfe_verts_in_cut) ? -1 : isect_seg_seg_v2_point(s1, s2, se1, se2, sint); if (isect_kind == -1) { /* isect_seg_seg_v2 doesn't do tolerance test around ends of s1-s2 */ closest_to_line_segment_v2(sint, s1, se1, se2); @@ -1486,7 +1597,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) * Need to find 3d intersection of ray through sint */ knife_input_ray_segment(kcd, sint, 1.0f, r1, r2); isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp); - if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats)) { + if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats, bm_elem_from_knife_edge(kfe))) { memset(&hit, 0, sizeof(hit)); if (kcd->snap_midpoints) { /* choose intermediate point snap too */ @@ -1515,7 +1626,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) float p[3], p_cage[3]; if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) { - if (point_is_visible(kcd, p_cage, s1, &mats)) { + if (point_is_visible(kcd, p_cage, s1, &mats, (BMElem *)f)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); @@ -1527,7 +1638,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) { - if (point_is_visible(kcd, p_cage, s2, &mats)) { + if (point_is_visible(kcd, p_cage, s2, &mats, (BMElem *)f)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); @@ -1589,6 +1700,10 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, 0.0f, NULL, co, cageco); + if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) { + f = NULL; + } + if (is_space) *is_space = !f; @@ -1983,34 +2098,17 @@ static int knife_update_active(KnifeTool_OpData *kcd) return 1; } -/* sort list of kverts by fraction along edge e */ -static void sort_by_frac_along(ListBase *lst, BMEdge *e) +static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cur_b_p) { - /* note, since we know the point is along the edge, sort from distance to v1co */ - const float *v1co = e->v1->co; - Ref *cur = NULL, *prev = NULL, *next = NULL; - - if (lst->first == lst->last) - return; - - for (cur = ((Ref *)lst->first)->next; cur; cur = next) { - KnifeVert *vcur = cur->ref; - const float vcur_fac_sq = len_squared_v3v3(v1co, vcur->co); + const KnifeVert *cur_a = ((const Ref *)cur_a_p)->ref; + const KnifeVert *cur_b = ((const Ref *)cur_b_p)->ref; + const float *co = co_p; + const float a_sq = len_squared_v3v3(co, cur_a->co); + const float b_sq = len_squared_v3v3(co, cur_b->co); - next = cur->next; - prev = cur->prev; - - BLI_remlink(lst, cur); - - while (prev) { - KnifeVert *vprev = prev->ref; - if (len_squared_v3v3(v1co, vprev->co) <= vcur_fac_sq) - break; - prev = prev->prev; - } - - BLI_insertlinkafter(lst, prev, cur); - } + if (a_sq < b_sq) return -1; + else if (a_sq > b_sq) return 1; + else return 0; } /* The chain so far goes from an instantiated vertex to kfv (some may be reversed). @@ -2341,13 +2439,22 @@ static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f) { bool v1_inside, v2_inside; bool v1_inface, v2_inface; + BMLoop *l1, *l2; if (!f || !v1 || !v2) return false; + l1 = v1->v ? BM_face_vert_share_loop(f, v1->v) : NULL; + l2 = v2->v ? BM_face_vert_share_loop(f, v2->v) : NULL; + + if ((l1 && l2) && BM_loop_is_adjacent(l1, l2)) { + /* boundary-case, always false to avoid edge-in-face checks below */ + return false; + } + /* find out if v1 and v2, if set, are part of the face */ - v1_inface = v1->v ? BM_vert_in_face(f, v1->v) : false; - v2_inface = v2->v ? BM_vert_in_face(f, v2->v) : false; + v1_inface = (l1 != NULL); + v2_inface = (l2 != NULL); /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */ v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co); @@ -2591,6 +2698,14 @@ static void knife_make_cuts(KnifeTool_OpData *kcd) /* put list of cutting edges for a face into fhash, keyed by face */ BLI_mempool_iternew(kcd->kedges, &iter); for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { + + /* select edges that lie directly on the cut */ + if (kcd->select_result) { + if (kfe->e && kfe->is_cut) { + BM_edge_select_set(bm, kfe->e, true); + } + } + f = kfe->basef; if (!f || kfe->e) continue; @@ -2627,7 +2742,8 @@ static void knife_make_cuts(KnifeTool_OpData *kcd) for (lst = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); lst; lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e)) { - sort_by_frac_along(lst, e); + BLI_listbase_sort_r(lst, e->v1->co, sort_verts_by_dist_cb); + for (ref = lst->first; ref; ref = ref->next) { kfv = ref->ref; pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co); @@ -2759,10 +2875,11 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd, kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->em, scene, NULL); - kcd->bmbvh = BKE_bmbvh_new_from_editmesh(kcd->em, - BMBVH_RETURN_ORIG | - (only_select ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN), - kcd->cagecos, false); + kcd->bmbvh = BKE_bmbvh_new_from_editmesh( + kcd->em, + BMBVH_RETURN_ORIG | + ((only_select && cut_through) ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN), + kcd->cagecos, false); kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife"); kcd->vthresh = KMAXDIST - 1; @@ -3120,16 +3237,14 @@ void MESH_OT_knife_tool(wmOperatorType *ot) * tessellation here seems way overkill, * but without this its very hard to know of a point is inside the face */ -static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3]) +static void edbm_mesh_knife_face_point(BMFace *f, float r_cent[3]) { const int tottri = f->len - 2; BMLoop **loops = BLI_array_alloca(loops, f->len); unsigned int (*index)[3] = BLI_array_alloca(index, tottri); int j; - - const float *best_co[3] = {NULL}; - float best_area = -1.0f; - bool ok = false; + int j_best = 0; /* use as fallback when unset */ + float area_best = -1.0f; BM_face_calc_tessellation(f, loops, index); @@ -3142,49 +3257,34 @@ static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3]) float cross[3]; cross_v3_v3v3(cross, p2, p3); area = fabsf(dot_v3v3(p1, cross)); - if (area > best_area) { - best_co[0] = p1; - best_co[1] = p2; - best_co[2] = p3; - best_area = area; - ok = true; + if (area > area_best) { + j_best = j; + area_best = area; } } - if (ok) { - mid_v3_v3v3v3(r_cent, best_co[0], best_co[1], best_co[2]); - } - else { - mid_v3_v3v3v3(r_cent, loops[0]->v->co, loops[1]->v->co, loops[2]->v->co); - } + mid_v3_v3v3v3( + r_cent, + loops[index[j_best][0]]->v->co, + loops[index[j_best][1]]->v->co, + loops[index[j_best][2]]->v->co); } -static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4]) +static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2]) { - float cent_ss[2]; - float cent[3]; - - edvm_mesh_knife_face_point(f, cent); - - ED_view3d_project_float_v2_m4(ar, cent, cent_ss, projmat); - - /* check */ - { - LinkNode *p = polys; - int isect = 0; - - while (p) { - const float (*mval_fl)[2] = p->link; - const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); - isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false); - p = p->next; - } + LinkNode *p = polys; + int isect = 0; - if (isect % 2) { - return true; - } + while (p) { + const float (*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false); + p = p->next; } + if (isect % 2) { + return true; + } return false; } @@ -3194,6 +3294,7 @@ static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_through) { KnifeTool_OpData *kcd; + bglMats mats; view3d_operator_needs_opengl(C); @@ -3212,6 +3313,10 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug if (use_tag) { BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false); } + + if (kcd->cut_through == false) { + bgl_get_mats(&mats); + } } /* execute */ @@ -3276,7 +3381,10 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug BMFace *f; BMIter fiter; BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) { + float cent[3], cent_ss[2]; + edbm_mesh_knife_face_point(f, cent); + knife_project_v2(kcd, cent, cent_ss); + if (edbm_mesh_knife_point_isect(polys, cent_ss)) { BM_elem_flag_enable(f, BM_ELEM_TAG); } } @@ -3309,7 +3417,12 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug } while ((l_iter = l_iter->next) != l_first && (found == false)); if (found) { - if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) { + float cent[3], cent_ss[2]; + edbm_mesh_knife_face_point(f, cent); + knife_project_v2(kcd, cent, cent_ss); + if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats, (BMElem *)f)) && + edbm_mesh_knife_point_isect(polys, cent_ss)) + { BM_elem_flag_enable(f, BM_ELEM_TAG); keep_search = true; } diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index e1ef74cbaf8..4eaac6cc1d3 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -32,9 +32,12 @@ #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_windowmanager_types.h" +#ifdef WITH_FREESTYLE +# include "DNA_meshdata_types.h" +#endif + #include "BLI_math.h" #include "BLI_linklist.h" diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 4f149bf2c52..ead243d6de8 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -626,7 +626,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve * split off vertex if... * - we cant find an edge - this means we are ripping a faces vert that is connected to other * geometry only at the vertex. - * - the boundary edge total is greater then 2, + * - the boundary edge total is greater than 2, * in this case edge split _can_ work but we get far nicer results if we use this special case. * - there are only 2 edges but we are a wire vert. */ if ((is_wire == false && totboundary_edge > 2) || diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c index 5daf33fae3b..a501dfc8c2c 100644 --- a/source/blender/editors/mesh/editmesh_rip_edge.c +++ b/source/blender/editors/mesh/editmesh_rip_edge.c @@ -24,8 +24,6 @@ * based on mouse cursor position, split of vertices along the closest edge. */ -#include "MEM_guardedalloc.h" - #include "DNA_object_types.h" #include "BLI_math.h" @@ -34,9 +32,6 @@ #include "BKE_report.h" #include "BKE_editmesh.h" -#include "RNA_define.h" -#include "RNA_access.h" - #include "WM_types.h" #include "ED_mesh.h" @@ -177,7 +172,7 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat); - /* avoid comparing with view-axis aligned edges (less then a pixel) */ + /* avoid comparing with view-axis aligned edges (less than a pixel) */ if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) { float v_dir[2]; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 5f3f7cb242c..d3073d519f6 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -38,7 +38,6 @@ #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_array.h" -#include "BLI_smallhash.h" #include "BKE_context.h" #include "BKE_report.h" @@ -62,8 +61,6 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "GPU_extensions.h" - #include "UI_resources.h" #include "bmesh_tools.h" @@ -386,8 +383,6 @@ static void findnearestvert__doClosest(void *userData, BMVert *eve, const float } - - static bool findnearestvert__backbufIndextest(void *handle, unsigned int index) { BMEditMesh *em = (BMEditMesh *)handle; @@ -711,6 +706,7 @@ static EnumPropertyItem prop_similar_types[] = { {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""}, {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""}, {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""}, + {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""}, #ifdef WITH_FREESTYLE {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""}, #endif @@ -888,7 +884,7 @@ static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUS #ifdef WITH_FREESTYLE const int a_end = SIMFACE_FREESTYLE; #else - const int a_end = SIMFACE_COPLANAR; + const int a_end = SIMFACE_SMOOTH; #endif for (a = SIMFACE_MATERIAL; a <= a_end; a++) { RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); @@ -994,6 +990,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) } MEM_freeN(groups_array); + MEM_freeN(group_index); if (changed) { WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); @@ -3365,8 +3362,8 @@ static int loop_find_region(BMLoop *l, int flag, static int verg_radial(const void *va, const void *vb) { - BMEdge *e_a = *((BMEdge **)va); - BMEdge *e_b = *((BMEdge **)vb); + const BMEdge *e_a = *((const BMEdge **)va); + const BMEdge *e_b = *((const BMEdge **)vb); int a, b; a = BM_edge_face_count(e_a); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index a136bc5e0c5..a480b2051cc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -878,7 +878,7 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) BMesh *bm = em->bm; BMOperator bmop; bool is_pair = (bm->totvertsel == 2); - int len; + int len = 0; bool check_degenerate = true; const int verts_len = bm->totvertsel; BMVert **verts; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index c6571058040..86cd75eed7a 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -232,7 +232,7 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool else { em->emcopyusers--; if (em->emcopyusers < 0) { - printf("warning: em->emcopyusers was less then zero.\n"); + printf("warning: em->emcopyusers was less than zero.\n"); } if (em->emcopyusers <= 0) { diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index e2ce97a3bdf..152d055d239 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -43,7 +43,6 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" -#include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -51,7 +50,6 @@ #include "BKE_report.h" #include "BKE_editmesh.h" -#include "RNA_access.h" #include "RNA_define.h" #include "WM_api.h" @@ -571,24 +569,13 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e return OPERATOR_CANCELLED; } - /* check input variables */ - if (RNA_struct_property_is_set(op->ptr, "filepath")) { - char path[FILE_MAX]; - - RNA_string_get(op->ptr, "filepath", path); - ima = BKE_image_load_exists(path); - } - else { - char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "name", name); - ima = (Image *)BKE_libblock_find_name(ID_IM, name); - } - + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); if (!ima) { - BKE_report(op->reports, RPT_ERROR, "Not an image"); return OPERATOR_CANCELLED; } - + /* handled below */ + id_us_min((ID *)ima); + /* put mesh in editmode */ obedit = base->object; @@ -639,6 +626,7 @@ void MESH_OT_drop_named_image(wmOperatorType *ot) /* properties */ RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign"); RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file"); + RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file"); } static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index f6a54beb8c8..57daec49465 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -47,7 +47,6 @@ #include "RNA_define.h" #include "RNA_access.h" -#include "RNA_enum_types.h" #include "BKE_depsgraph.h" #include "BKE_context.h" diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c index b7822200d98..3af85c33bcc 100644 --- a/source/blender/editors/metaball/mball_ops.c +++ b/source/blender/editors/metaball/mball_ops.c @@ -30,8 +30,6 @@ #include "DNA_scene_types.h" -#include "BLI_utildefines.h" - #include "RNA_access.h" #include "WM_api.h" @@ -62,7 +60,7 @@ void ED_operatormacros_metaball(void) wmOperatorTypeMacro *otmacro; ot = WM_operatortype_append_macro("MBALL_OT_duplicate_move", "Duplicate", - "Make copies of the selected bones within the same armature and move them", + "Make copies of the selected metaelements and move them", OPTYPE_UNDO | OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "MBALL_OT_duplicate_metaelems"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 9b380ff8d48..79437bb05b9 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -56,6 +56,7 @@ set(SRC object_relations.c object_select.c object_shapekey.c + object_data_transfer.c object_transform.c object_warp.c object_vgroup.c diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 24dcf85cec8..c3edd63b2d4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -69,7 +69,6 @@ #include "BKE_effect.h" #include "BKE_font.h" #include "BKE_group.h" -#include "BKE_image.h" #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -97,7 +96,6 @@ #include "ED_armature.h" #include "ED_curve.h" -#include "ED_lattice.h" #include "ED_mball.h" #include "ED_mesh.h" #include "ED_node.h" @@ -108,7 +106,6 @@ #include "ED_transform.h" #include "ED_view3d.h" -#include "UI_interface.h" #include "UI_resources.h" #include "GPU_material.h" @@ -833,24 +830,12 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv Image *ima = NULL; Object *ob = NULL; - /* check image input variables */ - if (RNA_struct_property_is_set(op->ptr, "filepath")) { - char path[FILE_MAX]; - - RNA_string_get(op->ptr, "filepath", path); - ima = BKE_image_load_exists(path); - } - else if (RNA_struct_property_is_set(op->ptr, "name")) { - char name[MAX_ID_NAME - 2]; - - RNA_string_get(op->ptr, "name", name); - ima = (Image *)BKE_libblock_find_name(ID_IM, name); - } - - if (ima == NULL) { - BKE_report(op->reports, RPT_ERROR, "Not an image"); + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); + if (!ima) { return OPERATOR_CANCELLED; } + /* handled below */ + id_us_min((ID *)ima); base = ED_view3d_give_base_under_cursor(C, event->mval); @@ -902,6 +887,8 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot) /* properties */ prop = RNA_def_string(ot->srna, "filepath", NULL, FILE_MAX, "Filepath", "Path to image file"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Image name to assign"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); ED_object_add_generic_props(ot, false); @@ -990,8 +977,11 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) if (0 == RNA_struct_property_is_set(op->ptr, "location")) { wmEvent *event = CTX_wm_window(C)->eventstate; + ARegion *ar = CTX_wm_region(C); + const int mval[2] = {event->x - ar->winrct.xmin, + event->y - ar->winrct.ymin}; ED_object_location_from_view(C, loc); - ED_view3d_cursor3d_position(C, loc, event->mval); + ED_view3d_cursor3d_position(C, loc, mval); RNA_float_set_array(op->ptr, "location", loc); } } @@ -1299,6 +1289,44 @@ static void copy_object_set_idnew(bContext *C, int dupflag) /********************* Make Duplicates Real ************************/ +/** + * \note regarding hashing dupli-objects, skip the first member of #DupliObject.persistent_id + * since its a unique index and we only want to know if the group objects are from the same dupli-group instance. + */ +static unsigned int dupliobject_hash(const void *ptr) +{ + const DupliObject *dob = ptr; + unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); + unsigned int i; + for (i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { + hash ^= (dob->persistent_id[i] ^ i); + } + return hash; +} + +static bool dupliobject_cmp(const void *a_, const void *b_) +{ + const DupliObject *a = a_; + const DupliObject *b = b_; + unsigned int i; + + if (a->ob != b->ob) { + return true; + } + + for (i = 1; (i < MAX_DUPLI_RECUR); i++) { + if (a->persistent_id[i] != b->persistent_id[i]) { + return true; + } + else if (a->persistent_id[i] == INT_MAX) { + break; + } + } + + /* matching */ + return false; +} + static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, const bool use_base_parent, const bool use_hierarchy) @@ -1315,8 +1343,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, lb = object_duplilist(bmain->eval_ctx, scene, base->object); if (use_hierarchy || use_base_parent) { - dupli_gh = BLI_ghash_ptr_new("make_object_duplilist_real dupli_gh"); - parent_gh = BLI_ghash_pair_new("make_object_duplilist_real parent_gh"); + dupli_gh = BLI_ghash_ptr_new(__func__); + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); } for (dob = lb->first; dob; dob = dob->next) { @@ -1356,7 +1384,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (dupli_gh) BLI_ghash_insert(dupli_gh, dob, ob); if (parent_gh) - BLI_ghash_insert(parent_gh, BLI_ghashutil_pairalloc(dob->ob, SET_INT_IN_POINTER(dob->persistent_id[0])), ob); + BLI_ghash_insert(parent_gh, dob, ob); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } @@ -1372,9 +1400,14 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, /* find parent that was also made real */ if (ob_src_par) { - GHashPair *pair = BLI_ghashutil_pairalloc(ob_src_par, SET_INT_IN_POINTER(dob->persistent_id[0])); - ob_dst_par = BLI_ghash_lookup(parent_gh, pair); - BLI_ghashutil_pairfree(pair); + /* OK to keep most of the members uninitialized, + * they won't be read, this is simply for a hash lookup. */ + DupliObject dob_key; + dob_key.ob = ob_src_par; + memcpy(&dob_key.persistent_id[1], + &dob->persistent_id[1], + sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key); } if (ob_dst_par) { @@ -1437,7 +1470,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (dupli_gh) BLI_ghash_free(dupli_gh, NULL, NULL); if (parent_gh) - BLI_ghash_free(parent_gh, BLI_ghashutil_pairfree, NULL); + BLI_ghash_free(parent_gh, NULL, NULL); copy_object_set_idnew(C, 0); @@ -2279,7 +2312,7 @@ static int add_named_exec(bContext *C, wmOperator *op) MEM_freeN(base); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 1f1bdbe55e5..758f4d180b9 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -45,8 +45,6 @@ #include "BLI_blenlib.h" #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "BLI_math.h" -#include "BLI_math_geom.h" #include "BKE_blender.h" #include "BKE_screen.h" @@ -71,7 +69,6 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_colormanagement.h" #include "GPU_draw.h" /* GPU_free_image */ diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 57fabcb06cf..83eeedfef52 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1081,8 +1081,9 @@ static int bake_exec(bContext *C, wmOperator *op) /* setup new render */ RE_test_break_cb(re, NULL, bake_break); - if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) - return OPERATOR_CANCELLED; + if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) { + goto finally; + } if (bkr.is_clear) { const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && (bkr.normal_space == R_BAKE_SPACE_TANGENT)); @@ -1117,6 +1118,8 @@ static int bake_exec(bContext *C, wmOperator *op) RE_SetReports(re, NULL); + +finally: BLI_freelistN(&bkr.selected_objects); return result; } diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c new file mode 100644 index 00000000000..f6cf0312e2d --- /dev/null +++ b/source/blender/editors/object/object_data_transfer.c @@ -0,0 +1,675 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_data_transfer.c + * \ingroup edobj + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_data_transfer.h" +#include "BKE_DerivedMesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" +#include "BKE_object.h" +#include "BKE_report.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "object_intern.h" + +/* All possible data to transfer. + * Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */ +/* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */ +static EnumPropertyItem DT_layer_items[] = { + {0, "", 0, "Vertex Data", ""}, + {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, "Vertex Group(s)", "Transfer active or all vertex groups"}, +#if 0 /* XXX For now, would like to finish/merge work from 2014 gsoc first. */ + {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"}, +#endif +#if 0 /* XXX When SkinModifier is enabled, it seems to erase its own CD_MVERT_SKIN layer from final DM :( */ + {DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"}, +#endif + {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"}, + {0, "", 0, "Edge Data", ""}, + {DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"}, + {DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"}, + {DT_TYPE_CREASE, "CREASE", 0, "Subsurf Crease", "Transfer crease values"}, + {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"}, + {DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"}, + {0, "", 0, "Face Corner Data", ""}, + {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"}, + {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, + {0, "", 0, "Face Data", ""}, + {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"}, + {DT_TYPE_FREESTYLE_FACE, "FREESTYLE_FACE", 0, "Freestyle Mark", "Transfer Freestyle face mark"}, + {0, NULL, 0, NULL, NULL} +}; + +/* Note: DT_layers_select_src_items enum is from rna_modifier.c */ +static EnumPropertyItem *dt_layers_select_src_itemf( + bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL, tmp_item = {0}; + int totitem = 0; + + const int data_type = RNA_enum_get(ptr, "data_type"); + + if (!C) { /* needed for docs and i18n tools */ + return DT_layers_select_src_items; + } + + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ALL_SRC); + + if (data_type == DT_TYPE_MDEFORMVERT) { + Object *ob_src = CTX_data_active_object(C); + + if (BKE_object_pose_armature_get(ob_src)) { + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM); + } + + if (ob_src) { + bDeformGroup *dg; + int i; + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = dg->name; + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (data_type == DT_TYPE_SHAPEKEY) { + /* TODO */ + } + else if (data_type == DT_TYPE_UV) { + Object *ob_src = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + + if (ob_src) { + DerivedMesh *dm_src; + CustomData *pdata; + int num_data, i; + + /* XXX Is this OK? */ + dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY); + pdata = dm_src->getPolyDataLayout(dm_src); + num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (data_type == DT_TYPE_VCOL) { + Object *ob_src = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + + if (ob_src) { + DerivedMesh *dm_src; + CustomData *ldata; + int num_data, i; + + /* XXX Is this OK? */ + dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL); + ldata = dm_src->getLoopDataLayout(dm_src); + num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +/* Note: DT_layers_select_dst_items enum is from rna_modifier.c */ +static EnumPropertyItem *dt_layers_select_dst_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL; + int totitem = 0; + + const int layers_select_src = RNA_enum_get(ptr, "layers_select_src"); + + if (!C) { /* needed for docs and i18n tools */ + return DT_layers_select_dst_items; + } + + if (layers_select_src == DT_LAYERS_ACTIVE_SRC || layers_select_src >= 0) { + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST); + } + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_NAME_DST); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_INDEX_DST); + + /* No 'specific' to-layers here, since we may transfer to several objects at once! */ + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +/* Note: DT_mix_mode_items enum is from rna_modifier.c */ +static EnumPropertyItem *dt_mix_mode_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL; + int totitem = 0; + + const int dtdata_type = RNA_enum_get(ptr, "data_type"); + bool support_advanced_mixing, support_threshold; + + if (!C) { /* needed for docs and i18n tools */ + return DT_mix_mode_items; + } + + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_TRANSFER); + + BKE_object_data_transfer_get_dttypes_capacity(dtdata_type, &support_advanced_mixing, &support_threshold); + + if (support_threshold) { + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD); + } + + if (support_advanced_mixing) { + RNA_enum_item_add_separator(&item, &totitem); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MIX); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_ADD); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_SUB); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MUL); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static bool data_transfer_check(bContext *UNUSED(C), wmOperator *op) +{ + const int layers_select_src = RNA_enum_get(op->ptr, "layers_select_src"); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "layers_select_dst"); + const int layers_select_dst = RNA_property_enum_get(op->ptr, prop); + + /* TODO: check for invalid layers_src select modes too! */ + + if ((layers_select_src != DT_LAYERS_ACTIVE_SRC) && (layers_select_dst == DT_LAYERS_ACTIVE_DST)) { + RNA_property_enum_set(op->ptr, prop, DT_LAYERS_NAME_DST); + return true; + } + + return false; +} + +/* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */ +static void data_transfer_exec_preprocess_objects( + bContext *C, wmOperator *op, Object *ob_src, ListBase *ctx_objects, const bool reverse_transfer) +{ + CollectionPointerLink *ctx_ob; + CTX_data_selected_editable_objects(C, ctx_objects); + + if (reverse_transfer) { + return; /* Nothing else to do in this case... */ + } + + for (ctx_ob = ctx_objects->first; ctx_ob; ctx_ob = ctx_ob->next) { + Object *ob = ctx_ob->ptr.data; + Mesh *me; + if ((ob == ob_src) || (ob->type != OB_MESH)) { + continue; + } + + me = ob->data; + if (me->id.lib) { + /* Do not transfer to linked data, not supported. */ + BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified", + ob->id.name + 2, me->id.name + 2); + me->id.flag &= ~LIB_DOIT; + continue; + } + + me->id.flag |= LIB_DOIT; + } +} + +/* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */ +static bool data_transfer_exec_is_object_valid( + wmOperator *op, Object *ob_src, Object *ob_dst, const bool reverse_transfer) +{ + Mesh *me; + if ((ob_dst == ob_src) || !ELEM(OB_MESH, ob_src->type, ob_dst->type)) { + return false; + } + + if (reverse_transfer) { + return true; + } + + me = ob_dst->data; + if (me->id.flag & LIB_DOIT) { + me->id.flag &= ~LIB_DOIT; + return true; + } + else if (me->id.lib == NULL) { + /* Do not transfer apply operation more than once. */ + /* XXX This is not nice regarding vgroups, which are half-Object data... :/ */ + BKE_reportf(op->reports, RPT_WARNING, + "Skipping object '%s', data '%s' has already been processed with a previous object", + ob_dst->id.name + 2, me->id.name + 2); + } + return false; +} + +static int data_transfer_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob_src = CTX_data_active_object(C); + + ListBase ctx_objects; + CollectionPointerLink *ctx_ob_dst; + + bool changed = false; + + const bool reverse_transfer = RNA_boolean_get(op->ptr, "use_reverse_transfer"); + + const int data_type = RNA_enum_get(op->ptr, "data_type"); + const bool use_create = RNA_boolean_get(op->ptr, "use_create"); + + const int map_vert_mode = RNA_enum_get(op->ptr, "vert_mapping"); + const int map_edge_mode = RNA_enum_get(op->ptr, "edge_mapping"); + const int map_loop_mode = RNA_enum_get(op->ptr, "loop_mapping"); + const int map_poly_mode = RNA_enum_get(op->ptr, "poly_mapping"); + + const bool use_object_transform = RNA_boolean_get(op->ptr, "use_object_transform"); + const bool use_max_distance = RNA_boolean_get(op->ptr, "use_max_distance"); + const float max_distance = use_max_distance ? RNA_float_get(op->ptr, "max_distance") : FLT_MAX; + const float ray_radius = RNA_float_get(op->ptr, "ray_radius"); + const float islands_precision = RNA_float_get(op->ptr, "islands_precision"); + + const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); + const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); + int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; + int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; + const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); + + const int mix_mode = RNA_enum_get(op->ptr, "mix_mode"); + const float mix_factor = RNA_float_get(op->ptr, "mix_factor"); + + SpaceTransform space_transform_data; + SpaceTransform *space_transform = use_object_transform ? &space_transform_data : NULL; + + if (reverse_transfer && ((ID *)(ob_src->data))->lib) { + /* Do not transfer to linked data, not supported. */ + return OPERATOR_CANCELLED; + } + + if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { + layers_select_src[fromto_idx] = layers_src; + layers_select_dst[fromto_idx] = layers_dst; + } + + data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, reverse_transfer); + + for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { + Object *ob_dst = ctx_ob_dst->ptr.data; + + if (reverse_transfer) { + SWAP(Object *, ob_src, ob_dst); + } + + if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, reverse_transfer)) { + if (space_transform) { + BLI_SPACE_TRANSFORM_SETUP(space_transform, ob_dst, ob_src); + } + + if (BKE_object_data_transfer_mesh( + scene, ob_src, ob_dst, data_type, use_create, + map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, + space_transform, max_distance, ray_radius, islands_precision, + layers_select_src, layers_select_dst, + mix_mode, mix_factor, NULL, false, op->reports)) + { + changed = true; + } + } + + if (reverse_transfer) { + SWAP(Object *, ob_src, ob_dst); + } + } + + BLI_freelistN(&ctx_objects); + +#if 0 /* TODO */ + /* Note: issue with that is that if canceled, operator cannot be redone... Nasty in our case. */ + return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +#else + (void)changed; + return OPERATOR_FINISHED; +#endif +} + +/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ +/* Note this context poll is only really partial, it cannot check for all possible invalid cases. */ +static int data_transfer_poll(bContext *C) +{ + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && ob->type == OB_MESH && data); +} + +/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ +static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +{ + PropertyRNA *prop_other; + + const char *prop_id = RNA_property_identifier(prop); + const int data_type = RNA_enum_get(ptr, "data_type"); + bool use_max_distance = false; + bool use_modifier = false; + + if ((prop_other = RNA_struct_find_property(ptr, "use_max_distance"))) { + use_max_distance = RNA_property_boolean_get(ptr, prop_other); + } + if ((prop_other = RNA_struct_find_property(ptr, "modifier"))) { + use_modifier = RNA_property_is_set(ptr, prop_other); + } + + if (STREQ(prop_id, "modifier")) { + return use_modifier; + } + + if (use_modifier) { + /* Hide everything but 'modifier' property, if set. */ + return false; + } + + if (STREQ(prop_id, "max_distance") && !use_max_distance) { + return false; + } + if (STREQ(prop_id, "islands_precision") && !DT_DATATYPE_IS_LOOP(data_type)) { + return false; + } + + if (STREQ(prop_id, "vert_mapping") && !DT_DATATYPE_IS_VERT(data_type)) { + return false; + } + if (STREQ(prop_id, "edge_mapping") && !DT_DATATYPE_IS_EDGE(data_type)) { + return false; + } + if (STREQ(prop_id, "loop_mapping") && !DT_DATATYPE_IS_LOOP(data_type)) { + return false; + } + if (STREQ(prop_id, "poly_mapping") && !DT_DATATYPE_IS_POLY(data_type)) { + return false; + } + + if ((STREQ(prop_id, "layers_select_src") || STREQ(prop_id, "layers_select_dst")) && + !DT_DATATYPE_IS_MULTILAYERS(data_type)) + { + return false; + } + + /* Else, show it! */ + return true; +} + +/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ +static void data_transfer_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, data_transfer_draw_check_prop, '\0'); +} + +/* transfers weight from active to selected */ +void OBJECT_OT_data_transfer(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* Identifiers.*/ + ot->name = "Transfer Mesh Data"; + ot->idname = "OBJECT_OT_data_transfer"; + ot->description = "Transfer data layer(s) (weights, edge sharp, ...) from active to selected meshes"; + + /* API callbacks.*/ + ot->poll = data_transfer_poll; + ot->invoke = WM_menu_invoke; + ot->exec = data_transfer_exec; + ot->check = data_transfer_check; + ot->ui = data_transfer_ui; + + /* Flags.*/ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties.*/ + prop = RNA_def_boolean(ot->srna, "use_reverse_transfer", false, "Reverse Transfer", + "Transfer from selected objects to active one"); + RNA_def_property_flag(prop, PROP_HIDDEN); + + /* Data type to transfer. */ + ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); + RNA_def_boolean(ot->srna, "use_create", true, "Create Data", "Add data layers on destination meshes if needed"); + + /* Mapping methods. */ + RNA_def_enum(ot->srna, "vert_mapping", DT_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping", + "Method used to map source vertices to destination ones"); + RNA_def_enum(ot->srna, "edge_mapping", DT_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping", + "Method used to map source edges to destination ones"); + RNA_def_enum(ot->srna, "loop_mapping", DT_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR, + "Face Corner Mapping", "Method used to map source faces' corners to destination ones"); + RNA_def_enum(ot->srna, "poly_mapping", DT_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping", + "Method used to map source faces to destination ones"); + + /* Mapping options and filtering. */ + RNA_def_boolean(ot->srna, "use_object_transform", true, "Object Transform", + "Evaluate source and destination meshes in their respective object spaces"); + RNA_def_boolean(ot->srna, "use_max_distance", false, "Only Neighbor Geometry", + "Source elements must be closer than given distance from destination one"); + prop = RNA_def_float(ot->srna, "max_distance", 1.0f, 0.0f, FLT_MAX, "Max Distance", + "Maximum allowed distance between source and destination element, for non-topology mappings", + 0.0f, 100.0f); + RNA_def_property_subtype(prop, PROP_DISTANCE); + prop = RNA_def_float(ot->srna, "ray_radius", 0.0f, 0.0f, FLT_MAX, "Ray Radius", + "'Width' of rays (especially useful when raycasting against vertices or edges)", + 0.0f, 10.0f); + RNA_def_property_subtype(prop, PROP_DISTANCE); + prop = RNA_def_float(ot->srna, "islands_precision", 0.1f, 0.0f, 10.0f, "Islands Precision", + "Factor controlling precision of islands handling (the higher, the better the results)", + 0.0f, 1.0f); + RNA_def_property_subtype(prop, PROP_FACTOR); + + /* How to handle multi-layers types of data. */ + prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf); + + prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf); + + prop = RNA_def_enum(ot->srna, "mix_mode", DT_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode", + "How to affect destination elements with source values"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_mix_mode_itemf); + RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 1.0f, "Mix Factor", + "Factor to use when applying data to destination (exact behavior depends on mix mode)", 0.0f, 1.0f); +} + +/******************************************************************************/ +/* Note: This operator is hybrid, it can work as a usual standalone Object operator, + * or as a DataTransfer modifier tool. + */ + +static int datalayout_transfer_poll(bContext *C) +{ + return (edit_modifier_poll_generic(C, &RNA_DataTransferModifier, (1 << OB_MESH)) || data_transfer_poll(C)); +} + +static int datalayout_transfer_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob_act = ED_object_active_context(C); + DataTransferModifierData *dtmd; + + dtmd = (DataTransferModifierData *)edit_modifier_property_get(op, ob_act, eModifierType_DataTransfer); + + /* If we have a modifier, we transfer data layout from this modifier's source object to active one. + * Else, we transfer data layout from active object to all selected ones. */ + if (dtmd) { + Object *ob_src = dtmd->ob_source; + Object *ob_dst = ob_act; + + const bool use_delete = false; /* Never when used from modifier, for now. */ + + if (!ob_src) { + return OPERATOR_CANCELLED; + } + + BKE_object_data_transfer_layout(scene, ob_src, ob_dst, dtmd->data_types, use_delete, + dtmd->layers_select_src, dtmd->layers_select_dst); + } + else { + Object *ob_src = ob_act; + + ListBase ctx_objects; + CollectionPointerLink *ctx_ob_dst; + + const int data_type = RNA_enum_get(op->ptr, "data_type"); + const bool use_delete = RNA_boolean_get(op->ptr, "use_delete"); + + const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); + const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); + int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; + int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; + const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); + + if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { + layers_select_src[fromto_idx] = layers_src; + layers_select_dst[fromto_idx] = layers_dst; + } + + data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, false); + + for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { + Object *ob_dst = ctx_ob_dst->ptr.data; + if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, false)) { + BKE_object_data_transfer_layout(scene, ob_src, ob_dst, data_type, use_delete, + layers_select_src, layers_select_dst); + } + } + + BLI_freelistN(&ctx_objects); + } + + return OPERATOR_FINISHED; +} + +static int datalayout_transfer_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (edit_modifier_invoke_properties(C, op)) { + return datalayout_transfer_exec(C, op); + } + else { + return WM_menu_invoke(C, op, event); + } +} + +void OBJECT_OT_datalayout_transfer(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Transfer Mesh Data Layout"; + ot->description = "Transfer layout of data layer(s) from active to selected meshes"; + ot->idname = "OBJECT_OT_datalayout_transfer"; + + ot->poll = datalayout_transfer_poll; + ot->invoke = datalayout_transfer_invoke; + ot->exec = datalayout_transfer_exec; + ot->check = data_transfer_check; + ot->ui = data_transfer_ui; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties.*/ + edit_modifier_properties(ot); + + /* Data type to transfer. */ + ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); + RNA_def_boolean(ot->srna, "use_delete", false, "Exact Match", + "Also delete some data layers from destination if necessary, so that it matches exactly source"); + + /* How to handle multi-layers types of data. */ + prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf); + + prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf); +} diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 6fa3caa6172..64fddf1b6a1 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -37,6 +37,11 @@ struct Lattice; struct Curve; struct Object; struct Mesh; +struct bContext; +struct StructRNA; +struct wmOperator; + +struct ModifierData; struct HookModifierData; /* add hook menu */ @@ -155,6 +160,12 @@ void GROUP_OT_objects_add_active(struct wmOperatorType *ot); void GROUP_OT_objects_remove_active(struct wmOperatorType *ot); /* object_modifier.c */ +int edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag); +int edit_modifier_poll(struct bContext *C); +void edit_modifier_properties(struct wmOperatorType *ot); +int edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op); +struct ModifierData *edit_modifier_property_get(struct wmOperator *op, struct Object *ob, int type); + void OBJECT_OT_modifier_add(struct wmOperatorType *ot); void OBJECT_OT_modifier_remove(struct wmOperatorType *ot); void OBJECT_OT_modifier_move_up(struct wmOperatorType *ot); @@ -214,7 +225,6 @@ void OBJECT_OT_vertex_group_remove_from(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_select(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_deselect(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_copy_to_linked(struct wmOperatorType *ot); -void OBJECT_OT_vertex_group_transfer_weight(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_copy_to_selected(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_copy(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_normalize(struct wmOperatorType *ot); @@ -266,5 +276,9 @@ void OBJECT_OT_lod_remove(struct wmOperatorType *ot); /* object_random.c */ void OBJECT_OT_vertex_random(struct wmOperatorType *ot); +/* object_transfer_data.c */ +void OBJECT_OT_data_transfer(struct wmOperatorType *ot); +void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot); + #endif /* __OBJECT_INTERN_H__ */ diff --git a/source/blender/editors/object/object_lod.c b/source/blender/editors/object/object_lod.c index 48e980015a7..ced306178b8 100644 --- a/source/blender/editors/object/object_lod.c +++ b/source/blender/editors/object/object_lod.c @@ -32,18 +32,22 @@ #include "DNA_object_types.h" #include "BKE_context.h" -#include "BKE_object.h" #include "WM_api.h" #include "WM_types.h" #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "ED_screen.h" #include "ED_object.h" +#ifdef WITH_GAMEENGINE +# include "BKE_object.h" + +# include "RNA_enum_types.h" +#endif + #include "object_intern.h" static int object_lod_add_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index cec5c683221..5a479af83b5 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -68,6 +68,7 @@ #include "BKE_multires.h" #include "BKE_report.h" #include "BKE_object.h" +#include "BKE_object_deform.h" #include "BKE_ocean.h" #include "BKE_paint.h" #include "BKE_particle.h" @@ -807,7 +808,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot) /************************ generic functions for operators using mod names and data context *********************/ -static int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) +int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) { PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); @@ -819,17 +820,17 @@ static int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obty return 1; } -static int edit_modifier_poll(bContext *C) +int edit_modifier_poll(bContext *C) { return edit_modifier_poll_generic(C, &RNA_Modifier, 0); } -static void edit_modifier_properties(wmOperatorType *ot) +void edit_modifier_properties(wmOperatorType *ot) { RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit"); } -static int edit_modifier_invoke_properties(bContext *C, wmOperator *op) +int edit_modifier_invoke_properties(bContext *C, wmOperator *op) { ModifierData *md; @@ -848,7 +849,7 @@ static int edit_modifier_invoke_properties(bContext *C, wmOperator *op) return false; } -static ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) +ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) { char modifier_name[MAX_NAME]; ModifierData *md; @@ -1353,7 +1354,7 @@ void OBJECT_OT_multires_external_save(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - WM_operator_properties_filesel(ot, FOLDERFILE | BTXFILE, FILE_SPECIAL, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); edit_modifier_properties(ot); } @@ -1667,7 +1668,7 @@ static void skin_armature_bone_create(Object *skin_ob, BLI_snprintf(bone->name, sizeof(bone->name), "Bone.%.2d", endx); /* add bDeformGroup */ - if ((dg = ED_vgroup_add_name(skin_ob, bone->name))) { + if ((dg = BKE_object_defgroup_add_name(skin_ob, bone->name))) { ED_vgroup_vert_add(skin_ob, dg, parent_v, 1, WEIGHT_REPLACE); ED_vgroup_vert_add(skin_ob, dg, v, 1, WEIGHT_REPLACE); } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index bef64fec8d0..15eb9090ce5 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -40,7 +40,6 @@ #include "BKE_context.h" #include "RNA_access.h" -#include "RNA_define.h" #include "WM_api.h" #include "WM_types.h" @@ -178,7 +177,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_vertex_group_select); WM_operatortype_append(OBJECT_OT_vertex_group_deselect); WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_linked); - WM_operatortype_append(OBJECT_OT_vertex_group_transfer_weight); WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_selected); WM_operatortype_append(OBJECT_OT_vertex_group_copy); WM_operatortype_append(OBJECT_OT_vertex_group_normalize); @@ -250,6 +248,9 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_lod_remove); WM_operatortype_append(OBJECT_OT_vertex_random); + + WM_operatortype_append(OBJECT_OT_data_transfer); + WM_operatortype_append(OBJECT_OT_datalayout_transfer); } void ED_operatormacros_object(void) @@ -421,6 +422,10 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OBJECT_OT_data_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + /* XXX No more available 'T' shortcuts... :/ */ + /* WM_keymap_verify_item(keymap, "OBJECT_OT_datalayout_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); */ + for (i = 0; i <= 5; i++) { kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0); RNA_int_set(kmi->ptr, "level", i); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 48e617eda11..67b5c8061cd 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -803,6 +803,7 @@ static void parent_set_vert_find(KDTree *tree, Object *child, int vert_par[3], b tot = BLI_kdtree_find_nearest_n(tree, co_find, nearest, 3); BLI_assert(tot == 3); + UNUSED_VARS(tot); vert_par[0] = nearest[0].index; vert_par[1] = nearest[1].index; diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index 6bb23a4a7f0..3fe8c86ef5c 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -75,10 +75,10 @@ /*********************** add shape key ***********************/ -static void ED_object_shape_key_add(bContext *C, Scene *scene, Object *ob, const bool from_mix) +static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix) { KeyBlock *kb; - if ((kb = BKE_object_insert_shape_key(scene, ob, NULL, from_mix))) { + if ((kb = BKE_object_insert_shape_key(ob, NULL, from_mix))) { Key *key = BKE_key_from_object(ob); /* for absolute shape keys, new keys may not be added last */ ob->shapenr = BLI_findindex(&key->block, kb) + 1; @@ -320,11 +320,10 @@ static int shape_key_poll(bContext *C) static int shape_key_add_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob = ED_object_context(C); const bool from_mix = RNA_boolean_get(op->ptr, "from_mix"); - ED_object_shape_key_add(C, scene, ob, from_mix); + ED_object_shape_key_add(C, ob, from_mix); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index f19765a5344..92fe5ded4dd 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -33,9 +33,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" -#include "DNA_key_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -69,7 +67,6 @@ #include "ED_armature.h" #include "ED_keyframing.h" -#include "ED_mball.h" #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 49c77770467..e70281c502b 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -36,16 +36,13 @@ #include "MEM_guardedalloc.h" -#include "DNA_cloth_types.h" #include "DNA_curve_types.h" #include "DNA_lattice_types.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" #include "DNA_scene_types.h" -#include "DNA_particle_types.h" #include "BLI_alloca.h" #include "BLI_array.h" @@ -54,7 +51,6 @@ #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" -#include "BLF_translation.h" #include "BKE_context.h" #include "BKE_customdata.h" @@ -85,11 +81,6 @@ #include "object_intern.h" /************************ Exported Functions **********************/ -static void vgroup_remap_update_users(Object *ob, int *map); -static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup); -static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg); -static void vgroup_delete_all(Object *ob); - static bool vertex_group_use_vert_sel(Object *ob) { if (ob->mode == OB_MODE_EDIT) { @@ -126,81 +117,6 @@ bool ED_vgroup_sync_from_pose(Object *ob) return false; } -bool ED_vgroup_object_is_edit_mode(Object *ob) -{ - if (ob->type == OB_MESH) - return (BKE_editmesh_from_object(ob) != NULL); - else if (ob->type == OB_LATTICE) - return (((Lattice *)ob->data)->editlatt != NULL); - - return false; -} - -bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name) -{ - bDeformGroup *defgroup; - - if (!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type)) - return NULL; - - defgroup = BKE_defgroup_new(ob, name); - - ob->actdef = BLI_listbase_count(&ob->defbase); - - return defgroup; -} - -bDeformGroup *ED_vgroup_add(Object *ob) -{ - return ED_vgroup_add_name(ob, DATA_("Group")); -} - -void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup) -{ - BLI_assert(BLI_findindex(&ob->defbase, defgroup) != -1); - - if (ED_vgroup_object_is_edit_mode(ob)) - vgroup_delete_edit_mode(ob, defgroup); - else - vgroup_delete_object_mode(ob, defgroup); -} - -void ED_vgroup_clear(Object *ob) -{ - bDeformGroup *dg = (bDeformGroup *)ob->defbase.first; - int edit_mode = ED_vgroup_object_is_edit_mode(ob); - - while (dg) { - bDeformGroup *next_dg = dg->next; - - if (edit_mode) - vgroup_delete_edit_mode(ob, dg); - else - vgroup_delete_object_mode(ob, dg); - - dg = next_dg; - } -} - -bool ED_vgroup_data_create(ID *id) -{ - /* create deform verts */ - - if (GS(id->name) == ID_ME) { - Mesh *me = (Mesh *)id; - me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert); - return true; - } - else if (GS(id->name) == ID_LT) { - Lattice *lt = (Lattice *)id; - lt->dvert = MEM_callocN(sizeof(MDeformVert) * lt->pntsu * lt->pntsv * lt->pntsw, "lattice deformVert"); - return true; - } - else { - return false; - } -} - /** * Removes out of range MDeformWeights */ @@ -327,31 +243,6 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co return false; } -static bool ed_vgroup_dm_parray_alloc(DerivedMesh *dm, MDeformVert ***dvert_arr, int *dvert_tot) -{ - *dvert_tot = 0; - *dvert_arr = NULL; - - if (dm) { - MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); - - if (dvert) { - int i, totvert = dm->getNumVerts(dm); - - *dvert_tot = totvert; - *dvert_arr = MEM_mallocN(sizeof(void *) * totvert, "vgroup parray from me"); - - for (i = 0; i < totvert; i++) { - (*dvert_arr)[i] = dvert + i; - } - - return true; - } - } - - return false; -} - /** * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true. * This finds the unselected mirror deform verts and copys the weights to them from the selected. @@ -465,34 +356,6 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot } } -/* returns true if the id type supports weights */ -bool ED_vgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot) -{ - if (id) { - switch (GS(id->name)) { - case ID_ME: - { - Mesh *me = (Mesh *)id; - *dvert_arr = me->dvert; - *dvert_tot = me->totvert; - return true; - } - case ID_LT: - { - Lattice *lt = (Lattice *)id; - lt = (lt->editlatt) ? lt->editlatt->latt : lt; - *dvert_arr = lt->dvert; - *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw; - return true; - } - } - } - - *dvert_arr = NULL; - *dvert_tot = 0; - return false; -} - /* matching index only */ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) { @@ -511,7 +374,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false); ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - if ((dvert_array == NULL) && (dvert_array_from != NULL) && ED_vgroup_data_create(ob->data)) { + if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) { ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); new_vgroup = true; } @@ -523,7 +386,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) if (new_vgroup == true) { /* free the newly added vgroup since it wasn't compatible */ - vgroup_delete_all(ob); + BKE_object_defgroup_remove_all(ob); } /* if true: both are 0 and nothing needs changing, consider this a success */ @@ -541,7 +404,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) for (i = 0; i <= defbase_tot_from; i++) remap[i] = i; for (; i <= defbase_tot; i++) remap[i] = 0; /* can't use these, so disable */ - vgroup_remap_update_users(ob, remap); + BKE_object_defgroup_remap_update_users(ob, remap); MEM_freeN(remap); } @@ -682,7 +545,7 @@ static void vgroup_normalize_active(Object *ob, eVGroupSelect subset_type) return; } - vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot); MEM_freeN((void *)vgroup_validmap); @@ -703,7 +566,7 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type) BMEditMesh *em = me->edit_btmesh; MDeformVert *dvert_act; int i, vgroup_tot, subset_count; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); if (em) { @@ -747,51 +610,6 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type) /***********************Start weight transfer (WT)*********************************/ -typedef enum WT_VertexGroupMode { - WT_REPLACE_ACTIVE_VERTEX_GROUP = 1, - WT_REPLACE_ALL_VERTEX_GROUPS = 2 -} WT_VertexGroupMode; - -typedef enum WT_Method { - WT_BY_INDEX = 1, - WT_BY_NEAREST_VERTEX = 2, - WT_BY_NEAREST_FACE = 3, - WT_BY_NEAREST_VERTEX_IN_FACE = 4 -} WT_Method; - -typedef enum WT_ReplaceMode { - WT_REPLACE_ALL_WEIGHTS = 1, - WT_REPLACE_EMPTY_WEIGHTS = 2 -} WT_ReplaceMode; - -static EnumPropertyItem WT_vertex_group_mode_item[] = { - {WT_REPLACE_ACTIVE_VERTEX_GROUP, - "WT_REPLACE_ACTIVE_VERTEX_GROUP", 0, "Active", "Transfer active vertex group from selected to active mesh"}, - {WT_REPLACE_ALL_VERTEX_GROUPS, - "WT_REPLACE_ALL_VERTEX_GROUPS", 0, "All", "Transfer all vertex groups from selected to active mesh"}, - {0, NULL, 0, NULL, NULL} -}; - -static EnumPropertyItem WT_method_item[] = { - {WT_BY_INDEX, - "WT_BY_INDEX", 0, "Vertex index", "Copy for identical meshes"}, - {WT_BY_NEAREST_VERTEX, - "WT_BY_NEAREST_VERTEX", 0, "Nearest vertex", "Copy weight from closest vertex"}, - {WT_BY_NEAREST_FACE, - "WT_BY_NEAREST_FACE", 0, "Nearest face", "Barycentric interpolation from nearest face"}, - {WT_BY_NEAREST_VERTEX_IN_FACE, - "WT_BY_NEAREST_VERTEX_IN_FACE", 0, "Nearest vertex in face", "Copy weight from closest vertex in nearest face"}, - {0, NULL, 0, NULL, NULL} -}; - -static EnumPropertyItem WT_replace_mode_item[] = { - {WT_REPLACE_ALL_WEIGHTS, - "WT_REPLACE_ALL_WEIGHTS", 0, "All", "Overwrite all weights"}, - {WT_REPLACE_EMPTY_WEIGHTS, - "WT_REPLACE_EMPTY_WEIGHTS", 0, "Empty", "Add weights to vertices with no weight"}, - {0, NULL, 0, NULL, NULL} -}; - static EnumPropertyItem WT_vertex_group_select_item[] = { {WT_VGROUP_ACTIVE, "ACTIVE", 0, "Active Group", "The active Vertex Group"}, @@ -867,298 +685,6 @@ static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_act ot->prop = prop; } -/* Copy weight.*/ -static void vgroup_transfer_weight(float *r_weight_dst, const float weight_src, const WT_ReplaceMode replace_mode) -{ - switch (replace_mode) { - case WT_REPLACE_ALL_WEIGHTS: - *r_weight_dst = weight_src; - break; - - case WT_REPLACE_EMPTY_WEIGHTS: - if (*r_weight_dst == 0.0f) { - *r_weight_dst = weight_src; - } - break; - - default: - BLI_assert(0); - break; - } -} - -/* Could be exposed externally by implementing it in header with the rest. - * Simple refactoring will break something. - * For now, naming is ed_ instead of ED_*/ -static bool ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGroup *dg_src, Scene *scene, - WT_Method method, WT_ReplaceMode replace_mode, wmOperator *op) -{ - bDeformGroup *dg_dst; - Mesh *me_dst; - DerivedMesh *dmesh_src; - BVHTreeFromMesh tree_mesh_vertices_src, tree_mesh_faces_src = {NULL}; - MDeformVert **dv_array_src, **dv_array_dst, **dv_src, **dv_dst; - MVert *mv_dst, *mv_src; - MFace *mface_src, *mf; - BVHTreeNearest nearest; - MDeformWeight *dw_dst, *dw_src; - int dv_tot_src, dv_tot_dst, i, v_index, index_dst, index_src, index_nearest, index_nearest_vertex; - unsigned int f_index; - float weight, tmp_weight[4], tmp_co[3], normal[3], tmp_mat[4][4], dist_v1, dist_v2, dist_v3, dist_v4; - const int use_vert_sel = vertex_group_use_vert_sel(ob_dst); - bool is_dg_dst_new = false; - - /* Ensure vertex group on target.*/ - if ((dg_dst = defgroup_find_name(ob_dst, dg_src->name)) == NULL) { - dg_dst = BKE_defgroup_new(ob_dst, dg_src->name); - is_dg_dst_new = true; - } - - /* Get meshes.*/ - dmesh_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MASK_MDEFORMVERT); - me_dst = ob_dst->data; - - /* Get vertex group array from source mesh */ - if (!ed_vgroup_dm_parray_alloc(dmesh_src, &dv_array_src, &dv_tot_src)) { - BKE_report(op->reports, RPT_ERROR, "Transfer failed (source mesh does not have any vertex groups)"); - return false; - } - - /* Create data in memory when nothing there.*/ - if (!me_dst->dvert) ED_vgroup_data_create(&me_dst->id); - - /* Get vertex group for destination mesh */ - ED_vgroup_parray_alloc(&me_dst->id, &dv_array_dst, &dv_tot_dst, use_vert_sel); - - /* Get indexes of vertex groups.*/ - index_src = BLI_findindex(&ob_src->defbase, dg_src); - index_dst = BLI_findindex(&ob_dst->defbase, dg_dst); - - /* Get vertices.*/ - mv_dst = me_dst->mvert; - mv_src = dmesh_src->getVertArray(dmesh_src); - - /* Prepare transformation matrix.*/ - invert_m4_m4(ob_src->imat, ob_src->obmat); - mul_m4_m4m4(tmp_mat, ob_src->imat, ob_dst->obmat); - - /* Clear weights.*/ - if (replace_mode == WT_REPLACE_ALL_WEIGHTS) { - for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++) { - - if (*dv_dst == NULL) continue; - - dw_dst = defvert_find_index(*dv_dst, index_dst); - /* Remove vertex from group.*/ - if (dw_dst) defvert_remove_group(*dv_dst, dw_dst); - } - } - - switch (method) { - - case WT_BY_INDEX: - /* Check if indices are matching, delete and return if not.*/ - if (ob_dst == ob_src || dv_tot_dst == 0 || dv_tot_dst != dv_tot_src || - dv_array_src == NULL || dv_array_dst == NULL) - { - if (is_dg_dst_new) { - ED_vgroup_delete(ob_dst, dg_dst); - } - - if (dv_array_src) MEM_freeN(dv_array_src); - if (dv_array_dst) MEM_freeN(dv_array_dst); - dmesh_src->release(dmesh_src); - BKE_report(op->reports, RPT_ERROR, "Transfer failed (indices are not matching)"); - return false; - } - - /* Loop through the vertices.*/ - for (i = 0, dv_src = dv_array_src, dv_dst = dv_array_dst; - i < me_dst->totvert; - i++, dv_dst++, dv_src++, mv_src++, mv_dst++) - { - - if (*dv_dst == NULL) { - continue; - } - - /* Copy weight.*/ - dw_src = defvert_find_index(*dv_src, index_src); - if (dw_src && dw_src->weight) { - dw_dst = defvert_verify_index(*dv_dst, index_dst); - vgroup_transfer_weight(&dw_dst->weight, dw_src->weight, replace_mode); - } - } - break; - - case WT_BY_NEAREST_VERTEX: - /* Make node tree.*/ - bvhtree_from_mesh_verts(&tree_mesh_vertices_src, dmesh_src, FLT_EPSILON, 2, 6); - - /* Loop trough vertices.*/ - for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++, mv_dst++) { - - if (*dv_dst == NULL) { - continue; - } - - /* Reset nearest.*/ - nearest.dist_sq = FLT_MAX; - /* It is faster to start searching at the top of the tree instead of previous search result.*/ - nearest.index = -1; - - /* Transform into target space.*/ - mul_v3_m4v3(tmp_co, tmp_mat, mv_dst->co); - - /* Node tree accelerated search for closest vetex.*/ - BLI_bvhtree_find_nearest(tree_mesh_vertices_src.tree, tmp_co, - &nearest, tree_mesh_vertices_src.nearest_callback, &tree_mesh_vertices_src); - - /* Copy weight that are not NULL including weight value 0. In relevant cases, existing weights are - * overwritten prior to this. See the "Clear weights." step above.*/ - dw_src = defvert_find_index(dv_array_src[nearest.index], index_src); - if (dw_src && dw_src->weight) { - dw_dst = defvert_verify_index(*dv_dst, index_dst); - vgroup_transfer_weight(&dw_dst->weight, dw_src->weight, replace_mode); - } - } - - /* Free memory.*/ - free_bvhtree_from_mesh(&tree_mesh_vertices_src); - break; - - case WT_BY_NEAREST_FACE: - /* Get faces.*/ - DM_ensure_tessface(dmesh_src); - mface_src = dmesh_src->getTessFaceArray(dmesh_src); - - /* Make node tree.*/ - bvhtree_from_mesh_faces(&tree_mesh_faces_src, dmesh_src, FLT_EPSILON, 2, 6); - - /* Loop through the vertices.*/ - for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++, mv_dst++) { - - if (*dv_dst == NULL) { - continue; - } - - /* Reset nearest.*/ - nearest.dist_sq = FLT_MAX; - /* It is faster to start searching at the top of the tree instead of previous search result.*/ - nearest.index = -1; - - /* Transform into target space.*/ - mul_v3_m4v3(tmp_co, tmp_mat, mv_dst->co); - - /* Node tree accelerated search for closest face.*/ - BLI_bvhtree_find_nearest(tree_mesh_faces_src.tree, tmp_co, - &nearest, tree_mesh_faces_src.nearest_callback, &tree_mesh_faces_src); - index_nearest = nearest.index; - - /* Project onto face.*/ - mf = &mface_src[index_nearest]; - normal_tri_v3(normal, mv_src[mf->v1].co, mv_src[mf->v2].co, mv_src[mf->v3].co); - project_v3_plane(tmp_co, normal, mv_src[mf->v1].co); - - /* Interpolate weights over face.*/ - interp_weights_face_v3(tmp_weight, - mv_src[mf->v1].co, - mv_src[mf->v2].co, - mv_src[mf->v3].co, - mf->v4 ? mv_src[mf->v4].co : NULL, - tmp_co); - - /* Get weights from face.*/ - f_index = mf->v4 ? 3 : 2; - weight = 0.0f; - do { - v_index = (&mf->v1)[f_index]; - weight += tmp_weight[f_index] * defvert_find_weight(dv_array_src[v_index], index_src); - } while (f_index--); - - /* Copy weight that are not NULL including weight value 0. In relevant cases, existing weights are - * overwritten prior to this. See the "Clear weights." step above.*/ - if (weight > 0.0f) { - dw_dst = defvert_verify_index(*dv_dst, index_dst); - vgroup_transfer_weight(&dw_dst->weight, weight, replace_mode); - } - } - - /* Free memory.*/ - free_bvhtree_from_mesh(&tree_mesh_faces_src); - break; - - case WT_BY_NEAREST_VERTEX_IN_FACE: - /* Get faces.*/ - DM_ensure_tessface(dmesh_src); - mface_src = dmesh_src->getTessFaceArray(dmesh_src); - - /* Make node tree.*/ - bvhtree_from_mesh_faces(&tree_mesh_faces_src, dmesh_src, FLT_EPSILON, 2, 6); - - /* Loop through the vertices.*/ - for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++, mv_dst++) { - - if (*dv_dst == NULL) { - continue; - } - - /* Reset nearest.*/ - nearest.dist_sq = FLT_MAX; - /* It is faster to start searching at the top of the tree instead of previous search result.*/ - nearest.index = -1; - - /* Transform into target space.*/ - mul_v3_m4v3(tmp_co, tmp_mat, mv_dst->co); - - /* Node tree accelerated search for closest face.*/ - BLI_bvhtree_find_nearest(tree_mesh_faces_src.tree, tmp_co, - &nearest, tree_mesh_faces_src.nearest_callback, &tree_mesh_faces_src); - index_nearest = nearest.index; - - /* Get distances.*/ - mf = &mface_src[index_nearest]; - dist_v1 = len_squared_v3v3(tmp_co, mv_src[mf->v1].co); - dist_v2 = len_squared_v3v3(tmp_co, mv_src[mf->v2].co); - dist_v3 = len_squared_v3v3(tmp_co, mv_src[mf->v3].co); - - /* Get closest vertex.*/ - f_index = mf->v4 ? 3 : 2; - if (dist_v1 < dist_v2 && dist_v1 < dist_v3) index_nearest_vertex = mf->v1; - else if (dist_v2 < dist_v3) index_nearest_vertex = mf->v2; - else index_nearest_vertex = mf->v3; - if (f_index == 3) { - dist_v4 = len_squared_v3v3(tmp_co, mv_src[mf->v4].co); - if (dist_v4 < dist_v1 && dist_v4 < dist_v2 && dist_v4 < dist_v3) { - index_nearest_vertex = mf->v4; - } - } - - /* Copy weight that are not NULL including weight value 0. In relevant cases, existing weights are - * overwritten prior to this. See the "Clear weights." step above.*/ - dw_src = defvert_find_index(dv_array_src[index_nearest_vertex], index_src); - if (dw_src && dw_src->weight) { - dw_dst = defvert_verify_index(*dv_dst, index_dst); - vgroup_transfer_weight(&dw_dst->weight, dw_src->weight, replace_mode); - } - } - - /* Free memory.*/ - free_bvhtree_from_mesh(&tree_mesh_faces_src); - break; - - default: - BLI_assert(0); - break; - } - - /* Free memory.*/ - if (dv_array_src) MEM_freeN(dv_array_src); - if (dv_array_dst) MEM_freeN(dv_array_dst); - dmesh_src->release(dmesh_src); - - return true; -} /***********************End weight transfer (WT)***********************************/ @@ -1175,7 +701,7 @@ static void ED_vgroup_nr_vert_add(Object *ob, int tot; /* get the vert */ - ED_vgroup_array_get(ob->data, &dvert, &tot); + BKE_object_defgroup_array_get(ob->data, &dvert, &tot); if (dvert == NULL) return; @@ -1208,7 +734,7 @@ static void ED_vgroup_nr_vert_add(Object *ob, break; case WEIGHT_SUBTRACT: dw->weight -= weight; - /* if the weight is zero or less then + /* if the weight is zero or less than * remove the vert from the deform group */ if (dw->weight <= 0.0f) { @@ -1261,8 +787,8 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, /* if there's no deform verts then create some, */ - if (ED_vgroup_array_get(ob->data, &dv, &tot) && dv == NULL) - ED_vgroup_data_create(ob->data); + if (BKE_object_defgroup_array_get(ob->data, &dv, &tot) && dv == NULL) + BKE_object_defgroup_data_create(ob->data); /* call another function to do the work */ @@ -1287,7 +813,7 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) /* get the deform vertices corresponding to the * vertnum */ - ED_vgroup_array_get(ob->data, &dvert, &tot); + BKE_object_defgroup_array_get(ob->data, &dvert, &tot); if (dvert) { MDeformVert *dv = &dvert[vertnum]; @@ -1498,86 +1024,6 @@ static void vgroup_duplicate(Object *ob) } } -/** - * Return the subset type of the Vertex Group Selection - */ -bool *ED_vgroup_subset_from_select_type(Object *ob, eVGroupSelect subset_type, int *r_vgroup_tot, int *r_subset_count) -{ - bool *vgroup_validmap = NULL; - *r_vgroup_tot = BLI_listbase_count(&ob->defbase); - - switch (subset_type) { - case WT_VGROUP_ACTIVE: - { - const int def_nr_active = ob->actdef - 1; - vgroup_validmap = MEM_mallocN(*r_vgroup_tot * sizeof(*vgroup_validmap), __func__); - memset(vgroup_validmap, false, *r_vgroup_tot * sizeof(*vgroup_validmap)); - if ((def_nr_active >= 0) && (def_nr_active < *r_vgroup_tot)) { - *r_subset_count = 1; - vgroup_validmap[def_nr_active] = true; - } - else { - *r_subset_count = 0; - } - break; - } - case WT_VGROUP_BONE_SELECT: - { - vgroup_validmap = BKE_objdef_selected_get(ob, *r_vgroup_tot, r_subset_count); - break; - } - case WT_VGROUP_BONE_DEFORM: - { - int i; - vgroup_validmap = BKE_objdef_validmap_get(ob, *r_vgroup_tot); - *r_subset_count = 0; - for (i = 0; i < *r_vgroup_tot; i++) { - if (vgroup_validmap[i] == true) { - *r_subset_count += 1; - } - } - break; - } - case WT_VGROUP_BONE_DEFORM_OFF: - { - int i; - vgroup_validmap = BKE_objdef_validmap_get(ob, *r_vgroup_tot); - *r_subset_count = 0; - for (i = 0; i < *r_vgroup_tot; i++) { - vgroup_validmap[i] = !vgroup_validmap[i]; - if (vgroup_validmap[i] == true) { - *r_subset_count += 1; - } - } - break; - } - case WT_VGROUP_ALL: - default: - { - vgroup_validmap = MEM_mallocN(*r_vgroup_tot * sizeof(*vgroup_validmap), __func__); - memset(vgroup_validmap, true, *r_vgroup_tot * sizeof(*vgroup_validmap)); - *r_subset_count = *r_vgroup_tot; - break; - } - } - - return vgroup_validmap; -} - -/** - * store indices from the vgroup_validmap (faster lookups in some cases) - */ -void ED_vgroup_subset_to_index_array(const bool *vgroup_validmap, const int vgroup_tot, - int *r_vgroup_subset_map) -{ - int i, j = 0; - for (i = 0; i < vgroup_tot; i++) { - if (vgroup_validmap[i]) { - r_vgroup_subset_map[j++] = i; - } - } -} - static void vgroup_normalize(Object *ob) { MDeformWeight *dw; @@ -2052,7 +1498,7 @@ static void vgroup_normalize_all(Object *ob, if (dvert_array) { const int defbase_tot = BLI_listbase_count(&ob->defbase); - bool *lock_flags = BKE_objdef_lock_flags_get(ob, defbase_tot); + bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot); if ((lock_active == true) && (lock_flags != NULL) && @@ -2205,7 +1651,7 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i BLI_SMALLSTACK_DECLARE(dv_stack, MDeformVert *); - ED_vgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map); + BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map); ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); memset(vgroup_subset_weights, 0, sizeof(*vgroup_subset_weights) * subset_count); @@ -2725,298 +2171,13 @@ cleanup: } -static void vgroup_remap_update_users(Object *ob, int *map) -{ - ExplodeModifierData *emd; - ModifierData *md; - ParticleSystem *psys; - ClothModifierData *clmd; - ClothSimSettings *clsim; - int a; - - /* these cases don't use names to refer to vertex groups, so when - * they get deleted the numbers get out of sync, this corrects that */ - - if (ob->soft) - ob->soft->vertgroup = map[ob->soft->vertgroup]; - - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Explode) { - emd = (ExplodeModifierData *)md; - emd->vgroup = map[emd->vgroup]; - } - else if (md->type == eModifierType_Cloth) { - clmd = (ClothModifierData *)md; - clsim = clmd->sim_parms; - - if (clsim) { - clsim->vgroup_mass = map[clsim->vgroup_mass]; - clsim->vgroup_bend = map[clsim->vgroup_bend]; - clsim->vgroup_struct = map[clsim->vgroup_struct]; - } - } - } - - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - for (a = 0; a < PSYS_TOT_VG; a++) - psys->vgroup[a] = map[psys->vgroup[a]]; - } -} - - -static void vgroup_delete_update_users(Object *ob, int id) -{ - int i, defbase_tot = BLI_listbase_count(&ob->defbase) + 1; - int *map = MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del"); - - map[id] = map[0] = 0; - for (i = 1; i < id; i++) map[i] = i; - for (i = id + 1; i < defbase_tot; i++) map[i] = i - 1; - - vgroup_remap_update_users(ob, map); - MEM_freeN(map); -} - - -static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg) -{ - MDeformVert *dvert_array = NULL; - int dvert_tot = 0; - const int def_nr = BLI_findindex(&ob->defbase, dg); - - BLI_assert(def_nr != -1); - - ED_vgroup_array_get(ob->data, &dvert_array, &dvert_tot); - - if (dvert_array) { - int i, j; - MDeformVert *dv; - for (i = 0, dv = dvert_array; i < dvert_tot; i++, dv++) { - MDeformWeight *dw; - - dw = defvert_find_index(dv, def_nr); - defvert_remove_group(dv, dw); /* dw can be NULL */ - - /* inline, make into a function if anything else needs to do this */ - for (j = 0; j < dv->totweight; j++) { - if (dv->dw[j].def_nr > def_nr) { - dv->dw[j].def_nr--; - } - } - /* done */ - } - } - - vgroup_delete_update_users(ob, def_nr + 1); - - /* Remove the group */ - BLI_freelinkN(&ob->defbase, dg); - - /* Update the active deform index if necessary */ - if (ob->actdef > def_nr) - ob->actdef--; - if (ob->actdef < 1 && ob->defbase.first) - ob->actdef = 1; - - /* remove all dverts */ - if (BLI_listbase_is_empty(&ob->defbase)) { - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); - me->dvert = NULL; - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = ob->data; - if (lt->dvert) { - MEM_freeN(lt->dvert); - lt->dvert = NULL; - } - } - } -} - -/* only in editmode */ -/* removes from active defgroup, if allverts==0 only selected vertices */ -static bool vgroup_active_remove_verts(Object *ob, const bool allverts, bDeformGroup *dg) -{ - MDeformVert *dv; - const int def_nr = BLI_findindex(&ob->defbase, dg); - bool changed = false; - - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (me->edit_btmesh) { - BMEditMesh *em = me->edit_btmesh; - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - if (cd_dvert_offset != -1) { - BMVert *eve; - BMIter iter; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - - if (dv && dv->dw && (allverts || BM_elem_flag_test(eve, BM_ELEM_SELECT))) { - MDeformWeight *dw = defvert_find_index(dv, def_nr); - defvert_remove_group(dv, dw); /* dw can be NULL */ - changed = true; - } - } - } - } - else { - if (me->dvert) { - MVert *mv; - int i; - - mv = me->mvert; - dv = me->dvert; - - for (i = 0; i < me->totvert; i++, mv++, dv++) { - if (mv->flag & SELECT) { - if (dv->dw && (allverts || (mv->flag & SELECT))) { - MDeformWeight *dw = defvert_find_index(dv, def_nr); - defvert_remove_group(dv, dw); /* dw can be NULL */ - changed = true; - } - } - } - } - } - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - - if (lt->dvert) { - BPoint *bp; - int i, tot = lt->pntsu * lt->pntsv * lt->pntsw; - - for (i = 0, bp = lt->def; i < tot; i++, bp++) { - if (allverts || (bp->f1 & SELECT)) { - MDeformWeight *dw; - - dv = <->dvert[i]; - - dw = defvert_find_index(dv, def_nr); - defvert_remove_group(dv, dw); /* dw can be NULL */ - changed = true; - } - } - } - } - - return changed; -} - -static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg) -{ - int i; - const int dg_index = BLI_findindex(&ob->defbase, dg); - - BLI_assert(dg_index != -1); - - /* Make sure that no verts are using this group */ - if (vgroup_active_remove_verts(ob, true, dg) == false) { - /* do nothing */ - } - /* Make sure that any verts with higher indices are adjusted accordingly */ - else if (ob->type == OB_MESH) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_btmesh; - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - BMIter iter; - BMVert *eve; - MDeformVert *dvert; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - - if (dvert) - for (i = 0; i < dvert->totweight; i++) - if (dvert->dw[i].def_nr > dg_index) - dvert->dw[i].def_nr--; - } - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - BPoint *bp; - MDeformVert *dvert = lt->dvert; - int a, tot; - - if (dvert) { - tot = lt->pntsu * lt->pntsv * lt->pntsw; - for (a = 0, bp = lt->def; a < tot; a++, bp++, dvert++) { - for (i = 0; i < dvert->totweight; i++) { - if (dvert->dw[i].def_nr > dg_index) - dvert->dw[i].def_nr--; - } - } - } - } - - vgroup_delete_update_users(ob, dg_index + 1); - - /* Remove the group */ - BLI_freelinkN(&ob->defbase, dg); - - /* Update the active deform index if necessary */ - if (ob->actdef > dg_index) - ob->actdef--; - if (ob->actdef < 1 && ob->defbase.first) - ob->actdef = 1; - - /* remove all dverts */ - if (BLI_listbase_is_empty(&ob->defbase)) { - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); - me->dvert = NULL; - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - if (lt->dvert) { - MEM_freeN(lt->dvert); - lt->dvert = NULL; - } - } - } -} - -static void vgroup_delete(Object *ob) +static void vgroup_delete_active(Object *ob) { bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); if (!dg) return; - if (BKE_object_is_in_editmode_vgroup(ob)) - vgroup_delete_edit_mode(ob, dg); - else - vgroup_delete_object_mode(ob, dg); -} - -static void vgroup_delete_all(Object *ob) -{ - /* Remove all DVerts */ - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); - me->dvert = NULL; - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - if (lt->dvert) { - MEM_freeN(lt->dvert); - lt->dvert = NULL; - } - } - - /* Remove all DefGroups */ - BLI_freelistN(&ob->defbase); - - /* Fix counters/indices */ - ob->actdef = 0; + BKE_object_defgroup_remove(ob, dg); } /* only in editmode */ @@ -3061,7 +2222,7 @@ static void vgroup_assign_verts(Object *ob, const float weight) int i; if (!me->dvert) { - ED_vgroup_data_create(&me->id); + BKE_object_defgroup_data_create(&me->id); } mv = me->mvert; @@ -3085,7 +2246,7 @@ static void vgroup_assign_verts(Object *ob, const float weight) int a, tot; if (lt->dvert == NULL) - ED_vgroup_data_create(<->id); + BKE_object_defgroup_data_create(<->id); dv = lt->dvert; @@ -3103,22 +2264,6 @@ static void vgroup_assign_verts(Object *ob, const float weight) } } -/* only in editmode */ -/* removes from all defgroup, if allverts==0 only selected vertices */ -static bool vgroup_remove_verts(Object *ob, int allverts) -{ - bool changed = false; - /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that - * only operates on the active vgroup. So we iterate through all groups, by changing - * active group index - */ - bDeformGroup *dg; - for (dg = ob->defbase.first; dg; dg = dg->next) { - changed |= vgroup_active_remove_verts(ob, allverts, dg); - } - return changed; -} - /********************** vertex group operators *********************/ static int vertex_group_poll(bContext *C) @@ -3150,7 +2295,7 @@ static int vertex_group_mesh_poll(bContext *C) ob->defbase.first); } -static int vertex_group_mesh_supported_poll(bContext *C) +static int UNUSED_FUNCTION(vertex_group_mesh_supported_poll)(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; @@ -3226,7 +2371,7 @@ static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); - ED_vgroup_add(ob); + BKE_object_defgroup_add(ob); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -3254,9 +2399,9 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op) Object *ob = ED_object_context(C); if (RNA_boolean_get(op->ptr, "all")) - vgroup_delete_all(ob); + BKE_object_defgroup_remove_all(ob); else - vgroup_delete(ob); + vgroup_delete_active(ob); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); @@ -3321,7 +2466,7 @@ static int vertex_group_assign_new_exec(bContext *C, wmOperator *op) { /* create new group... */ Object *ob = ED_object_context(C); - ED_vgroup_add(ob); + BKE_object_defgroup_add(ob); /* assign selection to new group */ return vertex_group_assign_exec(C, op); @@ -3353,14 +2498,14 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op) Object *ob = ED_object_context(C); if (use_all_groups) { - if (vgroup_remove_verts(ob, 0) == false) { + if (BKE_object_defgroup_clear_all(ob, true) == false) { return OPERATOR_CANCELLED; } } else { bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); - if ((dg == NULL) || (vgroup_active_remove_verts(ob, use_all_verts, dg) == false)) { + if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) { return OPERATOR_CANCELLED; } } @@ -3486,7 +2631,7 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op) int subset_count, vgroup_tot; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain); MEM_freeN((void *)vgroup_validmap); @@ -3552,7 +2697,7 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op) int subset_count, vgroup_tot; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, subset_count, lock_active); MEM_freeN((void *)vgroup_validmap); @@ -3674,7 +2819,7 @@ static int vertex_group_invert_exec(bContext *C, wmOperator *op) int subset_count, vgroup_tot; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove); MEM_freeN((void *)vgroup_validmap); @@ -3715,7 +2860,7 @@ static int vertex_group_blend_exec(bContext *C, wmOperator *op) int subset_count, vgroup_tot; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); vgroup_blend_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac); MEM_freeN((void *)vgroup_validmap); @@ -3791,7 +2936,7 @@ static int vertex_group_clean_exec(bContext *C, wmOperator *op) int subset_count, vgroup_tot; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single); MEM_freeN((void *)vgroup_validmap); @@ -3832,7 +2977,7 @@ static int vertex_group_quantize_exec(bContext *C, wmOperator *op) int subset_count, vgroup_tot; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps); MEM_freeN((void *)vgroup_validmap); @@ -3870,7 +3015,7 @@ static int vertex_group_limit_total_exec(bContext *C, wmOperator *op) int subset_count, vgroup_tot; - const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); int remove_tot = vgroup_limit_total_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit); MEM_freeN((void *)vgroup_validmap); @@ -3934,7 +3079,7 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) /* identifiers */ ot->name = "Mirror Vertex Group"; ot->idname = "OBJECT_OT_vertex_group_mirror"; - ot->description = "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, " + ot->description = "Mirror vertex group, flip weights and/or names, editing only selected vertices, " "flipping when both sides are selected otherwise copy from unselected"; /* api callbacks */ @@ -4032,143 +3177,6 @@ void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int vertex_group_transfer_weight_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Object *ob_act = CTX_data_active_object(C); - - bDeformGroup *dg_act = BLI_findlink(&ob_act->defbase, (ob_act->actdef - 1)); - char dg_act_name[MAX_VGROUP_NAME]; /* may be freed so copy */ - - int fail = 0; - bool changed = false; - - WT_VertexGroupMode vertex_group_mode = RNA_enum_get(op->ptr, "group_select_mode"); - WT_Method method = RNA_enum_get(op->ptr, "method"); - WT_ReplaceMode replace_mode = RNA_enum_get(op->ptr, "replace_mode"); - - if (vertex_group_mode == WT_REPLACE_ACTIVE_VERTEX_GROUP) { - if (!dg_act) { - BKE_report(op->reports, RPT_WARNING, "Failed, active object has no active groups"); - return OPERATOR_FINISHED; /* to get the chance to make changes in the redo panel*/ - } - } - - if (dg_act) { - BLI_strncpy(dg_act_name, dg_act->name, sizeof(dg_act_name)); - } - - /* Macro to loop through selected objects and perform operation depending on function, option and method.*/ - CTX_DATA_BEGIN (C, Object *, ob_src, selected_editable_objects) - { - if (ob_act != ob_src) { - - if (BLI_listbase_is_empty(&ob_src->defbase)) { - BKE_reportf(op->reports, RPT_WARNING, - "Skipping object '%s' it has no vertex groups", ob_src->id.name + 2); - continue; - } - else if (ob_src->type != OB_MESH) { - /* armatures can be in pose mode so ignore them */ - if (ob_src->type != OB_ARMATURE) { - BKE_reportf(op->reports, RPT_WARNING, - "Skipping object '%s' only copying from meshes is supported", ob_src->id.name + 2); - } - continue; - } - - switch (vertex_group_mode) { - - case WT_REPLACE_ACTIVE_VERTEX_GROUP: - { - bDeformGroup *dg_src; - dg_src = defgroup_find_name(ob_src, dg_act_name); - - if (dg_src == NULL) { - BKE_reportf(op->reports, RPT_WARNING, - "Skipping object '%s' no group '%s' found", ob_src->id.name + 2, dg_act_name); - continue; - } - - if (ed_vgroup_transfer_weight(ob_act, ob_src, dg_src, scene, method, replace_mode, op)) { - changed = true; - } - else { - fail++; - } - break; - } - case WT_REPLACE_ALL_VERTEX_GROUPS: - { - bDeformGroup *dg_src; - for (dg_src = ob_src->defbase.first; dg_src; dg_src = dg_src->next) { - if (ed_vgroup_transfer_weight(ob_act, ob_src, dg_src, scene, method, replace_mode, op)) { - changed = true; - } - else { - fail++; - } - } - break; - } - default: - BLI_assert(0); - break; - } - } - } - CTX_DATA_END; - - if (changed) { - - /* possible the active vertex group changed because of adding/removing */ - /* note!, dg_act may be realloc'd, only check its not NULL */ - if (dg_act) { - ED_vgroup_select_by_name(ob_act, dg_act_name); - } - else { - ED_vgroup_sync_from_pose(ob_act); - } - - /* Event notifiers for correct display of data.*/ - - - DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_act); /* for buttons */ - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_act); - return OPERATOR_FINISHED; - } - else { - if (BLI_listbase_is_empty(&op->reports->list)) { - BKE_report(op->reports, RPT_WARNING, "Failed, no other selected objects with vertex groups found"); - } - - return OPERATOR_FINISHED; /* to get the chance to make changes in the redo panel */ - } -} - -/* transfers weight from active to selected */ -void OBJECT_OT_vertex_group_transfer_weight(wmOperatorType *ot) -{ - /* Identifiers.*/ - ot->name = "Transfer Weights"; - ot->idname = "OBJECT_OT_vertex_group_transfer_weight"; - ot->description = "Transfer weight paint to active from selected mesh"; - - /* API callbacks.*/ - ot->poll = vertex_group_mesh_supported_poll; - ot->exec = vertex_group_transfer_weight_exec; - - /* Flags.*/ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* Properties.*/ - /* TODO, use vgroup_operator_subset_select_props for group_select_mode */ - ot->prop = RNA_def_enum(ot->srna, "group_select_mode", WT_vertex_group_mode_item, WT_REPLACE_ALL_VERTEX_GROUPS, "Group", ""); - ot->prop = RNA_def_enum(ot->srna, "method", WT_method_item, WT_BY_NEAREST_FACE, "Method", ""); - ot->prop = RNA_def_enum(ot->srna, "replace_mode", WT_replace_mode_item, WT_REPLACE_ALL_WEIGHTS, "Replace", ""); -} - static int set_active_group_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); @@ -4297,7 +3305,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) else { int dvert_tot = 0; - ED_vgroup_array_get(ob->data, &dvert, &dvert_tot); + BKE_object_defgroup_array_get(ob->data, &dvert, &dvert_tot); /*create as necessary*/ if (dvert) { @@ -4314,7 +3322,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) sort_map[i]++; sort_map_update[0] = 0; - vgroup_remap_update_users(ob, sort_map_update); + BKE_object_defgroup_remap_update_users(ob, sort_map_update); BLI_assert(sort_map_update[ob->actdef] >= 0); ob->actdef = sort_map_update[ob->actdef]; diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c index 8016dabf3a3..7413bb07c4c 100644 --- a/source/blender/editors/object/object_warp.c +++ b/source/blender/editors/object/object_warp.c @@ -31,7 +31,6 @@ #include "BLI_math.h" -#include "BKE_utildefines.h" #include "BKE_context.h" #include "RNA_access.h" diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 637af5d6536..d864934171b 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -40,6 +40,7 @@ #include "BKE_blender.h" #include "BKE_context.h" #include "BKE_deform.h" +#include "BKE_object_deform.h" #include "BKE_depsgraph.h" #include "BKE_dynamicpaint.h" #include "BKE_global.h" @@ -235,11 +236,11 @@ static int output_toggle_exec(bContext *C, wmOperator *op) /* Vertex Weight Layer */ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { if (!exists) { - ED_vgroup_add_name(ob, name); + BKE_object_defgroup_add_name(ob, name); } else { bDeformGroup *defgroup = defgroup_find_name(ob, name); - if (defgroup) ED_vgroup_delete(ob, defgroup); + if (defgroup) BKE_object_defgroup_remove(ob, defgroup); } } } diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index b53891f4880..b5adf38527b 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -72,8 +72,6 @@ #include "DNA_scene_types.h" #include "DNA_mesh_types.h" -#include "PIL_time.h" - static float get_fluid_viscosity(FluidsimSettings *settings) { diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index 2a8718b3ef5..37cf95e5c2d 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -29,10 +29,6 @@ #include <stdlib.h> -#include "DNA_scene_types.h" - -#include "BLI_utildefines.h" - #include "RNA_access.h" #include "WM_api.h" diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index dd0816e509d..85b059d5574 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -37,8 +37,6 @@ #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -#include "BLI_math.h" - #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index 13a3d7a523f..9b4f128ef86 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -33,16 +33,12 @@ #include <stdlib.h> #include <string.h> -#include "MEM_guardedalloc.h" -#include "DNA_group_types.h" #include "DNA_object_types.h" -#include "DNA_mesh_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "BLI_blenlib.h" -#include "BLI_math.h" #include "BLF_translation.h" @@ -50,7 +46,6 @@ #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_group.h" -#include "BKE_object.h" #include "BKE_report.h" #include "BKE_rigidbody.h" diff --git a/source/blender/editors/physics/rigidbody_world.c b/source/blender/editors/physics/rigidbody_world.c index 1c893992cf2..7bb189bd71b 100644 --- a/source/blender/editors/physics/rigidbody_world.c +++ b/source/blender/editors/physics/rigidbody_world.c @@ -37,8 +37,6 @@ #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -#include "BLI_math.h" - #ifdef WITH_BULLET # include "RBI_api.h" #endif @@ -48,8 +46,6 @@ #include "BKE_rigidbody.h" #include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -199,5 +195,5 @@ void RIGIDBODY_OT_world_export(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE, FILE_SPECIAL, FILE_SAVE, FILE_RELPATH, FILE_DEFAULTDISPLAY); + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, FILE_SPECIAL, FILE_SAVE, FILE_RELPATH, FILE_DEFAULTDISPLAY); } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index baf25a49f7c..b04f1d3e738 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -75,10 +75,8 @@ #include "RE_engine.h" #include "IMB_colormanagement.h" -#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "GPU_extensions.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -86,7 +84,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "wm_window.h" #include "render_intern.h" @@ -343,7 +340,11 @@ static void render_freejob(void *rjv) } /* str is IMA_MAX_RENDER_TEXT in size */ -static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_override, char *str) +static void make_renderinfo_string(const RenderStats *rs, + const Scene *scene, + const bool v3d_override, + const char *error, + char *str) { char info_time_str[32]; // used to be extern to header_info.c uintptr_t mem_in_use, mmap_in_use, peak_memory; @@ -416,8 +417,12 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_overr spos += sprintf(spos, IFACE_("| Full Sample %d "), rs->curfsa); /* extra info */ - if (rs->infostr && rs->infostr[0]) + if (rs->infostr && rs->infostr[0]) { spos += sprintf(spos, "| %s ", rs->infostr); + } + else if (error && error[0]) { + spos += sprintf(spos, "| %s ", error); + } /* very weak... but 512 characters is quite safe */ if (spos >= str + IMA_MAX_RENDER_TEXT) @@ -438,7 +443,8 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs) if (rr->text == NULL) rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"); - make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->text); + make_renderinfo_string(rs, rj->scene, rj->v3d_override, + rr->error, rr->text); } RE_ReleaseResult(rj->re); @@ -1121,7 +1127,7 @@ static void render_view3d_renderinfo_cb(void *rjp, RenderStats *rs) *rp->stop = 1; } else { - make_renderinfo_string(rs, rp->scene, false, rp->engine->text); + make_renderinfo_string(rs, rp->scene, false, NULL, rp->engine->text); /* make jobs timer to send notifier */ *(rp->do_update) = true; @@ -1439,7 +1445,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) rp->bmain = CTX_data_main(C); rp->resolution_divider = divider; rp->start_resolution_divider = divider; - rp->has_freestyle = scene->r.mode & R_EDGE_FRS; + rp->has_freestyle = (scene->r.mode & R_EDGE_FRS) != 0; copy_m4_m4(rp->viewmat, rp->rv3d->viewmat); /* clear info text */ @@ -1551,10 +1557,10 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) RE_ReleaseResultImage(re); } -void ED_viewport_render_kill_jobs(const bContext *C, bool free_database) +void ED_viewport_render_kill_jobs(wmWindowManager *wm, + Main *bmain, + bool free_database) { - wmWindowManager *wm = CTX_wm_manager(C); - Main *bmain = CTX_data_main(C); bScreen *sc; ScrArea *sa; ARegion *ar; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 559c86bf48c..8024add41cf 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -69,7 +69,6 @@ #include "GPU_extensions.h" #include "GPU_glew.h" -#include "wm_window.h" #include "render_intern.h" @@ -144,8 +143,10 @@ static void screen_opengl_render_apply(OGLRender *oglrender) int chanshown = sseq ? sseq->chanshown : 0; struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL; - context = BKE_sequencer_new_render_data(oglrender->bmain->eval_ctx, oglrender->bmain, - scene, oglrender->sizex, oglrender->sizey, 100.0f); + BKE_sequencer_new_render_data( + oglrender->bmain->eval_ctx, oglrender->bmain, scene, + oglrender->sizex, oglrender->sizey, 100.0f, + &context); ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); @@ -187,7 +188,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender) wmOrtho2(0, sizex, 0, sizey); glTranslatef(sizex / 2, sizey / 2, 0.0f); - ED_gpencil_draw_ex(gpd, sizex, sizey, scene->r.cfra); + G.f |= G_RENDER_OGL; + ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); + G.f &= ~G_RENDER_OGL; gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect); @@ -271,7 +274,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender) /* shouldnt suddenly give errors mid-render but possible */ char err_out[256] = "unknown"; ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey, - IB_rect, OB_SOLID, false, true, + IB_rect, OB_SOLID, false, true, true, (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, err_out); camera = scene->camera; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 2a0ec853079..ea80a07fdd4 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -60,6 +60,7 @@ #include "DNA_brush_types.h" #include "DNA_screen_types.h" +#include "BKE_appdir.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_colortools.h" @@ -78,14 +79,11 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "IMB_colormanagement.h" -#include "GPU_extensions.h" #include "BIF_gl.h" #include "BIF_glutil.h" -#include "PIL_time.h" #include "RE_pipeline.h" #include "RE_engine.h" @@ -96,9 +94,7 @@ #include "ED_datafiles.h" #include "ED_render.h" -#include "UI_interface.h" -#include "render_intern.h" ImBuf *get_brush_icon(Brush *brush) { @@ -121,7 +117,7 @@ ImBuf *get_brush_icon(Brush *brush) // otherwise lets try to find it in other directories if (!(brush->icon_imbuf)) { - folder = BLI_get_folder(BLENDER_DATAFILES, "brushicons"); + folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons"); BLI_make_file_string(G.main->name, path, folder, brush->icon_filepath); @@ -565,8 +561,9 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); float fx = rect->xmin + offx; float fy = rect->ymin; + if (re) + RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte); - RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte); glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte); MEM_freeN(rect_byte); @@ -1101,6 +1098,25 @@ static void icon_preview_free(void *customdata) MEM_freeN(ip); } +void ED_preview_icon_render(Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey) +{ + IconPreview ip = {0}; + short stop = false, update = false; + float progress = 0.0f; + + ip.scene = scene; + ip.owner = id; + ip.id = id; + + icon_preview_add_size(&ip, rect, sizex, sizey); + + icon_preview_startjob_all_sizes(&ip, &stop, &update, &progress); + + icon_preview_endjob(&ip); + + BLI_freelistN(&ip.sizes); +} + void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey) { wmJob *wm_job; @@ -1180,12 +1196,11 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M WM_jobs_start(CTX_wm_manager(C), wm_job); } -void ED_preview_kill_jobs(const struct bContext *C) +void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain) { - wmWindowManager *wm = CTX_wm_manager(C); if (wm) WM_jobs_kill(wm, NULL, common_preview_startjob); - - ED_viewport_render_kill_jobs(C, false); + + ED_viewport_render_kill_jobs(wm, bmain, false); } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index eaa7cf40aca..91c689373be 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -51,7 +51,6 @@ #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_font.h" -#include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" @@ -65,17 +64,15 @@ #include "BKE_world.h" #include "BKE_editmesh.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" -#include "GPU_material.h" #ifdef WITH_FREESTYLE +# include "BKE_freestyle.h" # include "FRS_freestyle.h" +# include "RNA_enum_types.h" #endif #include "RNA_access.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -1481,7 +1478,7 @@ void TEXTURE_OT_envmap_save(wmOperatorType *ot) "(use -1 to skip a face)", 0.0f, 0.0f); RNA_def_property_flag(prop, PROP_HIDDEN); - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 6118db703b4..be42e2ed518 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -41,11 +41,11 @@ #include "DNA_world_types.h" #include "DNA_windowmanager_types.h" +#include "BLI_listbase.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_icons.h" #include "BKE_main.h" @@ -85,7 +85,11 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) /* don't call this recursively for frame updates */ if (recursive_check) return; - + + /* Do not call if no WM available, see T42688. */ + if (BLI_listbase_is_empty(&bmain->wm)) + return; + recursive_check = true; C = CTX_create(); @@ -276,7 +280,7 @@ static void material_changed(Main *bmain, Material *ma) /* glsl */ if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); /* find node materials using this */ for (parent = bmain->mat.first; parent; parent = parent->id.next) { @@ -290,7 +294,7 @@ static void material_changed(Main *bmain, Material *ma) BKE_icon_changed(BKE_icon_getid(&parent->id)); if (parent->gpumaterial.first) - GPU_material_free(parent); + GPU_material_free(&parent->gpumaterial); } /* find if we have a scene with textured display */ @@ -336,10 +340,10 @@ static void lamp_changed(Main *bmain, Lamp *la) for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); } static int material_uses_texture(Material *ma, Tex *tex) @@ -377,7 +381,7 @@ static void texture_changed(Main *bmain, Tex *tex) BKE_icon_changed(BKE_icon_getid(&ma->id)); if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); } /* find lamps */ @@ -406,6 +410,9 @@ static void texture_changed(Main *bmain, Tex *tex) } BKE_icon_changed(BKE_icon_getid(&wo->id)); + + if (wo->gpumaterial.first) + GPU_material_free(&wo->gpumaterial); } /* find compositing nodes */ @@ -451,14 +458,17 @@ static void world_changed(Main *bmain, World *wo) /* icons */ BKE_icon_changed(BKE_icon_getid(&wo->id)); - + /* glsl */ for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); + + if (wo->gpumaterial.first) + GPU_material_free(&wo->gpumaterial); } static void image_changed(Main *bmain, Image *ima) @@ -478,6 +488,7 @@ static void scene_changed(Main *bmain, Scene *scene) { Object *ob; Material *ma; + World *wo; /* glsl */ for (ob = bmain->object.first; ob; ob = ob->id.next) { @@ -487,16 +498,20 @@ static void scene_changed(Main *bmain, Scene *scene) if (ob->mode & OB_MODE_TEXTURE_PAINT) { BKE_texpaint_slots_refresh_object(scene, ob); BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - GPU_drawobject_free(ob->derivedFinal); + GPU_drawobject_free(ob->derivedFinal); } } for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); + for (wo = bmain->world.first; wo; wo = wo->id.next) + if (wo->gpumaterial.first) + GPU_material_free(&wo->gpumaterial); + if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); } void ED_render_id_flush_update(Main *bmain, ID *id) diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 630ff8fecf6..71714bdcda9 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -41,7 +41,6 @@ #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" -#include "BLF_translation.h" #include "BKE_context.h" #include "BKE_global.h" @@ -896,7 +895,7 @@ static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar) static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen) { - AZone *az; + AZone *az = NULL; const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) == 0; if (is_hidden || !is_fullscreen) { @@ -907,7 +906,7 @@ static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const az->edge = edge; } - if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) { + if (!is_hidden) { if (!is_fullscreen) { if (G.debug_value == 3) region_azone_icon(sa, az, ar); @@ -1352,8 +1351,18 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand } if (flag & ED_KEYMAP_GPENCIL) { /* grease pencil */ - wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0); - WM_event_add_keymap_handler(handlers, keymap); + /* NOTE: This is now 2 keymaps - One for basic functionality, + * and one that only applies when "Edit Mode" is enabled + * for strokes. + * + * For now, it's easier to just include both, + * since you hardly want one without the other. + */ + wmKeyMap *keymap_general = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0); + wmKeyMap *keymap_edit = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0); + + WM_event_add_keymap_handler(handlers, keymap_general); + WM_event_add_keymap_handler(handlers, keymap_edit); } if (flag & ED_KEYMAP_HEADER) { /* standard keymap for headers regions */ diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index c095dfe7792..134feb59d55 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -45,7 +45,6 @@ #include "BIF_gl.h" #include "BIF_glutil.h" -#include "GPU_extensions.h" #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 18c9a94e46f..ce9c608247b 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -26,12 +26,13 @@ * \ingroup edscr */ - +#include <stdio.h> #include <stdlib.h> #include <string.h> #include "DNA_object_types.h" #include "DNA_armature_types.h" +#include "DNA_gpencil_types.h" #include "DNA_sequence_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -45,11 +46,13 @@ #include "BKE_object.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_gpencil.h" #include "BKE_sequencer.h" #include "RNA_access.h" #include "ED_armature.h" +#include "ED_gpencil.h" #include "WM_api.h" #include "UI_interface.h" @@ -66,12 +69,16 @@ const char *screen_context_dir[] = { "sculpt_object", "vertex_paint_object", "weight_paint_object", "image_paint_object", "particle_edit_object", "sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */ + "gpencil_data", "gpencil_data_owner", /* grease pencil data */ + "visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes", + "active_gpencil_layer", "active_gpencil_frame", "active_operator", NULL}; int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result) { bScreen *sc = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); Scene *scene = sc->scene; Base *base; unsigned int lay = scene->lay; @@ -392,6 +399,112 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } } + else if (CTX_data_equals(member, "gpencil_data")) { + /* FIXME: for some reason, CTX_data_active_object(C) returns NULL when called from these situations + * (as outlined above - see Campbell's #ifdefs). That causes the get_active function to fail when + * called from context. For that reason, we end up using an alternative where we pass everything in! + */ + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + + if (gpd) { + CTX_data_id_pointer_set(result, &gpd->id); + return 1; + } + } + else if (CTX_data_equals(member, "gpencil_data_owner")) { + /* pointer to which data/datablock owns the reference to the Grease Pencil data being used (as gpencil_data) + * XXX: see comment for gpencil_data case... + */ + bGPdata **gpd_ptr = NULL; + PointerRNA ptr; + + /* get pointer to Grease Pencil Data */ + gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, scene, sa, obact, &ptr); + + if (gpd_ptr) { + CTX_data_pointer_set(result, ptr.id.data, ptr.type, ptr.data); + return 1; + } + } + else if (CTX_data_equals(member, "active_gpencil_layer")) { + /* XXX: see comment for gpencil_data case... */ + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + + if (gpd) { + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + + if (gpl) { + CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl); + return 1; + } + } + } + else if (CTX_data_equals(member, "active_gpencil_frame")) { + /* XXX: see comment for gpencil_data case... */ + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + + if (gpd) { + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + + if (gpl) { + CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe); + return 1; + } + } + } + else if (CTX_data_equals(member, "visible_gpencil_layers")) { + /* XXX: see comment for gpencil_data case... */ + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + + if (gpd) { + bGPDlayer *gpl; + + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if ((gpl->flag & GP_LAYER_HIDE) == 0) { + CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl); + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + } + else if (CTX_data_equals(member, "editable_gpencil_layers")) { + /* XXX: see comment for gpencil_data case... */ + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + + if (gpd) { + bGPDlayer *gpl; + + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) { + CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl); + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + } + else if (CTX_data_equals(member, "editable_gpencil_strokes")) { + /* XXX: see comment for gpencil_data case... */ + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + + if (gpd) { + bGPDlayer *gpl; + + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 && (gpl->actframe)) { + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps; + + for (gps = gpf->strokes.first; gps; gps = gps->next) { + CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps); + } + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + } else if (CTX_data_equals(member, "active_operator")) { wmOperator *op = NULL; @@ -400,7 +513,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult op = sfile->op; } else if ((op = UI_context_active_operator_get(C))) { - /* do nothign */ + /* do nothing */ } else { /* note, this checks poll, could be a problem, but this also diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index c179cfc464c..3972d00293c 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1748,6 +1748,13 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type) } } + if (sa && (sa->spacetype != type)) { + newsa->flag |= AREA_FLAG_TEMP_TYPE; + } + else { + newsa->flag &= ~AREA_FLAG_TEMP_TYPE; + } + ED_area_newspace(C, newsa, type); return newsa; @@ -1763,6 +1770,21 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa) ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED); } +void ED_screen_retore_temp_type(bContext *C, ScrArea *sa, bool is_screen_change) +{ + /* incase nether functions below run */ + ED_area_tag_redraw(sa); + + if (sa->flag & AREA_FLAG_TEMP_TYPE) { + ED_area_prevspace(C, sa); + sa->flag &= ~AREA_FLAG_TEMP_TYPE; + } + + if (is_screen_change && sa->full) { + ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED); + } +} + /* restore a screen / area back to default operation, after temp fullscreen modes */ void ED_screen_full_restore(bContext *C, ScrArea *sa) { @@ -1789,12 +1811,14 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa) else ED_screen_state_toggle(C, win, sa, state); } - else if (sl->spacetype == SPACE_FILE) { + else if (sa->flag & AREA_FLAG_TEMP_TYPE) { ED_screen_full_prevspace(C, sa); } else { ED_screen_state_toggle(C, win, sa, state); } + + sa->flag &= ~AREA_FLAG_TEMP_TYPE; } /* otherwise just tile the area again */ else { @@ -1857,6 +1881,11 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s BKE_screen_free(oldscreen); BKE_libblock_free(CTX_data_main(C), oldscreen); + /* After we've restored back to SCREENNORMAL, we have to wait with + * screen handling as it uses the area coords which aren't updated yet. + * Without doing so, the screen handling gets wrong area coords, + * which in worst case can lead to crashes (see T43139) */ + sc->skip_handling = true; } else { /* change from SCREENNORMAL to new state */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 454bb3b7ca3..39321ec0770 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -43,6 +43,7 @@ #include "DNA_lattice_types.h" #include "DNA_object_types.h" #include "DNA_curve_types.h" +#include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_meta_types.h" #include "DNA_mask_types.h" @@ -81,8 +82,6 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "wm_window.h" - #include "screen_intern.h" /* own module include */ #define KM_MODAL_CANCEL 1 @@ -2150,6 +2149,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); + bGPdata *gpd = CTX_data_gpencil_data(C); bDopeSheet ads = {NULL}; DLRBT_Tree keys; ActKeyColumn *ak; @@ -2177,7 +2177,9 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op) if (ob) ob_to_keylist(&ads, ob, &keys, NULL); - + + gpencil_to_keylist(&ads, gpd, &keys); + { Mask *mask = CTX_data_edit_mask(C); if (mask) { @@ -3523,12 +3525,14 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot) /* find window that owns the animation timer */ bScreen *ED_screen_animation_playing(const wmWindowManager *wm) { - wmWindow *window; + wmWindow *win; + + for (win = wm->windows.first; win; win = win->next) { + if (win->screen->animtimer) { + return win->screen; + } + } - for (window = wm->windows.first; window; window = window->next) - if (window->screen->animtimer) - return window->screen; - return NULL; } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index be5fd48b41a..e7f256e414a 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -65,7 +65,6 @@ #include "PIL_time.h" -#include "ED_screen_types.h" #include "screen_intern.h" @@ -287,7 +286,7 @@ void SCREEN_OT_screenshot(wmOperatorType *ot) ot->flag = 0; - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, "full", 1, "Full Screen", "Capture the whole window (otherwise only capture the active area)"); diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index e27ef705fad..430ea1cc11d 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -341,8 +341,8 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } BKE_paint_reset_overlay_invalid(invalid); @@ -426,7 +426,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) len = sqrtf(x * x + y * y); if (len <= 1) { - float avg = BKE_brush_curve_strength_clamp(br, len, 1.0f); /* Falloff curve */ + float avg = BKE_brush_curve_strength(br, len, 1.0f); /* Falloff curve */ buffer[index] = 255 - (GLubyte)(255 * avg); @@ -464,8 +464,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); BKE_paint_reset_overlay_invalid(PAINT_INVALID_OVERLAY_CURVE); @@ -595,7 +595,7 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush, if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { /* brush rotation */ glTranslatef(0.5, 0.5, 0); - glRotatef((double)RAD2DEGF(ups->brush_rotation), + glRotatef((double)RAD2DEGF((primary) ? ups->brush_rotation : ups->brush_rotation_sec), 0.0, 0.0, 1.0); glTranslatef(-0.5f, -0.5f, 0); @@ -1000,9 +1000,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* don't calculate rake angles while a stroke is active because the rake variables are global and * we may get interference with the stroke itself. For line strokes, such interference is visible */ if (!ups->stroke_active) { - if (brush->flag & BRUSH_RAKE) - /* here, translation contains the mouse coordinates. */ - paint_calculate_rake_rotation(ups, translation); + paint_calculate_rake_rotation(ups, brush, translation); } /* draw overlay */ diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index 8c7c3b102e3..1f5ee708ad0 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -329,7 +329,7 @@ void PAINTCURVE_OT_add_point(wmOperatorType *ot) { /* identifiers */ ot->name = "Add New Paint Curve Point"; - ot->description = "Add new paint curve point"; + ot->description = ot->name; ot->idname = "PAINTCURVE_OT_add_point"; /* api callbacks */ @@ -410,8 +410,8 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op) void PAINTCURVE_OT_delete_point(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add New Paint Curve Point"; - ot->description = "Add new paint curve point"; + ot->name = "Remove Paint Curve Point"; + ot->description = ot->name; ot->idname = "PAINTCURVE_OT_delete_point"; /* api callbacks */ diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 021822793ff..d52b17372f7 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -45,13 +45,11 @@ #include "BLI_utildefines.h" #include "BLI_threads.h" -#include "PIL_time.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" -#include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -62,15 +60,9 @@ #include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" #include "BKE_node.h" #include "BKE_paint.h" -#include "BKE_report.h" -#include "BKE_scene.h" #include "BKE_texture.h" -#include "BKE_colortools.h" - -#include "BKE_editmesh.h" #include "UI_view2d.h" @@ -85,7 +77,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "GPU_draw.h" #include "GPU_buffers.h" @@ -671,22 +662,24 @@ void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_cor copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br)); else { if (br->flag & BRUSH_USE_GRADIENT) { + float color_gr[4]; switch (br->gradient_stroke_mode) { case BRUSH_GRADIENT_PRESSURE: - do_colorband(br->gradient, pressure, color); + do_colorband(br->gradient, pressure, color_gr); break; case BRUSH_GRADIENT_SPACING_REPEAT: { float coord = fmod(distance / br->gradient_spacing, 1.0); - do_colorband(br->gradient, coord, color); + do_colorband(br->gradient, coord, color_gr); break; } case BRUSH_GRADIENT_SPACING_CLAMP: { - do_colorband(br->gradient, distance / br->gradient_spacing, color); + do_colorband(br->gradient, distance / br->gradient_spacing, color_gr); break; } } + copy_v3_v3(color, color_gr); } else copy_v3_v3(color, BKE_brush_color_get(scene, br)); @@ -1065,7 +1058,7 @@ void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) enabled = true; if (enabled) { - BKE_paint_init(&imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT); + BKE_paint_init(&settings->unified_paint_settings, &imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT); paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll); } @@ -1422,7 +1415,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) ob->mode |= mode_flag; - BKE_paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT); + BKE_paint_init(&scene->toolsettings->unified_paint_settings, &imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT); if (U.glreslimit != 0) GPU_free_images(); diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index ea0e30a6635..95940d89694 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -38,9 +38,7 @@ #include "DNA_space_types.h" #include "DNA_object_types.h" -#include "BLI_math.h" -#include "BLI_rect.h" #include "BLI_math_color_blend.h" #include "BLI_stack.h" #include "BLI_bitmap.h" @@ -65,7 +63,6 @@ #include "UI_view2d.h" -#include "RE_shader_ext.h" #include "GPU_draw.h" @@ -362,7 +359,7 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int d float xy[2] = {x + xoff, y + yoff}; float len = len_v2(xy); - *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamp(brush, len, radius)); + *m = (unsigned short)(65535.0f * BKE_brush_curve_strength(brush, len, radius)); } } @@ -689,7 +686,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai bool do_partial_update_mask = false; /* invalidate case for all mapping modes */ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { - mask_rotation += ups->brush_rotation; + mask_rotation += ups->brush_rotation_sec; } else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) { renew_maxmask = true; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 9cc1906596f..3e675012d05 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -50,7 +50,6 @@ #include "BLF_translation.h" -#include "PIL_time.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -62,7 +61,6 @@ #include "DNA_object_types.h" #include "BKE_camera.h" -#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" @@ -80,10 +78,8 @@ #include "BKE_scene.h" #include "BKE_texture.h" -#include "UI_view2d.h" #include "UI_interface.h" -#include "ED_image.h" #include "ED_mesh.h" #include "ED_node.h" #include "ED_paint.h" @@ -101,7 +97,6 @@ #include "RNA_enum_types.h" #include "GPU_draw.h" -#include "GPU_buffers.h" #include "IMB_colormanagement.h" @@ -192,7 +187,7 @@ typedef struct ProjPaintImage { ImagePaintPartialRedraw *partRedrawRect; volatile void **undoRect; /* only used to build undo tiles during painting */ unsigned short **maskRect; /* the mask accumulation must happen on canvas, not on space screen bucket. - * Here we store the mask rectangle */ + * Here we store the mask rectangle */ bool **valid; /* store flag to enforce validation of undo rectangle */ int touch; } ProjPaintImage; @@ -1339,7 +1334,7 @@ static float project_paint_uvpixel_mask( /* now we can use the normal as a mask */ if (ps->is_ortho) { - angle = angle_normalized_v3v3((float *)ps->viewDir, no); + angle = angle_normalized_v3v3(ps->viewDir, no); } else { /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */ @@ -1967,25 +1962,63 @@ static int float_z_sort(const void *p1, const void *p2) return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1); } +/* assumes one point is within the rectangle */ +static void line_rect_clip( + rctf *rect, + const float l1[4], const float l2[4], + const float uv1[2], const float uv2[2], + float uv[2], bool is_ortho) +{ + float min = FLT_MAX, tmp; + if ((l1[0] - rect->xmin) * (l2[0] - rect->xmin) < 0) { + tmp = rect->xmin; + min = min_ff((tmp - l1[0]) / (l2[0] - l1[0]), min); + } + else if ((l1[0] - rect->xmax) * (l2[0] - rect->xmax) < 0) { + tmp = rect->xmax; + min = min_ff((tmp - l1[0]) / (l2[0] - l1[0]), min); + } + if ((l1[1] - rect->ymin) * (l2[1] - rect->ymin) < 0) { + tmp = rect->ymin; + min = min_ff((tmp - l1[1]) / (l2[1] - l1[1]), min); + } + else if ((l1[1] - rect->ymax) * (l2[1] - rect->ymax) < 0) { + tmp = rect->ymax; + min = min_ff((tmp - l1[1]) / (l2[1] - l1[1]), min); + } + + tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3])); + + uv[0] = (uv1[0] + min * (uv2[0] - uv1[0])) / tmp; + uv[1] = (uv1[1] + min * (uv2[1] - uv1[1])) / tmp; +} + + static void project_bucket_clip_face( const bool is_ortho, rctf *bucket_bounds, float *v1coSS, float *v2coSS, float *v3coSS, const float *uv1co, const float *uv2co, const float *uv3co, float bucket_bounds_uv[8][2], - int *tot) + int *tot, bool cull) { int inside_bucket_flag = 0; int inside_face_flag = 0; const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); - + bool colinear = false; + float bucket_bounds_ss[4][2]; + /* detect pathological case where face the three vertices are almost colinear in screen space. + * mostly those will be culled but when flood filling or with smooth shading */ + if (dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS) < PROJ_PIXEL_TOLERANCE) + colinear = true; + /* get the UV space bounding box */ inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS); inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1; inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2; - + if (inside_bucket_flag == ISECT_ALL3) { /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */ if (flip) { /* facing the back? */ @@ -1997,9 +2030,59 @@ static void project_bucket_clip_face( copy_v2_v2(bucket_bounds_uv[0], uv1co); copy_v2_v2(bucket_bounds_uv[1], uv2co); copy_v2_v2(bucket_bounds_uv[2], uv3co); + } + + *tot = 3; + return; + } + /* handle pathological case here, no need for further intersections below since tringle area is almost zero */ + if (colinear) { + int flag; + + (*tot) = 0; + + if (cull) + return; + + if (inside_bucket_flag & ISECT_1) { copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++; } + + flag = inside_bucket_flag & (ISECT_1 | ISECT_2); + if (flag && flag != (ISECT_1 | ISECT_2)) { + line_rect_clip(bucket_bounds, v1coSS, v2coSS, uv1co, uv2co, bucket_bounds_uv[*tot], is_ortho); + (*tot)++; + } + + if (inside_bucket_flag & ISECT_2) { copy_v2_v2(bucket_bounds_uv[*tot], uv2co); (*tot)++; } + + flag = inside_bucket_flag & (ISECT_2 | ISECT_3); + if (flag && flag != (ISECT_2 | ISECT_3)) { + line_rect_clip(bucket_bounds, v2coSS, v3coSS, uv2co, uv3co, bucket_bounds_uv[*tot], is_ortho); + (*tot)++; } - *tot = 3; + if (inside_bucket_flag & ISECT_3) { copy_v2_v2(bucket_bounds_uv[*tot], uv3co); (*tot)++; } + + flag = inside_bucket_flag & (ISECT_3 | ISECT_1); + if (flag && flag != (ISECT_3 | ISECT_1)) { + line_rect_clip(bucket_bounds, v3coSS, v1coSS, uv3co, uv1co, bucket_bounds_uv[*tot], is_ortho); + (*tot)++; + } + + if ((*tot) < 3) { /* no intersections to speak of */ + *tot = 0; + return; + } + + /* at this point we have all uv points needed in a row. all that's needed is to invert them if necessary */ + if (flip) { + /* flip only to the middle of the array */ + int i, max = *tot / 2; + for (i = 0; i < max; i++) { + SWAP(float, bucket_bounds_uv[i][0], bucket_bounds_uv[max - i][0]); + SWAP(float, bucket_bounds_uv[i][1], bucket_bounds_uv[max - i][1]); + } + } + return; } @@ -2128,47 +2211,32 @@ static void project_bucket_clip_face( if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip); else qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort); - /* remove doubles */ - /* first/last check */ - if (fabsf(isectVCosSS[0][0] - isectVCosSS[(*tot) - 1][0]) < PROJ_PIXEL_TOLERANCE && - fabsf(isectVCosSS[0][1] - isectVCosSS[(*tot) - 1][1]) < PROJ_PIXEL_TOLERANCE) - { - (*tot)--; - } - - /* its possible there is only a few left after remove doubles */ - if ((*tot) < 3) { - // printf("removed too many doubles A\n"); - *tot = 0; - return; - } - doubles = true; while (doubles == true) { doubles = false; - for (i = 1; i < (*tot); i++) { - if (fabsf(isectVCosSS[i - 1][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE && - fabsf(isectVCosSS[i - 1][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE) + + for (i = 0; i < (*tot); i++) { + if (fabsf(isectVCosSS[(i + 1) % *tot][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE && + fabsf(isectVCosSS[(i + 1) % *tot][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE) { int j; - for (j = i + 1; j < (*tot); j++) { - isectVCosSS[j - 1][0] = isectVCosSS[j][0]; - isectVCosSS[j - 1][1] = isectVCosSS[j][1]; + for (j = i; j < (*tot) - 1; j++) { + isectVCosSS[j][0] = isectVCosSS[j + 1][0]; + isectVCosSS[j][1] = isectVCosSS[j + 1][1]; } doubles = true; /* keep looking for more doubles */ (*tot)--; } } + + /* its possible there is only a few left after remove doubles */ + if ((*tot) < 3) { + // printf("removed too many doubles B\n"); + *tot = 0; + return; + } } - /* its possible there is only a few left after remove doubles */ - if ((*tot) < 3) { - // printf("removed too many doubles B\n"); - *tot = 0; - return; - } - - if (is_ortho) { for (i = 0; i < (*tot); i++) { barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w); @@ -2406,8 +2474,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i is_ortho, bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, - uv_clip, &uv_clip_tot - ); + uv_clip, &uv_clip_tot, + ps->do_backfacecull || ps->do_occlude); /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */ #if 0 @@ -2428,10 +2496,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i CLAMP(bounds_px.ymax, 0, ibuf->y); } - /* +#if 0 project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf, tile_width, threaded, ps->do_masking); - */ +#endif /* clip face and */ has_isect = 0; @@ -2821,7 +2889,7 @@ static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int buck int fidx; project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds); - + /* Is one of the faces verts in the bucket bounds? */ fidx = mf->v4 ? 3 : 2; @@ -3092,7 +3160,7 @@ static void project_paint_begin(ProjPaintState *ps) invert_m4_m4(ps->ob->imat, ps->ob->obmat); - if (ps->source == PROJ_SRC_VIEW) { + if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) { /* normal drawing */ ps->winx = ps->ar->winx; ps->winy = ps->ar->winy; @@ -3230,7 +3298,7 @@ static void project_paint_begin(ProjPaintState *ps) CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter)); #endif } - else { /* re-projection, use bounds */ + else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */ ps->screenMin[0] = 0; ps->screenMax[0] = (float)(ps->winx); @@ -3426,8 +3494,8 @@ static void project_paint_begin(ProjPaintState *ps) #ifdef PROJ_DEBUG_WINCLIP /* ignore faces outside the view */ - if ( - (v1coSS[0] < ps->screenMin[0] && + if ((ps->source != PROJ_SRC_VIEW_FILL) && + ((v1coSS[0] < ps->screenMin[0] && v2coSS[0] < ps->screenMin[0] && v3coSS[0] < ps->screenMin[0] && (mf->v4 && v4coSS[0] < ps->screenMin[0])) || @@ -3445,7 +3513,7 @@ static void project_paint_begin(ProjPaintState *ps) (v1coSS[1] > ps->screenMax[1] && v2coSS[1] > ps->screenMax[1] && v3coSS[1] > ps->screenMax[1] && - (mf->v4 && v4coSS[1] > ps->screenMax[1])) + (mf->v4 && v4coSS[1] > ps->screenMax[1]))) ) { continue; @@ -3795,10 +3863,9 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl } } -/* do_projectpaint_smear* - * - * note, mask is used to modify the alpha here, this is not correct since it allows - * accumulation of color greater then 'projPixel->mask' however in the case of smear its not +/** + * \note mask is used to modify the alpha here, this is not correct since it allows + * accumulation of color greater than 'projPixel->mask' however in the case of smear its not * really that important to be correct as it is with clone and painting */ static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float mask, @@ -4219,7 +4286,7 @@ static void *do_projectpaint_thread(void *ph_v) if (dist_sq <= brush_radius_sq) { dist = sqrtf(dist_sq); - falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, brush_radius); + falloff = BKE_brush_curve_strength(ps->brush, dist, brush_radius); if (falloff > 0.0f) { float texrgb[3]; @@ -4454,7 +4521,35 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po touch_any = 1; } } + + /* calculate pivot for rotation around seletion if needed */ + if (U.uiflag & USER_ORBIT_SELECTION) { + float w[3]; + int side, index; + + index = project_paint_PickFace(ps, pos, w, &side); + + if (index != -1) { + MFace *mf; + float world[3]; + UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings; + mf = ps->dm_mface + index; + + if (side == 0) { + interp_v3_v3v3v3(world, ps->dm_mvert[(*(&mf->v1))].co, ps->dm_mvert[(*(&mf->v2))].co, ps->dm_mvert[(*(&mf->v3))].co, w); + } + else { + interp_v3_v3v3v3(world, ps->dm_mvert[(*(&mf->v1))].co, ps->dm_mvert[(*(&mf->v3))].co, ps->dm_mvert[(*(&mf->v4))].co, w); + } + + ups->average_stroke_counter++; + mul_m4_v3(ps->ob->obmat, world); + add_v3_v3(ups->average_stroke_accum, world); + ups->last_stroke_valid = true; + } + } + return touch_any; } @@ -4626,7 +4721,7 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m paint_brush_init_tex(ps->brush); - ps->source = PROJ_SRC_VIEW; + ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW; if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) { MEM_freeN(ps); @@ -4649,10 +4744,6 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m paint_proj_begin_clone(ps, mouse); - /* special full screen draw mode for fill tool */ - if (ps->tool == PAINT_TOOL_FILL) - ps->source = PROJ_SRC_VIEW_FILL; - return ps; } @@ -5130,6 +5221,8 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) DAG_id_tag_update(&ma->id, 0); ED_area_tag_redraw(CTX_wm_area(C)); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + return true; } } @@ -5288,6 +5381,8 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op)) if (synch_selection) scene->toolsettings->uv_flag |= UV_SYNC_SELECTION; + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + DAG_id_tag_update(ob->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 9c4701d0a01..bb875d2ef00 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -207,6 +207,7 @@ static bool paint_brush_update(bContext *C, UnifiedPaintSettings *ups = stroke->ups; bool location_sampled = false; bool location_success = false; + bool do_random = false; /* XXX: Use pressure value from first brush step for brushes which don't * support strokes (grab, thumb). They depends on initial state and * brush coord/pressure/etc. @@ -256,17 +257,13 @@ static bool paint_brush_update(bContext *C, if (paint_supports_dynamic_tex_coords(brush, mode)) { if (((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) || (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) || - (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) && - !(brush->flag & BRUSH_RAKE)) + (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM))) { - if (brush->flag & BRUSH_RANDOM_ROTATION) - ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand(); - else - ups->brush_rotation = 0.0f; + do_random = true; } if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) - BKE_brush_randomize_texture_coordinates(ups, false); + BKE_brush_randomize_texture_coords(ups, false); else { copy_v2_v2(ups->tex_mouse, mouse); } @@ -274,7 +271,7 @@ static bool paint_brush_update(bContext *C, /* take care of mask texture, if any */ if (brush->mask_mtex.tex) { if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) - BKE_brush_randomize_texture_coordinates(ups, true); + BKE_brush_randomize_texture_coords(ups, true); else { copy_v2_v2(ups->mask_tex_mouse, mouse); } @@ -291,7 +288,7 @@ static bool paint_brush_update(bContext *C, ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy); - ups->brush_rotation = atan2f(dx, dy) + M_PI; + ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + M_PI; if (brush->flag & BRUSH_EDGE_TO_EDGE) { halfway[0] = dx * 0.5f + stroke->initial_mouse[0]; @@ -328,13 +325,27 @@ static bool paint_brush_update(bContext *C, ups->pixel_radius /= stroke->zoom_2d; ups->draw_anchored = true; } - else if (brush->flag & BRUSH_RAKE) { + else { /* here we are using the initial mouse coordinate because we do not want the rake * result to depend on jittering */ - if (!stroke->brush_init) + if (!stroke->brush_init) { copy_v2_v2(ups->last_rake, mouse_init); - else - paint_calculate_rake_rotation(ups, mouse_init); + } + else { + paint_calculate_rake_rotation(ups, brush, mouse_init); + } + } + + if (do_random) { + if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) { + ups->brush_rotation += -brush->mtex.random_angle / 2.0f + + brush->mtex.random_angle * BLI_frand(); + } + + if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) { + ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f + + brush->mask_mtex.random_angle * BLI_frand(); + } } if (!location_sampled) { @@ -651,6 +662,10 @@ PaintStroke *paint_stroke_new(bContext *C, /* initialize here */ ups->overlap_factor = 1.0; ups->stroke_active = true; + + zero_v3(ups->average_stroke_accum); + ups->average_stroke_counter = 0; + /* initialize here to avoid initialization conflict with threaded strokes */ curvemapping_initialize(br->curve); @@ -675,9 +690,12 @@ static void stroke_done(struct bContext *C, struct wmOperator *op) ups->stroke_active = false; /* reset rotation here to avoid doing so in cursor display */ - if (!(stroke->brush->flag & BRUSH_RAKE)) + if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) ups->brush_rotation = 0.0f; + if (!(stroke->brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) + ups->brush_rotation_sec = 0.0f; + if (stroke->stroke_started) { if (stroke->redraw) stroke->redraw(C, stroke, true); @@ -1064,10 +1082,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) else if ((br->flag & BRUSH_LINE) && stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) { - if (br->flag & BRUSH_RAKE) { + if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position); - paint_calculate_rake_rotation(stroke->ups, sample_average.mouse); } + paint_calculate_rake_rotation(stroke->ups, br, sample_average.mouse); } else if (first_modal || /* regular dabs */ diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index d41af26a4d1..9c2c13f9a2d 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -48,15 +48,13 @@ #include "BLF_translation.h" -#include "BKE_scene.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_DerivedMesh.h" -#include "BKE_material.h" #include "BKE_image.h" +#include "BKE_material.h" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_image.h" #include "RNA_access.h" #include "RNA_define.h" @@ -66,16 +64,12 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" -#include "RE_shader_ext.h" #include "RE_render_ext.h" #include "ED_view3d.h" #include "ED_screen.h" -#include "ED_uvedit.h" - -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "BLI_sys_types.h" #include "ED_mesh.h" /* for face mask functions */ @@ -397,12 +391,12 @@ static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int * } -static Image *imapaint_face_image(DerivedMesh *dm, int face_index) +static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index) { Image *ima; - MFace *mf = dm->getTessFaceArray(dm) + face_index; - Material *ma = dm->mat[mf->mat_nr]; - ima = ma ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; + MPoly *mp = me->mpoly + face_index; + Material *ma = give_current_material(ob, mp->mat_nr + 1);; + ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; return ima; } @@ -456,16 +450,15 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); if (ob) { + Mesh *me = (Mesh *)ob->data; DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); ViewContext vc; const int mval[2] = {x, y}; unsigned int faceindex; - unsigned int totface = dm->getNumTessFaces(dm); + unsigned int totface = me->totface; MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); - DM_update_materials(dm, ob); - if (dm_mtface) { view3d_set_viewcontext(C, &vc); @@ -475,7 +468,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr Image *image; if (use_material) - image = imapaint_face_image(dm, faceindex); + image = imapaint_face_image(ob, me, faceindex); else image = imapaint->canvas; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 75bef040d2e..7324cebbf49 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -66,8 +66,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "GPU_buffers.h" - #include "ED_armature.h" #include "ED_object.h" #include "ED_mesh.h" @@ -387,7 +385,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) } /* curdef should never be NULL unless this is - * a lamp and ED_vgroup_add_name fails */ + * a lamp and BKE_object_defgroup_add_name fails */ return mirrdef; } @@ -937,7 +935,7 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co else { factor = 1.0f; } - return factor * BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); + return factor * BKE_brush_curve_strength(brush, dist, brush_size_pressure); } } if (rgba) @@ -2074,7 +2072,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) paint_cursor_start(C, weight_paint_poll); - BKE_paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); + BKE_paint_init(&scene->toolsettings->unified_paint_settings, &wp->paint, PAINT_CURSOR_WEIGHT_PAINT); /* weight paint specific */ ED_mesh_mirror_spatial_table(ob, NULL, NULL, 's'); @@ -2159,7 +2157,7 @@ static bool wpaint_ensure_data(bContext *C, wmOperator *op) /* if nothing was added yet, we make dverts and a vertex deform group */ if (!me->dvert) { - ED_vgroup_data_create(&me->id); + BKE_object_defgroup_data_create(&me->id); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); } @@ -2174,7 +2172,7 @@ static bool wpaint_ensure_data(bContext *C, wmOperator *op) if (pchan) { bDeformGroup *dg = defgroup_find_name(ob, pchan->name); if (dg == NULL) { - dg = ED_vgroup_add_name(ob, pchan->name); /* sets actdef */ + dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */ } else { int actdef = 1 + BLI_findindex(&ob->defbase, dg); @@ -2186,7 +2184,7 @@ static bool wpaint_ensure_data(bContext *C, wmOperator *op) } } if (BLI_listbase_is_empty(&ob->defbase)) { - ED_vgroup_add(ob); + BKE_object_defgroup_add(ob); } /* ensure we don't try paint onto an invalid group */ @@ -2236,9 +2234,9 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN /* set up auto-normalize, and generate map for detecting which * vgroups affect deform bones */ wpd->defbase_tot = BLI_listbase_count(&ob->defbase); - wpd->lock_flags = BKE_objdef_lock_flags_get(ob, wpd->defbase_tot); + wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot); if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) { - wpd->vgroup_validmap = BKE_objdef_validmap_get(ob, wpd->defbase_tot); + wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot); } /* painting on subsurfs should give correct points too, this returns me->totvert amount */ @@ -2318,7 +2316,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ wpi.defbase_tot = wpd->defbase_tot; - wpi.defbase_sel = BKE_objdef_selected_get(ob, wpi.defbase_tot, &wpi.defbase_tot_sel); + wpi.defbase_sel = BKE_object_defgroup_selected_get(ob, wpi.defbase_tot, &wpi.defbase_tot_sel); if (wpi.defbase_tot_sel == 0 && ob->actdef > 0) { wpi.defbase_tot_sel = 1; } @@ -2682,7 +2680,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) paint_cursor_start(C, vertex_paint_poll); - BKE_paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT); + BKE_paint_init(&scene->toolsettings->unified_paint_settings, &vp->paint, PAINT_CURSOR_VERTEX_PAINT); } /* update modifier stack for mapping requirements */ @@ -3024,7 +3022,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P * avoid this if we can! */ DAG_id_tag_update(ob->data, 0); } - else if (!GPU_buffer_legacy(ob->derivedFinal)) { + else { /* If using new VBO drawing, mark mcol as dirty to force colors gpu buffer refresh! */ ob->derivedFinal->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW; } @@ -3217,7 +3215,7 @@ static void gradientVert_update(DMGradient_userData *grad_data, int index) /* no need to clamp 'alpha' yet */ /* adjust weight */ - alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f); + alpha = BKE_brush_curve_strength(grad_data->brush, alpha, 1.0f); if (alpha != 0.0f) { MDeformVert *dv = &me->dvert[index]; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 1e4931ac792..dbb29997102 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -40,7 +40,6 @@ #include "BLI_dial.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" -#include "BLI_threads.h" #include "BLF_translation.h" @@ -56,7 +55,6 @@ #include "BKE_brush.h" #include "BKE_ccg.h" #include "BKE_context.h" -#include "BKE_crazyspace.h" #include "BKE_depsgraph.h" #include "BKE_image.h" #include "BKE_key.h" @@ -85,7 +83,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RE_render_ext.h" #include "GPU_buffers.h" @@ -106,6 +103,8 @@ #if defined(__APPLE__) && defined _OPENMP #include <sys/sysctl.h> +#include "BLI_threads.h" + /* Query how many cores not counting HT aka physical cores we've got. */ static int system_physical_thread_count(void) { @@ -116,33 +115,6 @@ static int system_physical_thread_count(void) } #endif /* __APPLE__ */ -void ED_sculpt_stroke_get_average(Object *ob, float stroke[3]) -{ - if (ob->sculpt->last_stroke_valid && ob->sculpt->average_stroke_counter > 0) { - float fac = 1.0f / ob->sculpt->average_stroke_counter; - mul_v3_v3fl(stroke, ob->sculpt->average_stroke_accum, fac); - } - else { - copy_v3_v3(stroke, ob->obmat[3]); - } -} - -bool ED_sculpt_minmax(bContext *C, float min[3], float max[3]) -{ - Object *ob = CTX_data_active_object(C); - - if (ob && ob->sculpt && ob->sculpt->last_stroke_valid) { - copy_v3_v3(min, ob->sculpt->last_stroke); - copy_v3_v3(max, ob->sculpt->last_stroke); - - return 1; - } - else { - return 0; - } -} - - /* Check if there are any active modifiers in stack (used for flushing updates at enter/exit sculpt mode) */ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob) { @@ -2957,7 +2929,7 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) /* Note: we do the topology update before any brush actions to avoid * issues with the proxies. The size of the proxy can't change, so * topology must be updated first. */ -static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush) +static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *UNUSED(ups)) { SculptSession *ss = ob->sculpt; SculptSearchSphereData data; @@ -3018,13 +2990,10 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush) /* update average stroke position */ copy_v3_v3(location, ss->cache->true_location); mul_m4_v3(ob->obmat, location); - - add_v3_v3(ob->sculpt->average_stroke_accum, location); - ob->sculpt->average_stroke_counter++; } } -static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) +static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups) { SculptSession *ss = ob->sculpt; SculptSearchSphereData data; @@ -3138,8 +3107,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) copy_v3_v3(location, ss->cache->true_location); mul_m4_v3(ob->obmat, location); - add_v3_v3(ob->sculpt->average_stroke_accum, location); - ob->sculpt->average_stroke_counter++; + add_v3_v3(ups->average_stroke_accum, location); + ups->average_stroke_counter++; + /* update last stroke position */ + ups->last_stroke_valid = true; } } @@ -3348,9 +3319,9 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, } } -typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush); +typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups); -static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, +static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action, const char symm, const int axis, const float feather) @@ -3362,7 +3333,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X']; ss->cache->radial_symmetry_pass = i; calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather); - action(sd, ob, brush); + action(sd, ob, brush, ups); } } @@ -3400,11 +3371,11 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, cache->radial_symmetry_pass = 0; calc_brushdata_symm(sd, cache, i, 0, 0, feather); - action(sd, ob, brush); + action(sd, ob, brush, ups); - do_radial_symmetry(sd, ob, brush, action, i, 'X', feather); - do_radial_symmetry(sd, ob, brush, action, i, 'Y', feather); - do_radial_symmetry(sd, ob, brush, action, i, 'Z', feather); + do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather); + do_radial_symmetry(sd, ob, brush, ups, action, i, 'Y', feather); + do_radial_symmetry(sd, ob, brush, ups, action, i, 'Z', feather); } } } @@ -4156,9 +4127,6 @@ static bool sculpt_brush_stroke_init(bContext *C, wmOperator *op) is_smooth = sculpt_any_smooth_mode(brush, NULL, mode); BKE_sculpt_update_mesh_elements(scene, sd, ob, is_smooth, need_mask); - zero_v3(ob->sculpt->average_stroke_accum); - ob->sculpt->average_stroke_counter = 0; - return 1; } @@ -4365,10 +4333,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str } } - /* update last stroke position */ - ob->sculpt->last_stroke_valid = 1; - ED_sculpt_stroke_get_average(ob, ob->sculpt->last_stroke); - sculpt_cache_free(ss->cache); ss->cache = NULL; @@ -4985,7 +4949,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) "Object has negative scale, sculpting may be unpredictable"); } - BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); + BKE_paint_init(&ts->unified_paint_settings, &ts->sculpt->paint, PAINT_CURSOR_SCULPT); paint_cursor_start(C, sculpt_poll_view3d); } diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index d90eaafa379..23bc4a483d3 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -60,7 +60,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "paint_intern.h" #include "uvedit_intern.h" @@ -237,7 +236,7 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings settings->uvsculpt->paint.flags |= PAINT_SHOW_BRUSH; } - BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT); + BKE_paint_init(&settings->unified_paint_settings, &settings->uvsculpt->paint, PAINT_CURSOR_SCULPT); settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, brush_drawcursor_uvsculpt, NULL); @@ -558,15 +557,15 @@ static int uv_element_offset_from_face_get(UvElementMap *map, BMFace *efa, BMLoo static unsigned int uv_edge_hash(const void *key) { - UvEdge *edge = (UvEdge *)key; + const UvEdge *edge = key; return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1)); } static bool uv_edge_compare(const void *a, const void *b) { - UvEdge *edge1 = (UvEdge *)a; - UvEdge *edge2 = (UvEdge *)b; + const UvEdge *edge1 = a; + const UvEdge *edge2 = b; if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { return 0; diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 7ede6c95b9d..d9f4b97fe09 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -72,7 +72,6 @@ #include "ED_sound.h" #include "ED_util.h" -#include "sound_intern.h" /******************** open sound operator ********************/ @@ -143,7 +142,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) RNA_property_update(C, &pprop->ptr, pprop->prop); } - if (op->customdata) MEM_freeN(op->customdata); + MEM_freeN(op->customdata); return OPERATOR_FINISHED; } @@ -184,7 +183,7 @@ static void SOUND_OT_open(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory"); RNA_def_boolean(ot->srna, "mono", false, "Mono", "Mixdown the sound to mono"); @@ -206,7 +205,7 @@ static void SOUND_OT_open_mono(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory"); RNA_def_boolean(ot->srna, "mono", true, "Mono", "Mixdown the sound to mono"); @@ -651,7 +650,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE, FILE_SPECIAL, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); #ifdef WITH_AUDASPACE RNA_def_int(ot->srna, "accuracy", 1024, 1, 16777216, "Accuracy", "Sample accuracy, important for animation data (the lower the value, the more accurate)", 1, 16777216); diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index e55ce3ea8eb..bc9c578b558 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -545,7 +545,7 @@ static short copy_action_keys(bAnimContext *ac) static short paste_action_keys(bAnimContext *ac, - const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip) { ListBase anim_data = {NULL, NULL}; int filter, ok = 0; @@ -562,7 +562,7 @@ static short paste_action_keys(bAnimContext *ac, ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* paste keyframes */ - ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode); + ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip); /* clean up */ ANIM_animdata_freelist(&anim_data); @@ -622,6 +622,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op) const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset"); const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge"); + const bool flipped = RNA_boolean_get(op->ptr, "flipped"); /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -638,7 +639,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op) } else { /* non-zero return means an error occurred while trying to paste */ - if (paste_action_keys(&ac, offset_mode, merge_mode)) { + if (paste_action_keys(&ac, offset_mode, merge_mode, flipped)) { return OPERATOR_CANCELLED; } } @@ -651,6 +652,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op) void ACTION_OT_paste(wmOperatorType *ot) { + PropertyRNA *prop; /* identifiers */ ot->name = "Paste Keyframes"; ot->idname = "ACTION_OT_paste"; @@ -667,6 +669,8 @@ void ACTION_OT_paste(wmOperatorType *ot) /* props */ RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys"); RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing"); + prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ******************** Insert Keyframes Operator ************************* */ @@ -965,8 +969,11 @@ static int actkeys_clean_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) + + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); return OPERATOR_PASS_THROUGH; + } /* get cleaning threshold */ thresh = RNA_float_get(op->ptr, "threshold"); @@ -1025,15 +1032,18 @@ static void sample_action_keys(bAnimContext *ac) /* ------------------- */ -static int actkeys_sample_exec(bContext *C, wmOperator *UNUSED(op)) +static int actkeys_sample_exec(bContext *C, wmOperator *op) { bAnimContext ac; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) + + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); return OPERATOR_PASS_THROUGH; + } /* sample keyframes */ sample_action_keys(&ac); @@ -1138,8 +1148,11 @@ static int actkeys_expo_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) + + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); return OPERATOR_PASS_THROUGH; + } /* get handle setting mode */ mode = RNA_enum_get(op->ptr, "type"); @@ -1209,8 +1222,11 @@ static int actkeys_ipo_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) + + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); return OPERATOR_PASS_THROUGH; + } /* get handle setting mode */ mode = RNA_enum_get(op->ptr, "type"); @@ -1288,8 +1304,11 @@ static int actkeys_handletype_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) + + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + BKE_report(op->reports, RPT_ERROR, "Not implemented"); return OPERATOR_PASS_THROUGH; + } /* get handle setting mode */ mode = RNA_enum_get(op->ptr, "type"); @@ -1324,7 +1343,7 @@ void ACTION_OT_handle_type(wmOperatorType *ot) /* ******************** Set Keyframe-Type Operator *********************** */ -/* this function is responsible for setting interpolation mode for keyframes */ +/* this function is responsible for setting keyframe type for keyframes */ static void setkeytype_action_keys(bAnimContext *ac, short mode) { ListBase anim_data = {NULL, NULL}; @@ -1349,6 +1368,29 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode) ANIM_animdata_freelist(&anim_data); } +/* this function is responsible for setting the keyframe type for Grease Pencil frames */ +static void setkeytype_gpencil_keys(bAnimContext *ac, short mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop through each layer */ + for (ale = anim_data.first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + ED_gplayer_frames_keytype_set(ale->data, mode); + ale->update |= ANIM_UPDATE_DEPS; + } + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + /* ------------------- */ static int actkeys_keytype_exec(bContext *C, wmOperator *op) @@ -1359,14 +1401,22 @@ static int actkeys_keytype_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) + + if (ac.datatype == ANIMCONT_MASK) { + BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks"); return OPERATOR_PASS_THROUGH; + } /* get handle setting mode */ mode = RNA_enum_get(op->ptr, "type"); /* set handle type */ - setkeytype_action_keys(&ac, mode); + if (ac.datatype == ANIMCONT_GPENCIL) { + setkeytype_gpencil_keys(&ac, mode); + } + else { + setkeytype_action_keys(&ac, mode); + } /* set notifier that keyframe properties have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index b99419dec20..0fbacefa8e3 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -35,7 +35,6 @@ #include "DNA_space_types.h" -#include "BLI_utildefines.h" #include "ED_anim_api.h" #include "ED_markers.h" @@ -44,7 +43,6 @@ #include "action_intern.h" #include "RNA_access.h" -#include "RNA_define.h" #include "WM_api.h" #include "WM_types.h" @@ -207,9 +205,13 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) /* copy/paste */ WM_keymap_add_item(keymap, "ACTION_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); + kmi = WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "flipped", true); #ifdef __APPLE__ WM_keymap_add_item(keymap, "ACTION_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0); WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0); + kmi = WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_OSKEY | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "flipped", true); #endif /* auto-set range */ diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 77c6cce6cda..01f0d1ae54f 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -32,7 +32,6 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_windowmanager_types.h" @@ -61,7 +60,6 @@ #include "ED_space_api.h" #include "ED_sound.h" #include "ED_uvedit.h" -#include "ED_view3d.h" #include "ED_mball.h" #include "ED_logic.h" #include "ED_clip.h" @@ -155,6 +153,7 @@ void ED_spacemacros_init(void) ED_operatormacros_mask(); ED_operatormacros_sequencer(); ED_operatormacros_paint(); + ED_operatormacros_gpencil(); /* register dropboxes (can use macros) */ spacetypes = BKE_spacetypes_list(); @@ -318,7 +317,3 @@ void ED_spacetype_xxx(void) } /* ****************************** end template *********************** */ - - - - diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 3b939702c58..a67af289f59 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -61,7 +61,9 @@ #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_scene.h" -#include "BKE_freestyle.h" +#ifdef WITH_FREESTYLE +# include "BKE_freestyle.h" +#endif #include "RNA_access.h" @@ -468,7 +470,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts) } else { /* set one user as active based on active index */ - if (ct->index == BLI_listbase_count_ex(&ct->users, ct->index)) + if (ct->index == BLI_listbase_count_ex(&ct->users, ct->index + 1)) ct->index = 0; ct->user = BLI_findlink(&ct->users, ct->index); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 4d62f528915..a778df4b783 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -28,7 +28,6 @@ * \ingroup spbuttons */ - #include <string.h> #include <stdio.h> @@ -46,10 +45,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "UI_resources.h" -#include "UI_view2d.h" - - #include "buttons_intern.h" /* own include */ /* ******************** default callbacks for buttons space ***************** */ diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index fe36d9a9685..f8299a8d335 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -69,26 +69,9 @@ /* Panels */ -static int clip_grease_pencil_panel_poll(const bContext *C, PanelType *UNUSED(pt)) +void ED_clip_buttons_register(ARegionType *UNUSED(art)) { - SpaceClip *sc = CTX_wm_space_clip(C); - return sc->view == SC_VIEW_CLIP; -} - -void ED_clip_buttons_register(ARegionType *art) -{ - PanelType *pt; - - pt = MEM_callocN(sizeof(PanelType), "spacetype clip panel gpencil"); - strcpy(pt->idname, "CLIP_PT_gpencil"); - strcpy(pt->label, N_("Grease Pencil")); - strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw_header = ED_gpencil_panel_standard_header; - pt->draw = ED_gpencil_panel_standard; - pt->flag |= PNL_DEFAULT_CLOSED; - pt->poll = clip_grease_pencil_panel_poll; - BLI_addtail(&art->paneltypes, pt); } /********************* MovieClip Template ************************/ diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c index fe5b332aeb1..4bf4c1e7baa 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_draw.c +++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c @@ -30,7 +30,6 @@ */ #include "DNA_movieclip_types.h" -#include "DNA_object_types.h" /* SELECT */ #include "DNA_scene_types.h" #include "BLI_utildefines.h" diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c index 7ae5eda7139..d2f2fdd0b46 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_ops.c +++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c @@ -29,7 +29,6 @@ * \ingroup spclip */ -#include "DNA_object_types.h" /* SELECT */ #include "DNA_scene_types.h" #include "BLI_utildefines.h" diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index a35251e71ef..6c55d8d034e 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -63,7 +63,6 @@ #include "UI_resources.h" #include "UI_view2d.h" -#include "RNA_access.h" #include "BLF_api.h" @@ -1123,7 +1122,7 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane bool draw_outline, int width, int height) { bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0; - bool is_selected_track = plane_track->flag & SELECT; + bool is_selected_track = (plane_track->flag & SELECT) != 0; bool draw_plane_quad = plane_track->image == NULL || plane_track->image_opacity == 0.0f; float px[2]; diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index f25f035db32..89693a403fe 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -57,7 +57,6 @@ #include "BKE_tracking.h" #include "BKE_library.h" -#include "GPU_extensions.h" #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c index 723c8bd144a..2c3b8acf672 100644 --- a/source/blender/editors/space_clip/clip_graph_draw.c +++ b/source/blender/editors/space_clip/clip_graph_draw.c @@ -50,7 +50,6 @@ #include "UI_resources.h" #include "UI_view2d.h" -#include "BLF_api.h" #include "clip_intern.h" // own include diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index d1e2c770ade..2a2f15c94bb 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -45,8 +45,6 @@ #include "ED_screen.h" #include "ED_clip.h" -#include "UI_interface.h" - #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 787a7fca273..e3d45a297a7 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -299,7 +299,7 @@ void CLIP_OT_open(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY); } @@ -1307,7 +1307,14 @@ static void proxy_endjob(void *pjv) if (pj->index_context) IMB_anim_index_rebuild_finish(pj->index_context, pj->stop); - BKE_movieclip_reload(pj->clip); + if (pj->clip->source == MCLIP_SRC_MOVIE) { + /* Timecode might have changed, so do a full reload to deal with this. */ + BKE_movieclip_reload(pj->clip); + } + else { + /* For image sequences we'll preserve original cache. */ + BKE_movieclip_clear_proxy_cache(pj->clip); + } WM_main_add_notifier(NC_MOVIECLIP | ND_DISPLAY, pj->clip); } diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index a79ac1f7b82..5f919c9b51d 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -30,12 +30,10 @@ */ #include "DNA_scene_types.h" -#include "DNA_object_types.h" /* SELECT */ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -54,8 +52,6 @@ #include "ED_screen.h" #include "ED_clip.h" -#include "RNA_access.h" -#include "RNA_define.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index bf9b55ba3dd..fc2c0d3d45c 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -420,6 +420,9 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) clip_scopes_check_gpencil_change(sa); ED_area_tag_redraw(sa); } + else if (wmn->data & ND_GPENCIL_EDITMODE) { + ED_area_tag_redraw(sa); + } break; } } @@ -1245,6 +1248,8 @@ static void clip_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR case NC_GPENCIL: if (wmn->action == NA_EDITED) ED_region_tag_redraw(ar); + else if (wmn->data & ND_GPENCIL_EDITMODE) + ED_region_tag_redraw(ar); break; } } @@ -1495,7 +1500,7 @@ static void clip_properties_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s /* context changes */ switch (wmn->category) { case NC_GPENCIL: - if (wmn->data == ND_DATA) + if (ELEM(wmn->data, ND_DATA, ND_GPENCIL_EDITMODE)) ED_region_tag_redraw(ar); break; case NC_BRUSH: diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index bdb57cca81e..742e58d80dd 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -41,7 +41,6 @@ #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_listbase.h" -#include "BLI_rect.h" #include "BLI_blenlib.h" #include "BKE_main.h" @@ -65,7 +64,6 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "UI_interface.h" #include "RNA_access.h" #include "RNA_define.h" @@ -74,7 +72,6 @@ #include "PIL_time.h" -#include "UI_view2d.h" #include "clip_intern.h" // own include diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index 860d9dc6b3c..bc6ac507f03 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -36,7 +36,6 @@ #include "BLI_utildefines.h" #include "BLI_math.h" -#include "BLI_listbase.h" #include "BLI_rect.h" #include "BLI_lasso.h" @@ -49,16 +48,9 @@ #include "ED_screen.h" #include "ED_clip.h" -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" - -#include "UI_interface.h" - #include "RNA_access.h" #include "RNA_define.h" -#include "PIL_time.h" - #include "UI_view2d.h" #include "clip_intern.h" // own include diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 635d5ea07fd..d206ce4699e 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -30,7 +30,6 @@ #include <sys/stat.h> #include <limits.h> -#include "BLF_api.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 6f63f315f74..3f3c14d3a7d 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -47,7 +47,6 @@ #include "BKE_global.h" #include "BKE_main.h" -#include "BLF_api.h" #include "BLF_translation.h" #include "IMB_imbuf_types.h" @@ -67,7 +66,6 @@ #include "WM_types.h" -#include "fsmenu.h" #include "filelist.h" #include "file_intern.h" // own include @@ -113,6 +111,7 @@ void file_draw_buttons(const bContext *C, ARegion *ar) SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); ARegion *artmp; + const bool is_browse_only = (sfile->op == NULL); /* Initialize UI block. */ BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar); @@ -126,15 +125,22 @@ void file_draw_buttons(const bContext *C, ARegion *ar) available_w -= chan_offs; } } - + /* Is there enough space for the execute / cancel buttons? */ - loadbutton = UI_fontstyle_string_width(params->title) + btn_margin; - CLAMP_MIN(loadbutton, btn_minw); - if (available_w <= loadbutton + separator + input_minw || params->title[0] == 0) { + + if (is_browse_only) { loadbutton = 0; } else { + loadbutton = UI_fontstyle_string_width(params->title) + btn_margin; + CLAMP_MIN(loadbutton, btn_minw); + if (available_w <= loadbutton + separator + input_minw) { + loadbutton = 0; + } + } + + if (loadbutton) { line1_w -= (loadbutton + separator); line2_w = line1_w; } @@ -147,7 +153,7 @@ void file_draw_buttons(const bContext *C, ARegion *ar) else { line2_w -= (fnumbuttons + separator); } - + /* Text input fields for directory and file. */ if (available_w > 0) { int overwrite_alert = file_draw_check_exists(sfile); @@ -235,33 +241,33 @@ static int get_file_icon(struct direntry *file) if (strcmp(file->relname, "..") == 0) { return ICON_FILE_PARENT; } - if (file->flags & APPLICATIONBUNDLE) { + if (file->flags & FILE_TYPE_APPLICATIONBUNDLE) { return ICON_UGLYPACKAGE; } - if (file->flags & BLENDERFILE) { + if (file->flags & FILE_TYPE_BLENDER) { return ICON_FILE_BLEND; } return ICON_FILE_FOLDER; } - else if (file->flags & BLENDERFILE) + else if (file->flags & FILE_TYPE_BLENDER) return ICON_FILE_BLEND; - else if (file->flags & BLENDERFILE_BACKUP) + else if (file->flags & FILE_TYPE_BLENDER_BACKUP) return ICON_FILE_BACKUP; - else if (file->flags & IMAGEFILE) + else if (file->flags & FILE_TYPE_IMAGE) return ICON_FILE_IMAGE; - else if (file->flags & MOVIEFILE) + else if (file->flags & FILE_TYPE_MOVIE) return ICON_FILE_MOVIE; - else if (file->flags & PYSCRIPTFILE) + else if (file->flags & FILE_TYPE_PYSCRIPT) return ICON_FILE_SCRIPT; - else if (file->flags & SOUNDFILE) + else if (file->flags & FILE_TYPE_SOUND) return ICON_FILE_SOUND; - else if (file->flags & FTFONTFILE) + else if (file->flags & FILE_TYPE_FTFONT) return ICON_FILE_FONT; - else if (file->flags & BTXFILE) + else if (file->flags & FILE_TYPE_BTX) return ICON_FILE_BLANK; - else if (file->flags & COLLADAFILE) + else if (file->flags & FILE_TYPE_COLLADA) return ICON_FILE_BLANK; - else if (file->flags & TEXTFILE) + else if (file->flags & FILE_TYPE_TEXT) return ICON_FILE_TEXT; else return ICON_FILE_BLANK; @@ -516,10 +522,15 @@ void file_draw_list(const bContext *C, ARegion *ar) UI_ThemeColor4(TH_TEXT); - if (!(file->selflag & EDITING_FILE)) { - if ((params->active_file == i) || (file->selflag & HILITED_FILE) || (file->selflag & SELECTED_FILE)) { - int colorid = (file->selflag & SELECTED_FILE) ? TH_HILITE : TH_BACK; - int shade = (params->active_file == i) || (file->selflag & HILITED_FILE) ? 20 : 0; + if (!(file->selflag & FILE_SEL_EDITING)) { + if ((params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) || (file->selflag & FILE_SEL_SELECTED)) { + int colorid = (file->selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK; + int shade = (params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 20 : 0; + + /* readonly files (".." and ".") must not be drawn as selected - set color back to normal */ + if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) { + colorid = TH_BACK; + } draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade); } } @@ -536,7 +547,7 @@ void file_draw_list(const bContext *C, ARegion *ar) is_icon = 1; } - file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & IMAGEFILE), do_drag); + file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & FILE_TYPE_IMAGE), do_drag); } else { file_draw_icon(block, file->path, sx, sy - (UI_UNIT_Y / 6), get_file_icon(file), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag); @@ -545,7 +556,7 @@ void file_draw_list(const bContext *C, ARegion *ar) UI_ThemeColor4(TH_TEXT); - if (file->selflag & EDITING_FILE) { + if (file->selflag & FILE_SEL_EDITING) { uiBut *but; short width; @@ -568,11 +579,11 @@ void file_draw_list(const bContext *C, ARegion *ar) UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */ UI_but_flag_disable(but, UI_BUT_UNDO); if (false == UI_but_active_only(C, ar, block, but)) { - file->selflag &= ~EDITING_FILE; + file->selflag &= ~FILE_SEL_EDITING; } } - if (!(file->selflag & EDITING_FILE)) { + if (!(file->selflag & FILE_SEL_EDITING)) { int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : sy; file_draw_string(sx + 1, tpos, file->relname, (float)textwidth, textheight, align); } diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 13beba3fff8..3a579820106 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -34,6 +34,7 @@ #include "BLO_readfile.h" +#include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_global.h" @@ -219,7 +220,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL; /* flag the files as selected in the filelist */ - filelist_select(sfile->files, &sel, select, SELECTED_FILE, check_type); + filelist_select(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type); /* Don't act on multiple selected files */ if (sel.first != sel.last) select = 0; @@ -258,9 +259,25 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent * sel = file_selection_get(C, &rect, 0); if ( (sel.first != params->sel_first) || (sel.last != params->sel_last) ) { - file_deselect_all(sfile, HILITED_FILE); - filelist_select(sfile->files, &sel, FILE_SEL_ADD, HILITED_FILE, CHECK_ALL); + int idx; + + file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); + filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + + /* dont highlight readonly file (".." or ".") on border select */ + for (idx = sel.last; idx >= 0; idx--) { + struct direntry *file = filelist_file(sfile->files, idx); + + if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) { + file->selflag &= ~FILE_SEL_HIGHLIGHTED; + } + + /* active_file gets highlighted as well - make sure it is no readonly file */ + if (sel.last == idx) { + params->active_file = idx; + } + } } params->sel_first = sel.first; params->sel_last = sel.last; @@ -268,7 +285,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent * else { params->active_file = -1; params->sel_first = params->sel_last = -1; - file_deselect_all(sfile, HILITED_FILE); + file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } @@ -288,7 +305,7 @@ static int file_border_select_exec(bContext *C, wmOperator *op) if (!extend) { SpaceFile *sfile = CTX_wm_space_file(C); - file_deselect_all(sfile, SELECTED_FILE); + file_deselect_all(sfile, FILE_SEL_SELECTED); } BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect); @@ -340,8 +357,20 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin)) return OPERATOR_CANCELLED; - /* single select, deselect all selected first */ - if (!extend) file_deselect_all(sfile, SELECTED_FILE); + if (sfile && sfile->params) { + int idx = sfile->params->active_file; + + if (idx >= 0) { + struct direntry *file = filelist_file(sfile->files, idx); + if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) { + /* skip - If a readonly file (".." or ".") is selected, skip deselect all! */ + } + else { + /* single select, deselect all selected first */ + if (!extend) file_deselect_all(sfile, FILE_SEL_SELECTED); + } + } + } ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen); if (FILE_SELECT_DIR == ret) @@ -398,11 +427,11 @@ static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op)) } /* select all only if previously no file was selected */ if (is_selected) { - filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, SELECTED_FILE, CHECK_ALL); + filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); } else { const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES; - filelist_select(sfile->files, &sel, FILE_SEL_ADD, SELECTED_FILE, check_type); + filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type); } ED_area_tag_redraw(sa); return OPERATOR_FINISHED; @@ -472,7 +501,7 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op)) char name[FILE_MAX]; fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, FS_INSERT_SAVE); - BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(fsmenu, name); } @@ -504,7 +533,7 @@ static int bookmark_delete_exec(bContext *C, wmOperator *op) char name[FILE_MAX]; fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index); - BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(fsmenu, name); ED_area_tag_redraw(sa); } @@ -540,7 +569,7 @@ static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op)) while (fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) { fsmenu_remove_entry(fsmenu, FS_CATEGORY_RECENT, 0); } - BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(fsmenu, name); ED_area_tag_redraw(sa); @@ -821,7 +850,7 @@ int file_exec(bContext *C, wmOperator *exec_op) fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, FS_INSERT_SAVE | FS_INSERT_FIRST); } - BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + BLI_make_file_string(G.main->name, filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(fsmenu_get(), filepath); WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC); @@ -1197,7 +1226,7 @@ static void file_expand_directory(bContext *C) else if (sfile->params->dir[0] == '~') { char tmpstr[sizeof(sfile->params->dir) - 1]; BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr)); - BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BLI_getDefaultDocumentFolder(), tmpstr); + BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr); } else if (sfile->params->dir[0] == '\0') @@ -1481,7 +1510,7 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) int numfiles = filelist_numfiles(sfile->files); if ( (0 <= idx) && (idx < numfiles) ) { struct direntry *file = filelist_file(sfile->files, idx); - filelist_select_file(sfile->files, idx, FILE_SEL_ADD, EDITING_FILE, CHECK_ALL); + filelist_select_file(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE); sfile->params->renamefile[0] = '\0'; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 871abbda48a..bcef0817ffe 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -45,9 +45,10 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_fileops_types.h" +#include "BLI_fnmatch.h" #include "BLI_linklist.h" #include "BLI_utildefines.h" -#include "BLI_fileops_types.h" #ifdef WIN32 # include "BLI_winstuff.h" @@ -64,8 +65,8 @@ #include "DNA_space_types.h" -#include "ED_fileselect.h" #include "ED_datafiles.h" +#include "ED_fileselect.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -80,6 +81,119 @@ #include "filelist.h" + +/* ----------------- FOLDERLIST (previous/next) -------------- */ + +typedef struct FolderList { + struct FolderList *next, *prev; + char *foldername; +} FolderList; + +ListBase *folderlist_new(void) +{ + ListBase *p = MEM_callocN(sizeof(ListBase), "folderlist"); + return p; +} + +void folderlist_popdir(struct ListBase *folderlist, char *dir) +{ + const char *prev_dir; + struct FolderList *folder; + folder = folderlist->last; + + if (folder) { + /* remove the current directory */ + MEM_freeN(folder->foldername); + BLI_freelinkN(folderlist, folder); + + folder = folderlist->last; + if (folder) { + prev_dir = folder->foldername; + BLI_strncpy(dir, prev_dir, FILE_MAXDIR); + } + } + /* delete the folder next or use setdir directly before PREVIOUS OP */ +} + +void folderlist_pushdir(ListBase *folderlist, const char *dir) +{ + struct FolderList *folder, *previous_folder; + previous_folder = folderlist->last; + + /* check if already exists */ + if (previous_folder && previous_folder->foldername) { + if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { + return; + } + } + + /* create next folder element */ + folder = (FolderList *)MEM_mallocN(sizeof(FolderList), "FolderList"); + folder->foldername = BLI_strdup(dir); + + /* add it to the end of the list */ + BLI_addtail(folderlist, folder); +} + +const char *folderlist_peeklastdir(ListBase *folderlist) +{ + struct FolderList *folder; + + if (!folderlist->last) + return NULL; + + folder = folderlist->last; + return folder->foldername; +} + +int folderlist_clear_next(struct SpaceFile *sfile) +{ + struct FolderList *folder; + + /* if there is no folder_next there is nothing we can clear */ + if (!sfile->folders_next) + return 0; + + /* if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next */ + folder = sfile->folders_prev->last; + if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) + return 0; + + /* eventually clear flist->folders_next */ + return 1; +} + +/* not listbase itself */ +void folderlist_free(ListBase *folderlist) +{ + if (folderlist) { + FolderList *folder; + for (folder = folderlist->first; folder; folder = folder->next) + MEM_freeN(folder->foldername); + BLI_freelistN(folderlist); + } +} + +ListBase *folderlist_duplicate(ListBase *folderlist) +{ + + if (folderlist) { + ListBase *folderlistn = MEM_callocN(sizeof(ListBase), "copy folderlist"); + FolderList *folder; + + BLI_duplicatelist(folderlistn, folderlist); + + for (folder = folderlistn->first; folder; folder = folder->next) { + folder->foldername = MEM_dupallocN(folder->foldername); + } + return folderlistn; + } + return NULL; +} + + +/* ------------------FILELIST------------------------ */ + struct FileList; typedef struct FileImage { @@ -91,77 +205,87 @@ typedef struct FileImage { ImBuf *img; } FileImage; -typedef struct ThumbnailJob { - ListBase loadimages; - const short *stop; - const short *do_update; - struct FileList *filelist; - ReportList reports; -} ThumbnailJob; +typedef struct FileListFilter { + bool hide_dot; + bool hide_parent; + unsigned int filter; + char filter_glob[64]; + char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */ +} FileListFilter; typedef struct FileList { struct direntry *filelist; - int *fidx; int numfiles; - int numfiltered; char dir[FILE_MAX]; short prv_w; short prv_h; - short hide_dot; - unsigned int filter; - char filter_glob[64]; - short changed; + + bool changed; + + short sort; + bool need_sorting; + + FileListFilter filter_data; + int *fidx; /* Also used to detect when we need to filter! */ + int numfiltered; + + bool need_thumbnails; struct BlendHandle *libfiledata; - short hide_parent; void (*readf)(struct FileList *); - bool (*filterf)(struct direntry *file, const char *dir, unsigned int filter, short hide_dot); - + bool (*filterf)(struct direntry *, const char *, FileListFilter *); } FileList; -typedef struct FolderList { - struct FolderList *next, *prev; - char *foldername; -} FolderList; +#define FILENAME_IS_BREADCRUMBS(_n) \ + ((_n)[0] == '.' && ((_n)[1] == '\0' || ((_n)[1] == '.' && (_n)[2] == '\0'))) #define SPECIAL_IMG_SIZE 48 #define SPECIAL_IMG_ROWS 4 #define SPECIAL_IMG_COLS 4 -#define SPECIAL_IMG_FOLDER 0 -#define SPECIAL_IMG_PARENT 1 -#define SPECIAL_IMG_REFRESH 2 -#define SPECIAL_IMG_BLENDFILE 3 -#define SPECIAL_IMG_SOUNDFILE 4 -#define SPECIAL_IMG_MOVIEFILE 5 -#define SPECIAL_IMG_PYTHONFILE 6 -#define SPECIAL_IMG_TEXTFILE 7 -#define SPECIAL_IMG_FONTFILE 8 -#define SPECIAL_IMG_UNKNOWNFILE 9 -#define SPECIAL_IMG_LOADING 10 -#define SPECIAL_IMG_BACKUP 11 -#define SPECIAL_IMG_MAX SPECIAL_IMG_BACKUP + 1 +enum { + SPECIAL_IMG_FOLDER = 0, + SPECIAL_IMG_PARENT = 1, + SPECIAL_IMG_REFRESH = 2, + SPECIAL_IMG_BLENDFILE = 3, + SPECIAL_IMG_SOUNDFILE = 4, + SPECIAL_IMG_MOVIEFILE = 5, + SPECIAL_IMG_PYTHONFILE = 6, + SPECIAL_IMG_TEXTFILE = 7, + SPECIAL_IMG_FONTFILE = 8, + SPECIAL_IMG_UNKNOWNFILE = 9, + SPECIAL_IMG_LOADING = 10, + SPECIAL_IMG_BACKUP = 11, + SPECIAL_IMG_MAX +}; static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; -/* ******************* SORT ******************* */ +static void filelist_from_main(struct FileList *filelist); +static void filelist_from_library(struct FileList *filelist); + +static void filelist_read_main(struct FileList *filelist); +static void filelist_read_library(struct FileList *filelist); +static void filelist_read_dir(struct FileList *filelist); + +static void filelist_filter_clear(FileList *filelist); + +/* ********** Sort helpers ********** */ static bool compare_is_directory(const struct direntry *entry) { /* for library browse .blend files may be treated as directories, but * for sorting purposes they should be considered regular files */ if (S_ISDIR(entry->type)) - return !(entry->flags & (BLENDERFILE | BLENDERFILE_BACKUP)); + return !(entry->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)); return false; } -static int compare_name(const void *a1, const void *a2) +static int compare_direntry_generic(const struct direntry *entry1, const struct direntry *entry2) { - const struct direntry *entry1 = a1, *entry2 = a2; - /* type is equal to stat.st_mode */ if (compare_is_directory(entry1)) { @@ -185,35 +309,29 @@ static int compare_name(const void *a1, const void *a2) if (strcmp(entry1->relname, "..") == 0) return (-1); if (strcmp(entry2->relname, "..") == 0) return (1); + return 0; +} + +static int compare_name(const void *a1, const void *a2) +{ + const struct direntry *entry1 = a1, *entry2 = a2; + int ret; + + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } + return (BLI_natstrcmp(entry1->relname, entry2->relname)); } static int compare_date(const void *a1, const void *a2) { const struct direntry *entry1 = a1, *entry2 = a2; + int ret; - /* type is equal to stat.st_mode */ - - if (compare_is_directory(entry1)) { - if (compare_is_directory(entry2) == 0) return (-1); + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; } - else { - if (compare_is_directory(entry2)) return (1); - } - if (S_ISREG(entry1->type)) { - if (S_ISREG(entry2->type) == 0) return (-1); - } - else { - if (S_ISREG(entry2->type)) return (1); - } - if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); - if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); - - /* make sure "." and ".." are always first */ - if (strcmp(entry1->relname, ".") == 0) return (-1); - if (strcmp(entry2->relname, ".") == 0) return (1); - if (strcmp(entry1->relname, "..") == 0) return (-1); - if (strcmp(entry2->relname, "..") == 0) return (1); if (entry1->s.st_mtime < entry2->s.st_mtime) return 1; if (entry1->s.st_mtime > entry2->s.st_mtime) return -1; @@ -224,29 +342,11 @@ static int compare_date(const void *a1, const void *a2) static int compare_size(const void *a1, const void *a2) { const struct direntry *entry1 = a1, *entry2 = a2; + int ret; - /* type is equal to stat.st_mode */ - - if (compare_is_directory(entry1)) { - if (compare_is_directory(entry2) == 0) return (-1); - } - else { - if (compare_is_directory(entry2)) return (1); - } - if (S_ISREG(entry1->type)) { - if (S_ISREG(entry2->type) == 0) return (-1); + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; } - else { - if (S_ISREG(entry2->type)) return (1); - } - if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); - if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); - - /* make sure "." and ".." are always first */ - if (strcmp(entry1->relname, ".") == 0) return (-1); - if (strcmp(entry2->relname, ".") == 0) return (1); - if (strcmp(entry1->relname, "..") == 0) return (-1); - if (strcmp(entry2->relname, "..") == 0) return (1); if (entry1->s.st_size < entry2->s.st_size) return 1; if (entry1->s.st_size > entry2->s.st_size) return -1; @@ -258,6 +358,11 @@ static int compare_extension(const void *a1, const void *a2) const struct direntry *entry1 = a1, *entry2 = a2; const char *sufix1, *sufix2; const char *nil = ""; + int ret; + + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } if (!(sufix1 = strstr(entry1->relname, ".blend.gz"))) sufix1 = strrchr(entry1->relname, '.'); @@ -266,126 +371,191 @@ static int compare_extension(const void *a1, const void *a2) if (!sufix1) sufix1 = nil; if (!sufix2) sufix2 = nil; - /* type is equal to stat.st_mode */ + return (BLI_strcasecmp(sufix1, sufix2)); +} - if (compare_is_directory(entry1)) { - if (compare_is_directory(entry2) == 0) return (-1); - } - else { - if (compare_is_directory(entry2)) return (1); - } - if (S_ISREG(entry1->type)) { - if (S_ISREG(entry2->type) == 0) return (-1); +bool filelist_need_sorting(struct FileList *filelist) +{ + return filelist->need_sorting && (filelist->sort != FILE_SORT_NONE); +} + +void filelist_sort(struct FileList *filelist) +{ + if (filelist_need_sorting(filelist)) { + filelist->need_sorting = false; + + switch (filelist->sort) { + case FILE_SORT_ALPHA: + qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name); + break; + case FILE_SORT_TIME: + qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date); + break; + case FILE_SORT_SIZE: + qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size); + break; + case FILE_SORT_EXTENSION: + qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension); + break; + case FILE_SORT_NONE: /* Should never reach this point! */ + default: + BLI_assert(0); + return; + } + + filelist_filter_clear(filelist); } - else { - if (S_ISREG(entry2->type)) return (1); +} + +void filelist_setsorting(struct FileList *filelist, const short sort) +{ + if (filelist->sort != sort) { + filelist->sort = sort; + filelist->need_sorting = true; } - if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); - if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); - - /* make sure "." and ".." are always first */ - if (strcmp(entry1->relname, ".") == 0) return (-1); - if (strcmp(entry2->relname, ".") == 0) return (1); - if (strcmp(entry1->relname, "..") == 0) return (-1); - if (strcmp(entry2->relname, "..") == 0) return (1); - - return (BLI_strcasecmp(sufix1, sufix2)); } -static bool is_hidden_file(const char *filename, short hide_dot) +/* ********** Filter helpers ********** */ + +static bool is_hidden_file(const char *filename, FileListFilter *filter) { bool is_hidden = false; - if (hide_dot) { - if (filename[0] == '.' && filename[1] != '.' && filename[1] != 0) { - is_hidden = 1; /* ignore .file */ - } - else if (((filename[0] == '.') && (filename[1] == 0))) { - is_hidden = 1; /* ignore . */ + if (filter->hide_dot) { + if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') { + is_hidden = true; /* ignore .file */ } else { int len = strlen(filename); if ((len > 0) && (filename[len - 1] == '~')) { - is_hidden = 1; /* ignore file~ */ + is_hidden = true; /* ignore file~ */ } } } - else { - if (((filename[0] == '.') && (filename[1] == 0))) { - is_hidden = 1; /* ignore . */ + if (!is_hidden && filter->hide_parent) { + if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { + is_hidden = true; /* ignore .. */ } } + if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) { + is_hidden = true; /* ignore . */ + } return is_hidden; } -static bool is_filtered_file(struct direntry *file, const char *UNUSED(dir), unsigned int filter, short hide_dot) +static bool is_filtered_file(struct direntry *file, const char *UNUSED(root), FileListFilter *filter) { - bool is_filtered = false; - if (filter) { - if (file->flags & filter) { - is_filtered = 1; + bool is_filtered = !is_hidden_file(file->relname, filter); + + if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) { + if ((file->type & S_IFDIR) && !(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; } - else if (file->type & S_IFDIR) { - if (filter & FOLDERFILE) { - is_filtered = 1; + if (!(file->type & S_IFDIR) && !(file->flags & filter->filter)) { + is_filtered = false; + } + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relname, FNM_CASEFOLD) != 0) { + is_filtered = false; } } } - else { - is_filtered = 1; - } - return is_filtered && !is_hidden_file(file->relname, hide_dot); + + return is_filtered; } -static bool is_filtered_lib(struct direntry *file, const char *dir, unsigned int filter, short hide_dot) +static bool is_filtered_lib(struct direntry *file, const char *root, FileListFilter *filter) { - bool is_filtered = false; - char tdir[FILE_MAX], tgroup[BLO_GROUP_MAX]; - if (BLO_is_a_library(dir, tdir, tgroup)) { - is_filtered = !is_hidden_file(file->relname, hide_dot); + bool is_filtered = !is_hidden_file(file->relname, filter); + char dir[FILE_MAXDIR], group[BLO_GROUP_MAX]; + + if (BLO_is_a_library(root, dir, group)) { + is_filtered = !is_hidden_file(file->relname, filter); + if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) { + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relname, FNM_CASEFOLD) != 0) { + is_filtered = false; + } + } + } } else { - is_filtered = is_filtered_file(file, dir, filter, hide_dot); + is_filtered = is_filtered_file(file, root, filter); } + return is_filtered; } -static bool is_filtered_main(struct direntry *file, const char *UNUSED(dir), unsigned int UNUSED(filter), short hide_dot) +static bool is_filtered_main(struct direntry *file, const char *UNUSED(dir), FileListFilter *filter) +{ + return !is_hidden_file(file->relname, filter); +} + +static void filelist_filter_clear(FileList *filelist) { - return !is_hidden_file(file->relname, hide_dot); + MEM_SAFE_FREE(filelist->fidx); + filelist->numfiltered = 0; } void filelist_filter(FileList *filelist) { int num_filtered = 0; - int i, j; + int *fidx_tmp; + int i; - if (!filelist->filelist) + if (!filelist->filelist) { return; + } - /* How many files are left after filter ? */ + if (filelist->fidx) { + /* Assume it has already been filtered, nothing else to do! */ + return; + } + + fidx_tmp = MEM_mallocN(sizeof(*fidx_tmp) * (size_t)filelist->numfiles, __func__); + + /* Filter remap & count how many files are left after filter in a single loop. */ for (i = 0; i < filelist->numfiles; ++i) { struct direntry *file = &filelist->filelist[i]; - if (filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot)) { - num_filtered++; + + if (filelist->filterf(file, filelist->dir, &filelist->filter_data)) { + fidx_tmp[num_filtered++] = i; } } - - if (filelist->fidx) { - MEM_freeN(filelist->fidx); - filelist->fidx = NULL; - } - filelist->fidx = (int *)MEM_callocN(num_filtered * sizeof(int), "filteridx"); + + /* Note: maybe we could even accept filelist->fidx to be filelist->numfiles -len allocated? */ + filelist->fidx = (int *)MEM_mallocN(sizeof(*filelist->fidx) * (size_t)num_filtered, __func__); + memcpy(filelist->fidx, fidx_tmp, sizeof(*filelist->fidx) * (size_t)num_filtered); filelist->numfiltered = num_filtered; - for (i = 0, j = 0; i < filelist->numfiles; ++i) { - struct direntry *file = &filelist->filelist[i]; - if (filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot)) { - filelist->fidx[j++] = i; - } + MEM_freeN(fidx_tmp); +} + +void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent, + const unsigned int filter, + const char *filter_glob, const char *filter_search) +{ + if ((filelist->filter_data.hide_dot != hide_dot) || + (filelist->filter_data.hide_parent != hide_parent) || + (filelist->filter_data.filter != filter) || + !STREQ(filelist->filter_data.filter_glob, filter_glob) || + (BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) + { + filelist->filter_data.hide_dot = hide_dot; + filelist->filter_data.hide_parent = hide_parent; + + filelist->filter_data.filter = filter; + BLI_strncpy(filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob)); + BLI_strncpy_ensure_pad(filelist->filter_data.filter_search, filter_search, '*', + sizeof(filelist->filter_data.filter_search)); + + /* And now, free filtered data so that we now we have to filter again. */ + filelist_filter_clear(filelist); } } +/* ********** Icon/image helpers ********** */ + void filelist_init_icons(void) { short x, y, k; @@ -428,115 +598,86 @@ void filelist_free_icons(void) } } -/* -----------------FOLDERLIST (previous/next) -------------- */ -ListBase *folderlist_new(void) -{ - ListBase *p = MEM_callocN(sizeof(ListBase), "folderlist"); - return p; -} - -void folderlist_popdir(struct ListBase *folderlist, char *dir) +void filelist_imgsize(struct FileList *filelist, short w, short h) { - const char *prev_dir; - struct FolderList *folder; - folder = folderlist->last; - - if (folder) { - /* remove the current directory */ - MEM_freeN(folder->foldername); - BLI_freelinkN(folderlist, folder); - - folder = folderlist->last; - if (folder) { - prev_dir = folder->foldername; - BLI_strncpy(dir, prev_dir, FILE_MAXDIR); - } - } - /* delete the folder next or use setdir directly before PREVIOUS OP */ + filelist->prv_w = w; + filelist->prv_h = h; } -void folderlist_pushdir(ListBase *folderlist, const char *dir) +ImBuf *filelist_getimage(struct FileList *filelist, const int index) { - struct FolderList *folder, *previous_folder; - previous_folder = folderlist->last; - - /* check if already exists */ - if (previous_folder && previous_folder->foldername) { - if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { - return; - } - } - - /* create next folder element */ - folder = (FolderList *)MEM_mallocN(sizeof(FolderList), "FolderList"); - folder->foldername = BLI_strdup(dir); - - /* add it to the end of the list */ - BLI_addtail(folderlist, folder); -} + ImBuf *ibuf = NULL; + int fidx = 0; -const char *folderlist_peeklastdir(ListBase *folderlist) -{ - struct FolderList *folder; + BLI_assert(G.background == false); - if (!folderlist->last) + if ((index < 0) || (index >= filelist->numfiltered)) { return NULL; + } + fidx = filelist->fidx[index]; + ibuf = filelist->filelist[fidx].image; - folder = folderlist->last; - return folder->foldername; + return ibuf; } -int folderlist_clear_next(struct SpaceFile *sfile) +ImBuf *filelist_geticon(struct FileList *filelist, const int index) { - struct FolderList *folder; - - /* if there is no folder_next there is nothing we can clear */ - if (!sfile->folders_next) - return 0; - - /* if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next */ - folder = sfile->folders_prev->last; - if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) - return 0; + ImBuf *ibuf = NULL; + struct direntry *file = NULL; + int fidx = 0; - /* eventually clear flist->folders_next */ - return 1; -} + BLI_assert(G.background == false); -/* not listbase itself */ -void folderlist_free(ListBase *folderlist) -{ - if (folderlist) { - FolderList *folder; - for (folder = folderlist->first; folder; folder = folder->next) - MEM_freeN(folder->foldername); - BLI_freelistN(folderlist); + if ((index < 0) || (index >= filelist->numfiltered)) { + return NULL; } -} - -ListBase *folderlist_duplicate(ListBase *folderlist) -{ - - if (folderlist) { - ListBase *folderlistn = MEM_callocN(sizeof(ListBase), "copy folderlist"); - FolderList *folder; - - BLI_duplicatelist(folderlistn, folderlist); - - for (folder = folderlistn->first; folder; folder = folder->next) { - folder->foldername = MEM_dupallocN(folder->foldername); + fidx = filelist->fidx[index]; + file = &filelist->filelist[fidx]; + if (file->type & S_IFDIR) { + if (strcmp(filelist->filelist[fidx].relname, "..") == 0) { + ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; + } + else if (strcmp(filelist->filelist[fidx].relname, ".") == 0) { + ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; + } + else { + ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; } - return folderlistn; } - return NULL; -} + else { + ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; + } + if (file->flags & FILE_TYPE_BLENDER) { + ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; + } + else if ((file->flags & FILE_TYPE_MOVIE) || (file->flags & FILE_TYPE_MOVIE_ICON)) { + ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; + } + else if (file->flags & FILE_TYPE_SOUND) { + ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; + } + else if (file->flags & FILE_TYPE_PYSCRIPT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; + } + else if (file->flags & FILE_TYPE_FTFONT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; + } + else if (file->flags & FILE_TYPE_TEXT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; + } + else if (file->flags & FILE_TYPE_IMAGE) { + ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; + } + else if (file->flags & FILE_TYPE_BLENDER_BACKUP) { + ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP]; + } -static void filelist_read_main(struct FileList *filelist); -static void filelist_read_library(struct FileList *filelist); -static void filelist_read_dir(struct FileList *filelist); + return ibuf; +} + +/* ********** Main ********** */ -/* ------------------FILELIST------------------------ */ FileList *filelist_new(short type) { FileList *p = MEM_callocN(sizeof(FileList), "filelist"); @@ -558,7 +699,6 @@ FileList *filelist_new(short type) return p; } - void filelist_free(struct FileList *filelist) { if (!filelist) { @@ -566,18 +706,16 @@ void filelist_free(struct FileList *filelist) return; } - if (filelist->fidx) { - MEM_freeN(filelist->fidx); - filelist->fidx = NULL; - } + MEM_SAFE_FREE(filelist->fidx); + filelist->numfiltered = 0; + memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); + + filelist->need_sorting = false; + filelist->sort = FILE_SORT_NONE; - BLI_free_filelist(filelist->filelist, filelist->numfiles); + BLI_filelist_free(filelist->filelist, filelist->numfiles, NULL); filelist->numfiles = 0; filelist->filelist = NULL; - filelist->filter = 0; - filelist->filter_glob[0] = '\0'; - filelist->numfiltered = 0; - filelist->hide_dot = 0; } void filelist_freelib(struct FileList *filelist) @@ -607,89 +745,11 @@ void filelist_setdir(struct FileList *filelist, const char *dir) BLI_strncpy(filelist->dir, dir, sizeof(filelist->dir)); } -void filelist_imgsize(struct FileList *filelist, short w, short h) -{ - filelist->prv_w = w; - filelist->prv_h = h; -} - short filelist_changed(struct FileList *filelist) { return filelist->changed; } -ImBuf *filelist_getimage(struct FileList *filelist, int index) -{ - ImBuf *ibuf = NULL; - int fidx = 0; - - BLI_assert(G.background == false); - - if ((index < 0) || (index >= filelist->numfiltered)) { - return NULL; - } - fidx = filelist->fidx[index]; - ibuf = filelist->filelist[fidx].image; - - return ibuf; -} - -ImBuf *filelist_geticon(struct FileList *filelist, int index) -{ - ImBuf *ibuf = NULL; - struct direntry *file = NULL; - int fidx = 0; - - BLI_assert(G.background == false); - - if ((index < 0) || (index >= filelist->numfiltered)) { - return NULL; - } - fidx = filelist->fidx[index]; - file = &filelist->filelist[fidx]; - if (file->type & S_IFDIR) { - if (strcmp(filelist->filelist[fidx].relname, "..") == 0) { - ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; - } - else if (strcmp(filelist->filelist[fidx].relname, ".") == 0) { - ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; - } - else { - ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; - } - } - else { - ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; - } - - if (file->flags & BLENDERFILE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; - } - else if ((file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; - } - else if (file->flags & SOUNDFILE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; - } - else if (file->flags & PYSCRIPTFILE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; - } - else if (file->flags & FTFONTFILE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; - } - else if (file->flags & TEXTFILE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; - } - else if (file->flags & IMAGEFILE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; - } - else if (file->flags & BLENDERFILE_BACKUP) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP]; - } - - return ibuf; -} - struct direntry *filelist_file(struct FileList *filelist, int index) { int fidx = 0; @@ -728,21 +788,6 @@ int filelist_find(struct FileList *filelist, const char *filename) return fidx; } -void filelist_hidedot(struct FileList *filelist, short hide) -{ - filelist->hide_dot = hide; -} - -void filelist_setfilter(struct FileList *filelist, unsigned int filter) -{ - filelist->filter = filter; -} - -void filelist_setfilter_types(struct FileList *filelist, const char *filter_glob) -{ - BLI_strncpy(filelist->filter_glob, filter_glob, sizeof(filelist->filter_glob)); -} - /* would recognize .blend as well */ static bool file_is_blend_backup(const char *str) { @@ -772,47 +817,47 @@ static bool file_is_blend_backup(const char *str) static int path_extension_type(const char *path) { if (BLO_has_bfile_extension(path)) { - return BLENDERFILE; + return FILE_TYPE_BLENDER; } else if (file_is_blend_backup(path)) { - return BLENDERFILE_BACKUP; + return FILE_TYPE_BLENDER_BACKUP; } else if (BLI_testextensie(path, ".app")) { - return APPLICATIONBUNDLE; + return FILE_TYPE_APPLICATIONBUNDLE; } else if (BLI_testextensie(path, ".py")) { - return PYSCRIPTFILE; + return FILE_TYPE_PYSCRIPT; } else if (BLI_testextensie_n(path, ".txt", ".glsl", ".osl", ".data", NULL)) { - return TEXTFILE; + return FILE_TYPE_TEXT; } else if (BLI_testextensie_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) { - return FTFONTFILE; + return FILE_TYPE_FTFONT; } else if (BLI_testextensie(path, ".btx")) { - return BTXFILE; + return FILE_TYPE_BTX; } else if (BLI_testextensie(path, ".dae")) { - return COLLADAFILE; + return FILE_TYPE_COLLADA; } else if (BLI_testextensie_array(path, imb_ext_image) || (G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt))) { - return IMAGEFILE; + return FILE_TYPE_IMAGE; } else if (BLI_testextensie(path, ".ogg")) { if (IMB_isanim(path)) { - return MOVIEFILE; + return FILE_TYPE_MOVIE; } else { - return SOUNDFILE; + return FILE_TYPE_SOUND; } } else if (BLI_testextensie_array(path, imb_ext_movie)) { - return MOVIEFILE; + return FILE_TYPE_MOVIE; } else if (BLI_testextensie_array(path, imb_ext_audio)) { - return SOUNDFILE; + return FILE_TYPE_SOUND; } return 0; } @@ -828,25 +873,25 @@ int ED_file_extension_icon(const char *path) { int type = path_extension_type(path); - if (type == BLENDERFILE) + if (type == FILE_TYPE_BLENDER) return ICON_FILE_BLEND; - else if (type == BLENDERFILE_BACKUP) + else if (type == FILE_TYPE_BLENDER_BACKUP) return ICON_FILE_BACKUP; - else if (type == IMAGEFILE) + else if (type == FILE_TYPE_IMAGE) return ICON_FILE_IMAGE; - else if (type == MOVIEFILE) + else if (type == FILE_TYPE_MOVIE) return ICON_FILE_MOVIE; - else if (type == PYSCRIPTFILE) + else if (type == FILE_TYPE_PYSCRIPT) return ICON_FILE_SCRIPT; - else if (type == SOUNDFILE) + else if (type == FILE_TYPE_SOUND) return ICON_FILE_SOUND; - else if (type == FTFONTFILE) + else if (type == FILE_TYPE_FTFONT) return ICON_FILE_FONT; - else if (type == BTXFILE) + else if (type == FILE_TYPE_BTX) return ICON_FILE_BLANK; - else if (type == COLLADAFILE) + else if (type == FILE_TYPE_COLLADA) return ICON_FILE_BLANK; - else if (type == TEXTFILE) + else if (type == FILE_TYPE_TEXT) return ICON_FILE_TEXT; return ICON_FILE_BLANK; @@ -869,12 +914,11 @@ static void filelist_setfiletypes(struct FileList *filelist) #endif file->flags = file_extension_type(filelist->dir, file->relname); - if (filelist->filter_glob[0] && - BLI_testextensie_glob(file->relname, filelist->filter_glob)) + if (filelist->filter_data.filter_glob[0] && + BLI_testextensie_glob(file->relname, filelist->filter_data.filter_glob)) { - file->flags = OPERATORFILE; + file->flags = FILE_TYPE_OPERATOR; } - } } @@ -885,11 +929,15 @@ static void filelist_read_dir(struct FileList *filelist) filelist->fidx = NULL; filelist->filelist = NULL; + BLI_make_exist(filelist->dir); BLI_cleanup_dir(G.main->name, filelist->dir); - filelist->numfiles = BLI_dir_contents(filelist->dir, &(filelist->filelist)); + filelist->numfiles = BLI_filelist_dir_contents(filelist->dir, &(filelist->filelist)); + + /* We shall *never* get an empty list here, since we now the dir exists and is readable + * (ensured by BLI_make_exist()). So we expect at the very least the parent '..' entry. */ + BLI_assert(filelist->numfiles != 0); filelist_setfiletypes(filelist); - filelist_filter(filelist); } static void filelist_read_main(struct FileList *filelist) @@ -907,7 +955,6 @@ static void filelist_read_library(struct FileList *filelist) int num; struct direntry *file; - BLI_make_exist(filelist->dir); filelist_read_dir(filelist); file = filelist->filelist; for (num = 0; num < filelist->numfiles; num++, file++) { @@ -929,18 +976,15 @@ static void filelist_read_library(struct FileList *filelist) void filelist_readdir(struct FileList *filelist) { filelist->readf(filelist); -} -int filelist_empty(struct FileList *filelist) -{ - return filelist->filelist == NULL; + filelist->need_sorting = true; + filelist->need_thumbnails = true; + filelist_filter_clear(filelist); } -void filelist_parent(struct FileList *filelist) +int filelist_empty(struct FileList *filelist) { - BLI_parent_dir(filelist->dir); - BLI_make_exist(filelist->dir); - filelist_readdir(filelist); + return filelist->filelist == NULL; } void filelist_select_file(struct FileList *filelist, int index, FileSelType select, unsigned int flag, FileCheckType check) @@ -995,35 +1039,15 @@ bool filelist_is_selected(struct FileList *filelist, int index, FileCheckType ch } switch (check) { case CHECK_DIRS: - return S_ISDIR(file->type) && (file->selflag & SELECTED_FILE); + return S_ISDIR(file->type) && (file->selflag & FILE_SEL_SELECTED); case CHECK_FILES: - return S_ISREG(file->type) && (file->selflag & SELECTED_FILE); + return S_ISREG(file->type) && (file->selflag & FILE_SEL_SELECTED); case CHECK_ALL: default: - return (file->selflag & SELECTED_FILE) != 0; + return (file->selflag & FILE_SEL_SELECTED) != 0; } } -void filelist_sort(struct FileList *filelist, short sort) -{ - switch (sort) { - case FILE_SORT_ALPHA: - qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name); - break; - case FILE_SORT_TIME: - qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date); - break; - case FILE_SORT_SIZE: - qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size); - break; - case FILE_SORT_EXTENSION: - qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension); - break; - } - - filelist_filter(filelist); -} - bool filelist_islibrary(struct FileList *filelist, char *dir, char *group) { @@ -1042,8 +1066,8 @@ static int groupname_to_code(const char *group) return buf[0] ? BKE_idcode_from_name(buf) : 0; } - -void filelist_from_library(struct FileList *filelist) + +static void filelist_from_library(struct FileList *filelist) { LinkNode *l, *names, *previews; struct ImBuf *ima; @@ -1124,7 +1148,7 @@ void filelist_from_library(struct FileList *filelist) ima = IMB_allocImBuf(w, h, 32, IB_rect); memcpy(ima->rect, rect, w * h * sizeof(unsigned int)); filelist->filelist[i + 1].image = ima; - filelist->filelist[i + 1].flags = IMAGEFILE; + filelist->filelist[i + 1].flags = FILE_TYPE_IMAGE; } } } @@ -1133,20 +1157,10 @@ void filelist_from_library(struct FileList *filelist) BLI_linklist_free(names, free); if (previews) BLI_linklist_free(previews, BKE_previewimg_freefunc); - filelist_sort(filelist, FILE_SORT_ALPHA); - BLI_strncpy(G.main->name, filename, sizeof(filename)); /* prevent G.main->name to change */ - - filelist->filter = 0; - filelist_filter(filelist); -} - -void filelist_hideparent(struct FileList *filelist, short hide) -{ - filelist->hide_parent = hide; } -void filelist_from_main(struct FileList *filelist) +static void filelist_from_main(struct FileList *filelist) { ID *id; struct direntry *files, *firstlib = NULL; @@ -1166,9 +1180,9 @@ void filelist_from_main(struct FileList *filelist) /* make directories */ #ifdef WITH_FREESTYLE - filelist->numfiles = 25; -#else filelist->numfiles = 24; +#else + filelist->numfiles = 23; #endif filelist->filelist = (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)); @@ -1178,32 +1192,31 @@ void filelist_from_main(struct FileList *filelist) } filelist->filelist[0].relname = BLI_strdup(".."); - filelist->filelist[2].relname = BLI_strdup("Scene"); - filelist->filelist[3].relname = BLI_strdup("Object"); - filelist->filelist[4].relname = BLI_strdup("Mesh"); - filelist->filelist[5].relname = BLI_strdup("Curve"); - filelist->filelist[6].relname = BLI_strdup("Metaball"); - filelist->filelist[7].relname = BLI_strdup("Material"); - filelist->filelist[8].relname = BLI_strdup("Texture"); - filelist->filelist[9].relname = BLI_strdup("Image"); - filelist->filelist[10].relname = BLI_strdup("Ika"); - filelist->filelist[11].relname = BLI_strdup("Wave"); - filelist->filelist[12].relname = BLI_strdup("Lattice"); - filelist->filelist[13].relname = BLI_strdup("Lamp"); - filelist->filelist[14].relname = BLI_strdup("Camera"); - filelist->filelist[15].relname = BLI_strdup("Ipo"); - filelist->filelist[16].relname = BLI_strdup("World"); - filelist->filelist[17].relname = BLI_strdup("Screen"); - filelist->filelist[18].relname = BLI_strdup("VFont"); - filelist->filelist[19].relname = BLI_strdup("Text"); - filelist->filelist[20].relname = BLI_strdup("Armature"); - filelist->filelist[21].relname = BLI_strdup("Action"); - filelist->filelist[22].relname = BLI_strdup("NodeTree"); - filelist->filelist[23].relname = BLI_strdup("Speaker"); + filelist->filelist[1].relname = BLI_strdup("Scene"); + filelist->filelist[2].relname = BLI_strdup("Object"); + filelist->filelist[3].relname = BLI_strdup("Mesh"); + filelist->filelist[4].relname = BLI_strdup("Curve"); + filelist->filelist[5].relname = BLI_strdup("Metaball"); + filelist->filelist[6].relname = BLI_strdup("Material"); + filelist->filelist[7].relname = BLI_strdup("Texture"); + filelist->filelist[8].relname = BLI_strdup("Image"); + filelist->filelist[9].relname = BLI_strdup("Ika"); + filelist->filelist[10].relname = BLI_strdup("Wave"); + filelist->filelist[11].relname = BLI_strdup("Lattice"); + filelist->filelist[12].relname = BLI_strdup("Lamp"); + filelist->filelist[13].relname = BLI_strdup("Camera"); + filelist->filelist[14].relname = BLI_strdup("Ipo"); + filelist->filelist[15].relname = BLI_strdup("World"); + filelist->filelist[16].relname = BLI_strdup("Screen"); + filelist->filelist[17].relname = BLI_strdup("VFont"); + filelist->filelist[18].relname = BLI_strdup("Text"); + filelist->filelist[19].relname = BLI_strdup("Armature"); + filelist->filelist[20].relname = BLI_strdup("Action"); + filelist->filelist[21].relname = BLI_strdup("NodeTree"); + filelist->filelist[22].relname = BLI_strdup("Speaker"); #ifdef WITH_FREESTYLE - filelist->filelist[24].relname = BLI_strdup("FreestyleLineStyle"); + filelist->filelist[23].relname = BLI_strdup("FreestyleLineStyle"); #endif - filelist_sort(filelist, FILE_SORT_ALPHA); } else { @@ -1216,7 +1229,7 @@ void filelist_from_main(struct FileList *filelist) id = lb->first; filelist->numfiles = 0; while (id) { - if (!filelist->hide_dot || id->name[2] != '.') { + if (!filelist->filter_data.hide_dot || id->name[2] != '.') { filelist->numfiles++; } @@ -1224,12 +1237,12 @@ void filelist_from_main(struct FileList *filelist) } /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */ - if (!filelist->hide_parent) filelist->numfiles += 1; + if (!filelist->filter_data.hide_parent) filelist->numfiles += 1; filelist->filelist = filelist->numfiles > 0 ? (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)) : NULL; files = filelist->filelist; - if (!filelist->hide_parent) { + if (!filelist->filter_data.hide_parent) { memset(&(filelist->filelist[0]), 0, sizeof(struct direntry)); filelist->filelist[0].relname = BLI_strdup(".."); filelist->filelist[0].type |= S_IFDIR; @@ -1243,7 +1256,7 @@ void filelist_from_main(struct FileList *filelist) while (id) { ok = 1; if (ok) { - if (!filelist->hide_dot || id->name[2] != '.') { + if (!filelist->filter_data.hide_dot || id->name[2] != '.') { memset(files, 0, sizeof(struct direntry)); if (id->lib == NULL) { files->relname = BLI_strdup(id->name + 2); @@ -1256,10 +1269,10 @@ void filelist_from_main(struct FileList *filelist) #if 0 /* XXXXX TODO show the selection status of the objects */ if (!filelist->has_func) { /* F4 DATA BROWSE */ if (idcode == ID_OB) { - if ( ((Object *)id)->flag & SELECT) files->selflag |= SELECTED_FILE; + if ( ((Object *)id)->flag & SELECT) files->selflag |= FILE_SEL_SELECTED; } else if (idcode == ID_SCE) { - if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->selflag |= SELECTED_FILE; + if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->selflag |= FILE_SEL_SELECTED; } } #endif @@ -1267,7 +1280,7 @@ void filelist_from_main(struct FileList *filelist) files->poin = id; fake = id->flag & LIB_FAKEUSER; if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) { - files->flags |= IMAGEFILE; + files->flags |= FILE_TYPE_IMAGE; } if (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->extra), "LF %d", id->us); else if (id->lib) BLI_snprintf(files->extra, sizeof(files->extra), "L %d", id->us); @@ -1292,8 +1305,22 @@ void filelist_from_main(struct FileList *filelist) qsort(firstlib, totlib, sizeof(struct direntry), compare_name); } } - filelist->filter = 0; - filelist_filter(filelist); +} + +/* ********** Thumbnails job ********** */ + +typedef struct ThumbnailJob { + ListBase loadimages; + ImBuf *static_icons_buffers[BIFICONID_LAST]; + const short *stop; + const short *do_update; + struct FileList *filelist; + ReportList reports; +} ThumbnailJob; + +bool filelist_need_thumbnails(FileList *filelist) +{ + return filelist->need_thumbnails; } static void thumbnail_joblist_free(ThumbnailJob *tj) @@ -1318,18 +1345,18 @@ static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float tj->do_update = do_update; while ((*stop == 0) && (limg)) { - if (limg->flags & IMAGEFILE) { + if (limg->flags & FILE_TYPE_IMAGE) { limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE); } - else if (limg->flags & (BLENDERFILE | BLENDERFILE_BACKUP)) { + else if (limg->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND); } - else if (limg->flags & MOVIEFILE) { + else if (limg->flags & FILE_TYPE_MOVIE) { limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE); if (!limg->img) { /* remember that file can't be loaded via IMB_open_anim */ - limg->flags &= ~MOVIEFILE; - limg->flags |= MOVIEFILE_ICON; + limg->flags &= ~FILE_TYPE_MOVIE; + limg->flags |= FILE_TYPE_MOVIE_ICON; } } *do_update = true; @@ -1348,9 +1375,9 @@ static void thumbnails_update(void *tjv) if (!limg->done && limg->img) { tj->filelist->filelist[limg->index].image = limg->img; /* update flag for movie files where thumbnail can't be created */ - if (limg->flags & MOVIEFILE_ICON) { - tj->filelist->filelist[limg->index].flags &= ~MOVIEFILE; - tj->filelist->filelist[limg->index].flags |= MOVIEFILE_ICON; + if (limg->flags & FILE_TYPE_MOVIE_ICON) { + tj->filelist->filelist[limg->index].flags &= ~FILE_TYPE_MOVIE; + tj->filelist->filelist[limg->index].flags |= FILE_TYPE_MOVIE_ICON; } limg->done = true; } @@ -1359,6 +1386,15 @@ static void thumbnails_update(void *tjv) } } +static void thumbnails_endjob(void *tjv) +{ + ThumbnailJob *tj = tjv; + + if (!*tj->stop) { + tj->filelist->need_thumbnails = false; + } +} + static void thumbnails_free(void *tjv) { ThumbnailJob *tj = tjv; @@ -1378,7 +1414,9 @@ void thumbnails_start(FileList *filelist, const bContext *C) tj->filelist = filelist; for (idx = 0; idx < filelist->numfiles; idx++) { if (!filelist->filelist[idx].image) { - if ((filelist->filelist[idx].flags & (IMAGEFILE | MOVIEFILE | BLENDERFILE | BLENDERFILE_BACKUP))) { + if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | + FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) + { FileImage *limg = MEM_callocN(sizeof(FileImage), "loadimage"); BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX); limg->index = idx; @@ -1395,7 +1433,7 @@ void thumbnails_start(FileList *filelist, const bContext *C) 0, WM_JOB_TYPE_FILESEL_THUMBNAIL); WM_jobs_customdata_set(wm_job, tj, thumbnails_free); WM_jobs_timer(wm_job, 0.5, NC_WINDOW, NC_WINDOW); - WM_jobs_callbacks(wm_job, thumbnails_startjob, NULL, thumbnails_update, NULL); + WM_jobs_callbacks(wm_job, thumbnails_startjob, NULL, thumbnails_update, thumbnails_endjob); /* start the job */ WM_jobs_start(CTX_wm_manager(C), wm_job); @@ -1403,7 +1441,7 @@ void thumbnails_start(FileList *filelist, const bContext *C) void thumbnails_stop(wmWindowManager *wm, FileList *filelist) { - WM_jobs_kill(wm, filelist, NULL); + WM_jobs_kill_type(wm, filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL); } int thumbnails_running(wmWindowManager *wm, FileList *filelist) diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index c37bb882168..797d54a89b1 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -60,47 +60,53 @@ typedef enum FileCheckType { CHECK_ALL = 3 } FileCheckType; -struct FileList * filelist_new(short type); +struct ListBase * folderlist_new(void); +void folderlist_free(struct ListBase *folderlist); +struct ListBase * folderlist_duplicate(ListBase *folderlist); +void folderlist_popdir(struct ListBase *folderlist, char *dir); +void folderlist_pushdir(struct ListBase *folderlist, const char *dir); +const char * folderlist_peeklastdir(struct ListBase *folderdist); +int folderlist_clear_next(struct SpaceFile *sfile); + + +void filelist_setsorting(struct FileList *filelist, const short sort); +bool filelist_need_sorting(struct FileList *filelist); +void filelist_sort(struct FileList *filelist); + +void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent, + const unsigned int filter, + const char *filter_glob, const char *filter_search); +void filelist_filter(struct FileList *filelist); + void filelist_init_icons(void); void filelist_free_icons(void); -int filelist_find(struct FileList *filelist, const char *file); +void filelist_imgsize(struct FileList *filelist, short w, short h); +struct ImBuf * filelist_getimage(struct FileList *filelist, const int index); +struct ImBuf * filelist_geticon(struct FileList *filelist, const int index); + +struct FileList * filelist_new(short type); void filelist_free(struct FileList *filelist); -void filelist_sort(struct FileList *filelist, short sort); -int filelist_numfiles(struct FileList *filelist); + const char * filelist_dir(struct FileList *filelist); +void filelist_readdir(struct FileList *filelist); void filelist_setdir(struct FileList *filelist, const char *dir); + +int filelist_empty(struct FileList *filelist); +int filelist_numfiles(struct FileList *filelist); struct direntry * filelist_file(struct FileList *filelist, int index); +int filelist_find(struct FileList *filelist, const char *file); + +short filelist_changed(struct FileList *filelist); + void filelist_select(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check); void filelist_select_file(struct FileList *filelist, int index, FileSelType select, unsigned int flag, FileCheckType check); bool filelist_is_selected(struct FileList *filelist, int index, FileCheckType check); -void filelist_hidedot(struct FileList *filelist, short hide); -void filelist_setfilter(struct FileList *filelist, unsigned int filter); -void filelist_setfilter_types(struct FileList *filelist, const char *filter_glob); -void filelist_filter(struct FileList *filelist); -void filelist_imgsize(struct FileList *filelist, short w, short h); -struct ImBuf * filelist_getimage(struct FileList *filelist, int index); -struct ImBuf * filelist_geticon(struct FileList *filelist, int index); -short filelist_changed(struct FileList *filelist); -void filelist_readdir(struct FileList *filelist); - -int filelist_empty(struct FileList *filelist); -void filelist_parent(struct FileList *filelist); struct BlendHandle *filelist_lib(struct FileList *filelist); bool filelist_islibrary(struct FileList *filelist, char *dir, char *group); -void filelist_from_main(struct FileList *filelist); -void filelist_from_library(struct FileList *filelist); void filelist_freelib(struct FileList *filelist); -void filelist_hideparent(struct FileList *filelist, short hide); - -struct ListBase * folderlist_new(void); -void folderlist_free(struct ListBase *folderlist); -struct ListBase * folderlist_duplicate(ListBase *folderlist); -void folderlist_popdir(struct ListBase *folderlist, char *dir); -void folderlist_pushdir(struct ListBase *folderlist, const char *dir); -const char * folderlist_peeklastdir(struct ListBase *folderdist); -int folderlist_clear_next(struct SpaceFile *sfile); +bool filelist_need_thumbnails(struct FileList *filelist); void thumbnails_start(struct FileList *filelist, const struct bContext *C); void thumbnails_stop(struct wmWindowManager *wm, struct FileList *filelist); int thumbnails_running(struct wmWindowManager *wm, struct FileList *filelist); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 8b90cf6cc29..3e663275dcd 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -58,6 +58,7 @@ #include "BLI_fileops_types.h" #include "BLI_fnmatch.h" +#include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" @@ -157,30 +158,30 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->filter = 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_backup"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE_BACKUP : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER_BACKUP : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_image"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? IMAGEFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_IMAGE : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_movie"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? MOVIEFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_MOVIE : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_python"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? PYSCRIPTFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_PYSCRIPT : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_font"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FTFONTFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FTFONT : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_sound"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? SOUNDFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_SOUND : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? TEXTFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_TEXT : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FOLDERFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FOLDER : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_btx"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BTXFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? COLLADAFILE : 0; + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) { RNA_property_string_get(op->ptr, prop, params->filter_glob); - params->filter |= (OPERATORFILE | FOLDERFILE); + params->filter |= (FILE_TYPE_OPERATOR | FILE_TYPE_FOLDER); } else { params->filter_glob[0] = '\0'; @@ -214,7 +215,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) if (params->display == FILE_DEFAULTDISPLAY) { if (U.uiflag & USER_SHOW_THUMBNAILS) { - if (params->filter & (IMAGEFILE | MOVIEFILE)) + if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE)) params->display = FILE_IMGDISPLAY; else params->display = FILE_SHORTDISPLAY; @@ -253,7 +254,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) BLI_split_dir_part(G.main->name, sfile->params->dir, sizeof(sfile->params->dir)); } else { - const char *doc_path = BLI_getDefaultDocumentFolder(); + const char *doc_path = BKE_appdir_folder_default(); if (doc_path) { BLI_strncpy(sfile->params->dir, doc_path, sizeof(sfile->params->dir)); } @@ -602,9 +603,12 @@ void file_change_dir(bContext *C, int checkdir) SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { - ED_fileselect_clear(wm, sfile); + /* Clear search string, it is very rare to want to keep that filter while changing dir, + * and usually very annoying to keep it actually! */ + sfile->params->filter_search[0] = '\0'; + if (checkdir && !BLI_is_dir(sfile->params->dir)) { BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); /* could return but just refresh the current dir */ @@ -634,7 +638,7 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche for (i = 0; i < n; i++) { file = filelist_file(sfile->files, i); if (fnmatch(pattern, file->relname, 0) == 0) { - file->selflag |= SELECTED_FILE; + file->selflag |= FILE_SEL_SELECTED; if (!match) { BLI_strncpy(matched_file, file->relname, FILE_MAX); } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index f046ac7cdb3..4ab9bc6a849 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -367,7 +367,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) /* As 10.4 doesn't provide proper API to retrieve the favorite places, * assume they are the standard ones - * TODO : replace hardcoded paths with proper BLI_get_folder calls */ + * TODO : replace hardcoded paths with proper BKE_appdir_folder_id calls */ home = getenv("HOME"); if (read_bookmarks && home) { BLI_snprintf(line, sizeof(line), "%s/", home); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index d5be04cff20..f0555933146 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -39,8 +39,8 @@ #include "BLI_utildefines.h" #include "BLI_fileops_types.h" -#include "BLO_readfile.h" +#include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_global.h" @@ -193,64 +193,59 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa)) SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); - if (!sfile->folders_prev) + if (!sfile->folders_prev) { sfile->folders_prev = folderlist_new(); + } if (!sfile->files) { sfile->files = filelist_new(params->type); filelist_setdir(sfile->files, params->dir); - params->active_file = -1; // added this so it opens nicer (ton) + params->active_file = -1; /* added this so it opens nicer (ton) */ } - filelist_hidedot(sfile->files, params->flag & FILE_HIDE_DOT); - filelist_setfilter(sfile->files, params->flag & FILE_FILTER ? params->filter : 0); - filelist_setfilter_types(sfile->files, params->filter_glob); + filelist_setsorting(sfile->files, params->sort); + filelist_setfilter_options(sfile->files, params->flag & FILE_HIDE_DOT, + false, /* TODO hide_parent, should be controllable? */ + params->flag & FILE_FILTER ? params->filter : 0, + params->filter_glob, + params->filter_search); if (filelist_empty(sfile->files)) { thumbnails_stop(wm, sfile->files); filelist_readdir(sfile->files); - if (params->sort != FILE_SORT_NONE) { - filelist_sort(sfile->files, params->sort); - } + filelist_sort(sfile->files); BLI_strncpy(params->dir, filelist_dir(sfile->files), FILE_MAX); - if (params->display == FILE_IMGDISPLAY) { + } + else if (filelist_need_sorting(sfile->files)) { + thumbnails_stop(wm, sfile->files); + filelist_sort(sfile->files); + } + + if ((params->display == FILE_IMGDISPLAY) && filelist_need_thumbnails(sfile->files)) { + if (!thumbnails_running(wm, sfile->files)) { thumbnails_start(sfile->files, C); } } else { - if (params->sort != FILE_SORT_NONE) { - thumbnails_stop(wm, sfile->files); - filelist_sort(sfile->files, params->sort); - if (params->display == FILE_IMGDISPLAY) { - thumbnails_start(sfile->files, C); - } - } - else { - if (params->display == FILE_IMGDISPLAY) { - if (!thumbnails_running(wm, sfile->files)) { - thumbnails_start(sfile->files, C); - } - } - else { - /* stop any running thumbnail jobs if we're not - * displaying them - speedup for NFS */ - thumbnails_stop(wm, sfile->files); - } - filelist_filter(sfile->files); - } + /* stop any running thumbnail jobs if we're not displaying them - speedup for NFS */ + thumbnails_stop(wm, sfile->files); } - + + filelist_filter(sfile->files); + if (params->renamefile[0] != '\0') { int idx = filelist_find(sfile->files, params->renamefile); if (idx >= 0) { struct direntry *file = filelist_file(sfile->files, idx); if (file) { - file->selflag |= EDITING_FILE; + file->selflag |= FILE_SEL_EDITING; } } BLI_strncpy(sfile->params->renameedit, sfile->params->renamefile, sizeof(sfile->params->renameedit)); params->renamefile[0] = '\0'; } - if (sfile->layout) sfile->layout->dirty = true; + if (sfile->layout) { + sfile->layout->dirty = true; + } } static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) @@ -656,7 +651,7 @@ void ED_file_exit(void) void ED_file_read_bookmarks(void) { - const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); + const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); fsmenu_free(); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 53beb5e0659..b87f80c4e62 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -60,8 +60,6 @@ #include "BKE_context.h" #include "BKE_report.h" -#include "UI_interface.h" -#include "UI_resources.h" #include "UI_view2d.h" #include "ED_anim_api.h" @@ -699,7 +697,7 @@ static short copy_graph_keys(bAnimContext *ac) } static short paste_graph_keys(bAnimContext *ac, - const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) + const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip) { ListBase anim_data = {NULL, NULL}; int filter, ok = 0; @@ -716,7 +714,7 @@ static short paste_graph_keys(bAnimContext *ac, ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* paste keyframes */ - ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode); + ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip); /* clean up */ ANIM_animdata_freelist(&anim_data); @@ -767,6 +765,7 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op) const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset"); const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge"); + const bool flipped = RNA_boolean_get(op->ptr, "flipped"); /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -776,7 +775,7 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op) ac.reports = op->reports; /* paste keyframes - non-zero return means an error occurred while trying to paste */ - if (paste_graph_keys(&ac, offset_mode, merge_mode)) { + if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) { return OPERATOR_CANCELLED; } @@ -788,6 +787,8 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op) void GRAPH_OT_paste(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Paste Keyframes"; ot->idname = "GRAPH_OT_paste"; @@ -804,6 +805,8 @@ void GRAPH_OT_paste(wmOperatorType *ot) /* props */ RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys"); RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing"); + prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ******************** Duplicate Keyframes Operator ************************* */ @@ -1241,7 +1244,7 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_float(ot->srna, "low", 0.0f, 0.0, 100000.0, "Lowest frequency", "Cutoff frequency of a high-pass filter that is applied to the audio data", 0.1, 1000.00); diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 408c78d194e..50412952139 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -62,6 +62,7 @@ void graph_draw_ghost_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, str void GRAPH_OT_select_all_toggle(struct wmOperatorType *ot); void GRAPH_OT_select_border(struct wmOperatorType *ot); void GRAPH_OT_select_lasso(struct wmOperatorType *ot); +void GRAPH_OT_select_circle(struct wmOperatorType *ot); void GRAPH_OT_select_column(struct wmOperatorType *ot); void GRAPH_OT_select_linked(struct wmOperatorType *ot); void GRAPH_OT_select_more(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 62b6b59df29..da308d0b1f1 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -34,6 +34,7 @@ #include "DNA_scene_types.h" +#include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_base.h" @@ -200,6 +201,174 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Value", "", -100.0f, 100.0f); } +/* Hide/Reveal ------------------------------------------------------------ */ + +static int graphview_curves_hide_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + ListBase all_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + const bool unselected = RNA_boolean_get(op->ptr, "unselected"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get list of all channels that selection may need to be flushed to + * - hierarchy must not affect what we have access to here... + */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype); + + /* filter data + * - of the remaining visible curves, we want to hide the ones that are + * selected/unselected (depending on "unselected" prop) + */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); + if (unselected) + filter |= ANIMFILTER_UNSEL; + else + filter |= ANIMFILTER_SEL; + + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ + /* TODO: find out why this is the case, and fix that */ + if (ale->type == ANIMTYPE_OBJECT) + continue; + + /* change the hide setting, and unselect it... */ + ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR); + ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_CLEAR); + + /* now, also flush selection status up/down as appropriate */ + ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR); + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); + BLI_freelistN(&all_data); + + /* unhide selected */ + if (unselected) { + /* turn off requirement for visible */ + filter = ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_LIST_CHANNELS; + + /* flushing has been done */ + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ + /* TODO: find out why this is the case, and fix that */ + if (ale->type == ANIMTYPE_OBJECT) + continue; + + /* change the hide setting, and unselect it... */ + ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD); + ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + + /* now, also flush selection status up/down as appropriate */ + ANIM_flush_setting_anim_channels(&ac, &anim_data, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD); + } + ANIM_animdata_freelist(&anim_data); + } + + + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +static void GRAPH_OT_hide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Hide Curves"; + ot->idname = "GRAPH_OT_hide"; + ot->description = "Hide selected curves from Graph Editor view"; + + /* api callbacks */ + ot->exec = graphview_curves_hide_exec; + ot->poll = ED_operator_graphedit_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected curves"); +} + +/* ........ */ + +static int graphview_curves_reveal_exec(bContext *C, wmOperator *UNUSED(op)) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + ListBase all_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get list of all channels that selection may need to be flushed to + * - hierarchy must not affect what we have access to here... + */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype); + + /* filter data + * - just go through all visible channels, ensuring that everything is set to be curve-visible + */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + for (ale = anim_data.first; ale; ale = ale->next) { + /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ + /* TODO: find out why this is the case, and fix that */ + if (ale->type == ANIMTYPE_OBJECT) + continue; + + /* select if it is not visible */ + if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE) == 0) + ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + + /* change the visibility setting */ + ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD); + + /* now, also flush selection status up/down as appropriate */ + ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, true); + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); + BLI_freelistN(&all_data); + + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +static void GRAPH_OT_reveal(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Reveal Curves"; + ot->idname = "GRAPH_OT_reveal"; + ot->description = "Make previously hidden curves visible again in Graph Editor view"; + + /* api callbacks */ + ot->exec = graphview_curves_reveal_exec; + ot->poll = ED_operator_graphedit_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ************************** registration - operator types **********************************/ void graphedit_operatortypes(void) @@ -215,12 +384,16 @@ void graphedit_operatortypes(void) WM_operatortype_append(GRAPH_OT_ghost_curves_create); WM_operatortype_append(GRAPH_OT_ghost_curves_clear); + WM_operatortype_append(GRAPH_OT_hide); + WM_operatortype_append(GRAPH_OT_reveal); + /* keyframes */ /* selection */ WM_operatortype_append(GRAPH_OT_clickselect); WM_operatortype_append(GRAPH_OT_select_all_toggle); WM_operatortype_append(GRAPH_OT_select_border); WM_operatortype_append(GRAPH_OT_select_lasso); + WM_operatortype_append(GRAPH_OT_select_circle); WM_operatortype_append(GRAPH_OT_select_column); WM_operatortype_append(GRAPH_OT_select_linked); WM_operatortype_append(GRAPH_OT_select_more); @@ -359,6 +532,8 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "deselect", true); + WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0); + /* column select */ RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_KEYS); RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_CFRA); @@ -405,9 +580,13 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) /* copy/paste */ WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "flipped", true); #ifdef __APPLE__ WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0); WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0); + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_OSKEY | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "flipped", true); #endif /* auto-set range */ @@ -429,6 +608,19 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) /* transform system */ transform_keymap_for_space(keyconf, keymap, SPACE_IPO); + /* pivot point settings */ + kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); + RNA_string_set(kmi->ptr, "value", "BOUNDING_BOX_CENTER"); + + kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); + RNA_string_set(kmi->ptr, "value", "CURSOR"); + + kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_CTRL, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); + RNA_string_set(kmi->ptr, "value", "INDIVIDUAL_ORIGINS"); + /* special markers hotkeys for anim editors: see note in definition of this function */ ED_marker_keymap_animedit_conflictfree(keymap); } @@ -438,6 +630,7 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) void graphedit_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap; + wmKeyMapItem *kmi; /* keymap for all regions */ keymap = WM_keymap_find(keyconf, "Graph Editor Generic", SPACE_IPO, 0); @@ -448,7 +641,17 @@ void graphedit_keymap(wmKeyConfig *keyconf) /* find (i.e. a shortcut for setting the name filter) */ WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0); - + + /* hide/reveal selected curves */ + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_hide", HKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "unselected", false); + + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "unselected", true); + + WM_keymap_add_item(keymap, "GRAPH_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0); + + /* channels */ /* Channels are not directly handled by the Graph Editor module, but are inherited from the Animation module. * All the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as these diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 378139accbc..78dbae7618b 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -219,7 +219,7 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot) */ static void borderselect_graphkeys( bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, bool incl_handles, - struct KeyframeEdit_LassoData *data_lasso) + void *data) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -244,10 +244,16 @@ static void borderselect_graphkeys( /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); - if (data_lasso) { + if (mode == BEZT_OK_REGION_LASSO) { + struct KeyframeEdit_LassoData *data_lasso = data; data_lasso->rectf_scaled = &scaled_rectf; ked.data = data_lasso; } + else if (mode == BEZT_OK_REGION_CIRCLE) { + struct KeyframeEdit_CircleData *data_circle = data; + data_circle->rectf_scaled = &scaled_rectf; + ked.data = data; + } else { ked.data = &scaled_rectf; } @@ -485,6 +491,81 @@ void GRAPH_OT_select_lasso(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } +static int graph_circle_select_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + short selectmode; + bool incl_handles; + rctf rect_fl; + struct KeyframeEdit_CircleData data; + float x = RNA_int_get(op->ptr, "x"); + float y = RNA_int_get(op->ptr, "y"); + float radius = RNA_int_get(op->ptr, "radius"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data.mval[0] = x; + data.mval[1] = y; + data.radius_squared = radius * radius; + data.rectf_view = &rect_fl; + + if (gesture_mode == GESTURE_MODAL_SELECT) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + + rect_fl.xmin = x - radius; + rect_fl.xmax = x + radius; + rect_fl.ymin = y - radius; + rect_fl.ymax = y + radius; + + if (ac.spacetype == SPACE_IPO) { + SpaceIpo *sipo = (SpaceIpo *)ac.sl; + if (selectmode == SELECT_ADD) { + incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || + (sipo->flag & SIPO_NOHANDLES)) == 0; + } + else { + incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; + } + } + else { + incl_handles = false; + } + + /* apply borderselect action */ + borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void GRAPH_OT_select_circle(wmOperatorType *ot) +{ + ot->name = "Circle Select"; + ot->description = "Select keyframe points using circle selection"; + ot->idname = "GRAPH_OT_select_circle"; + + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = graph_circle_select_exec; + ot->poll = graphop_visible_keyframes_poll; + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX); + RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); +} + /* ******************** Column Select Operator **************************** */ /* This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index e9c8ae95acd..eea360ced45 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -40,7 +40,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_blenlib.h" #include "BKE_context.h" diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index be65cdb2d4f..05868283b2e 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -977,19 +977,9 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser } } -void image_buttons_register(ARegionType *art) +void image_buttons_register(ARegionType *UNUSED(art)) { - PanelType *pt; - const char *category = "Grease Pencil"; - - pt = MEM_callocN(sizeof(PanelType), "spacetype image panel gpencil"); - strcpy(pt->idname, "IMAGE_PT_gpencil"); - strcpy(pt->label, N_("Grease Pencil")); - strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw_header = ED_gpencil_panel_standard_header; - pt->draw = ED_gpencil_panel_standard; - BLI_strncpy(pt->category, category, BLI_strlen_utf8(category)); - BLI_addtail(&art->paneltypes, pt); + } static int image_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index f41e237beb4..7c5aa349fa0 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -854,8 +854,13 @@ void draw_image_main(const bContext *C, ARegion *ar) draw_render_info(sima->iuser.scene, ima, ar, zoomx, zoomy); } -static bool show_image_cache(Image *image, Mask *mask) +bool ED_space_image_show_cache(SpaceImage *sima) { + Image *image = ED_space_image(sima); + Mask *mask = NULL; + if (sima->mode == SI_MODE_MASK) { + mask = ED_space_image_get_mask(sima); + } if (image == NULL && mask == NULL) { return false; } @@ -873,12 +878,12 @@ void draw_image_cache(const bContext *C, ARegion *ar) float x, cfra = CFRA, sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1); Mask *mask = NULL; - if (sima->mode == SI_MODE_MASK) { - mask = ED_space_image_get_mask(sima); + if (!ED_space_image_show_cache(sima)) { + return; } - if (!show_image_cache(image, mask)) { - return; + if (sima->mode == SI_MODE_MASK) { + mask = ED_space_image_get_mask(sima); } glEnable(GL_BLEND); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 836ff25bddc..9d816853e8e 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -92,6 +92,8 @@ #include "PIL_time.h" +#include "RE_engine.h" + #include "image_intern.h" /******************** view navigation utilities *********************/ @@ -1052,6 +1054,7 @@ static int image_open_exec(bContext *C, wmOperator *op) char path[FILE_MAX]; int frame_seq_len = 0; int frame_ofs = 1; + bool exists = false; const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path"); @@ -1070,7 +1073,7 @@ static int image_open_exec(bContext *C, wmOperator *op) errno = 0; - ima = BKE_image_load_exists(path); + ima = BKE_image_load_exists_ex(path, &exists); if (!ima) { if (op->customdata) MEM_freeN(op->customdata); @@ -1084,8 +1087,9 @@ static int image_open_exec(bContext *C, wmOperator *op) /* only image path after save, never ibuf */ if (is_relative_path) { - const char *relbase = ID_BLEND_PATH(bmain, &ima->id); - BLI_path_rel(ima->name, relbase); + if (!exists) { + BLI_path_rel(ima->name, bmain->name); + } } /* hook into UI */ @@ -1127,7 +1131,7 @@ static int image_open_exec(bContext *C, wmOperator *op) } /* XXX unpackImage frees image buffers */ - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); BKE_image_signal(ima, iuser, IMA_SIGNAL_RELOAD); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); @@ -1203,7 +1207,7 @@ void IMAGE_OT_open(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); } @@ -1279,7 +1283,7 @@ static int image_replace_exec(bContext *C, wmOperator *op) sima->image->source = IMA_SRC_FILE; /* XXX unpackImage frees image buffers */ - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); BKE_icon_changed(BKE_icon_getid(&sima->image->id)); BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD); @@ -1322,7 +1326,7 @@ void IMAGE_OT_replace(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); } @@ -1732,7 +1736,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot) RNA_def_boolean(ot->srna, "save_as_render", 0, "Save As Render", "Apply render part of display transform when saving byte image"); RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender"); - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); } @@ -1880,7 +1884,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* XXX unpackImage frees image buffers */ - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); // XXX other users? BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD); @@ -2309,7 +2313,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save"); /* XXX unpackImage frees image buffers */ - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); unpackImage(op->reports, ima, method); @@ -2580,8 +2584,9 @@ static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event ImageSampleInfo *info; if (ar->regiontype == RGN_TYPE_WINDOW) { - if (event->mval[1] <= 16) + if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) { return OPERATOR_PASS_THROUGH; + } } if (!ED_space_image_has_buffer(sima)) @@ -3015,8 +3020,10 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event ARegion *ar = CTX_wm_region(C); if (ar->regiontype == RGN_TYPE_WINDOW) { - if (event->mval[1] > 16) + SpaceImage *sima = CTX_wm_space_image(C); + if (event->mval[1] > 16 || !ED_space_image_show_cache(sima)) { return OPERATOR_PASS_THROUGH; + } } RNA_int_set(op->ptr, "frame", frame_from_event(C, event)); @@ -3108,8 +3115,21 @@ static int render_border_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + Render *re = RE_GetRender(scene->id.name); + RenderData *rd; rctf border; + if (re == NULL) { + /* Shouldn't happen, but better be safe close to the release. */ + return OPERATOR_CANCELLED; + } + + rd = RE_engine_get_render_data(re); + if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) { + BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render"); + return OPERATOR_CANCELLED; + } + /* get rectangle from operator */ WM_operator_properties_border_to_rctf(op, &border); UI_view2d_region_to_view_rctf(&ar->v2d, &border, &border); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 5dc9af2de84..6cf53533618 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -356,7 +356,7 @@ static void image_keymap(struct wmKeyConfig *keyconf) static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) - if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ return 1; return 0; } @@ -797,7 +797,9 @@ static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion * /* context changes */ switch (wmn->category) { case NC_GPENCIL: - if (wmn->action == NA_EDITED) + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) + ED_region_tag_redraw(ar); + else if (wmn->data & ND_GPENCIL_EDITMODE) ED_region_tag_redraw(ar); break; case NC_IMAGE: @@ -860,6 +862,10 @@ static void image_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa) case NC_NODE: ED_region_tag_redraw(ar); break; + case NC_GPENCIL: + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) + ED_region_tag_redraw(ar); + break; } } @@ -908,7 +914,7 @@ static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), /* context changes */ switch (wmn->category) { case NC_GPENCIL: - if (wmn->data == ND_DATA) + if (wmn->data == ND_DATA || ELEM(wmn->action, NA_EDITED, NA_SELECTED)) ED_region_tag_redraw(ar); break; case NC_BRUSH: diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c index 86af89bd6a9..e2895109b48 100644 --- a/source/blender/editors/space_info/info_draw.c +++ b/source/blender/editors/space_info/info_draw.c @@ -33,7 +33,6 @@ #include <sys/stat.h> #include <limits.h> -#include "BLF_api.h" #include "BLI_utildefines.h" @@ -45,8 +44,6 @@ #include "BIF_gl.h" -#include "ED_datafiles.h" -#include "ED_types.h" #include "UI_resources.h" #include "UI_interface.h" diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index 33333e4c992..ebce13389c9 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -155,7 +155,7 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str MEM_freeN(offsets); return 1; } - else if (y_next - cdc->lheight < cdc->ymin) { + else if (y_next < cdc->ymin) { /* have not reached the drawable area so don't break */ cdc->xy[1] = y_next; diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c index 085fe68df92..e0cbc1c9539 100644 --- a/source/blender/editors/space_logic/logic_buttons.c +++ b/source/blender/editors/space_logic/logic_buttons.c @@ -34,7 +34,6 @@ #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_screen.h" #include "ED_screen.h" diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 5464449a94e..21a9246d7e6 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -96,11 +96,7 @@ static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisf static int vergname(const void *v1, const void *v2) { - char **x1, **x2; - - x1 = (char **)v1; - x2 = (char **)v2; - + const char * const *x1 = v1, * const *x2 = v2; return BLI_natstrcmp(*x1, *x2); } diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 89cfd389a9d..66023ce1243 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -143,6 +143,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p case ANIMTYPE_DSLAT: case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: { /* for these channels, we only do AnimData */ if (ale->adt && adt_ptr) { diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index fbb4d273626..0abe5e42c3e 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -182,6 +182,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe case ANIMTYPE_DSLAT: case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: { /* sanity checking... */ if (ale->adt) { diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 4cae820de89..ef3c3504a85 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -59,7 +59,6 @@ #include "WM_types.h" #include "UI_interface.h" -#include "UI_interface_icons.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -619,7 +618,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) /* *********************************************** */ /* Channel List */ -void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar) +void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index f43982fac8b..a883f350f1c 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1372,11 +1372,15 @@ static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op)) /* just flip the mute flag for now */ // TODO: have a pre-pass to check if mute all or unmute all? strip->flag ^= NLASTRIP_FLAG_MUTED; + + /* tag AnimData to get recalculated */ + ale->update |= ANIM_UPDATE_DEPS; } } } - /* free temp data */ + /* cleanup */ + ANIM_animdata_update(&ac, &anim_data); ANIM_animdata_freelist(&anim_data); /* set notifier that things have changed */ @@ -2130,9 +2134,13 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op) /* remove the meta-strips now that we're done */ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1); + + /* tag for recalculating the animation */ + ale->update |= ANIM_UPDATE_DEPS; } - /* free temp data */ + /* cleanup */ + ANIM_animdata_update(&ac, &anim_data); ANIM_animdata_freelist(&anim_data); /* refresh auto strip properties */ @@ -2246,6 +2254,7 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op) if (fcm) { set_active_fmodifier(&strip->modifiers, fcm); + ale->update |= ANIM_UPDATE_DEPS; } else { BKE_reportf(op->reports, RPT_ERROR, @@ -2256,6 +2265,7 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op) } /* free temp data */ + ANIM_animdata_update(&ac, &anim_data); ANIM_animdata_freelist(&anim_data); /* set notifier that things have changed */ @@ -2321,6 +2331,9 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op) } } + /* free temp data */ + ANIM_animdata_freelist(&anim_data); + /* successful or not? */ if (ok == 0) { BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied"); @@ -2375,10 +2388,12 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op) for (strip = nlt->strips.first; strip; strip = strip->next) { // TODO: do we want to replace existing modifiers? add user pref for that! ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0); + ale->update |= ANIM_UPDATE_DEPS; } } /* clean up */ + ANIM_animdata_update(&ac, &anim_data); ANIM_animdata_freelist(&anim_data); /* successful or not? */ diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index 766ae28da6f..bd96b5a4de5 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -50,7 +50,7 @@ void NLA_OT_properties(wmOperatorType *ot); /* nla_draw.c */ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar); -void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar); +void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar); /* **************************************** */ /* nla_select.c */ diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 5e1381db696..b3a875047db 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -28,15 +28,11 @@ * \ingroup spnla */ - #include <string.h> #include <stdio.h> #include "DNA_scene_types.h" - -#include "BLI_blenlib.h" - #include "BKE_context.h" #include "BKE_screen.h" diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index cc1d6002134..ec584525aeb 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -236,7 +236,7 @@ static void nla_channel_area_draw(const bContext *C, ARegion *ar) /* data */ if (ANIM_animdata_get_context(C, &ac)) { - draw_nla_channel_list((bContext *)C, &ac, ar); + draw_nla_channel_list(C, &ac, ar); } /* reset view matrix */ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index e0fe622d98d..c45626e4284 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -54,7 +54,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "ED_node.h" @@ -64,7 +63,6 @@ #include "UI_resources.h" #include "IMB_colormanagement.h" -#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "node_intern.h" /* own include */ @@ -781,8 +779,8 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); - uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); + uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) { uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE); diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 5805c11a438..b6fa4518ed6 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -29,8 +29,6 @@ * \ingroup spnode */ -#include <errno.h> - #include "MEM_guardedalloc.h" #include "DNA_node_types.h" @@ -227,7 +225,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) float insert_point[2]; /* always first */ - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); node_deselect_all(snode); @@ -304,33 +302,12 @@ static int node_add_file_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); bNode *node; - Image *ima = NULL; + Image *ima; int type = 0; - /* check input variables */ - if (RNA_struct_property_is_set(op->ptr, "filepath")) { - char path[FILE_MAX]; - RNA_string_get(op->ptr, "filepath", path); - - errno = 0; - - ima = BKE_image_load_exists(path); - - if (!ima) { - BKE_reportf(op->reports, RPT_ERROR, "Cannot read image '%s': %s", - path, errno ? strerror(errno) : TIP_("unsupported format")); - return OPERATOR_CANCELLED; - } - } - else if (RNA_struct_property_is_set(op->ptr, "name")) { - char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "name", name); - ima = (Image *)BKE_libblock_find_name(ID_IM, name); - - if (!ima) { - BKE_reportf(op->reports, RPT_ERROR, "Image '%s' not found", name); - return OPERATOR_CANCELLED; - } + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); + if (!ima) { + return OPERATOR_CANCELLED; } switch (snode->nodetree->type) { @@ -347,7 +324,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); node = node_add_node(C, NULL, type, snode->cursor[0], snode->cursor[1]); @@ -357,9 +334,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op) } node->id = (ID *)ima; - - BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); - WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); + + /* When adding new image file via drag-drop we need to load imbuf in order + * to get proper image source. + */ + if (RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); + } snode_notify(C, snode); snode_dag_update(C, snode); @@ -397,8 +379,8 @@ void NODE_OT_add_file(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE, - WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Datablock name to assign"); } @@ -426,7 +408,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); node = node_add_node(C, NULL, CMP_NODE_MASK, snode->cursor[0], snode->cursor[1]); @@ -471,8 +453,8 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) PointerRNA ptr, idptr; PropertyRNA *prop; const char *idname; - char _treename[MAX_ID_NAME - 2]; - char *treename = _treename; + char treename_buf[MAX_ID_NAME - 2]; + const char *treename; if (RNA_struct_property_is_set(op->ptr, "type")) { prop = RNA_struct_find_property(op->ptr, "type"); @@ -484,10 +466,11 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; if (RNA_struct_property_is_set(op->ptr, "name")) { - RNA_string_get(op->ptr, "name", treename); + RNA_string_get(op->ptr, "name", treename_buf); + treename = treename_buf; } else { - treename = (char *)DATA_("NodeTree"); + treename = DATA_("NodeTree"); } if (!ntreeTypeFind(idname)) { diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index 58d94a28226..76a096b8471 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -57,6 +57,7 @@ /* ******************* node space & buttons ************** */ +#if 0 /* poll for active nodetree */ static int active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt)) { @@ -64,6 +65,7 @@ static int active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt)) return (snode && snode->nodetree); } +#endif static int node_sockets_poll(const bContext *C, PanelType *UNUSED(pt)) { @@ -197,15 +199,6 @@ void node_buttons_register(ARegionType *art) pt->draw = node_tree_interface_panel; pt->poll = node_tree_interface_poll; BLI_addtail(&art->paneltypes, pt); - - pt = MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil"); - strcpy(pt->idname, "NODE_PT_gpencil"); - strcpy(pt->label, N_("Grease Pencil")); - strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw_header = ED_gpencil_panel_standard_header; - pt->draw = ED_gpencil_panel_standard; - pt->poll = active_nodetree_poll; - BLI_addtail(&art->paneltypes, pt); } static int node_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 42259a37f45..16ad63bcafa 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -66,7 +66,10 @@ #include "RNA_access.h" #include "node_intern.h" /* own include */ -#include "COM_compositor.h" + +#ifdef WITH_COMPOSITOR +# include "COM_compositor.h" +#endif /* XXX interface.h */ extern void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select); @@ -1130,6 +1133,9 @@ void node_update_nodetree(const bContext *C, bNodeTree *ntree) { bNode *node; + /* make sure socket "used" tags are correct, for displaying value buttons */ + ntreeTagUsedSockets(ntree); + /* update nodes front to back, so children sizes get updated before parents */ for (node = ntree->nodes.last; node; node = node->prev) { node_update(C, ntree, node); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index a16adb09b4f..1e258368b8b 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -31,7 +31,6 @@ #include "MEM_guardedalloc.h" -#include "DNA_action_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -73,8 +72,6 @@ #include "IMB_imbuf_types.h" #include "node_intern.h" /* own include */ -#include "NOD_common.h" -#include "NOD_socket.h" #include "NOD_composite.h" #include "NOD_shader.h" #include "NOD_texture.h" @@ -342,14 +339,22 @@ void snode_dag_update(bContext *C, SpaceNode *snode) void snode_notify(bContext *C, SpaceNode *snode) { + ID *id = snode->id; + WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL); - if (ED_node_is_shader(snode)) - WM_event_add_notifier(C, NC_MATERIAL | ND_NODES, snode->id); + if (ED_node_is_shader(snode)) { + if (GS(id->name) == ID_MA) + WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id); + else if (GS(id->name) == ID_LA) + WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id); + else if (GS(id->name) == ID_WO) + WM_main_add_notifier(NC_WORLD | ND_WORLD, id); + } else if (ED_node_is_compositor(snode)) - WM_event_add_notifier(C, NC_SCENE | ND_NODES, snode->id); + WM_event_add_notifier(C, NC_SCENE | ND_NODES, id); else if (ED_node_is_texture(snode)) - WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, snode->id); + WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id); } void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo) @@ -662,11 +667,16 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) /* if active texture changed, free glsl materials */ if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) { Material *ma; + World *wo; for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); + for (wo = bmain->world.first; wo; wo = wo->id.next) + if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree)) + GPU_material_free(&wo->gpumaterial); + WM_main_add_notifier(NC_IMAGE, NULL); } @@ -1142,7 +1152,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) bNodeLink *link, *newlink, *lastlink; const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); lastnode = ntree->nodes.last; for (node = ntree->nodes.first; node; node = node->next) { @@ -1277,7 +1287,7 @@ static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op)) Scene *curscene = CTX_data_scene(C), *scene; bNode *node; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); /* first tag scenes unread */ for (scene = bmain->scene.first; scene; scene = scene->id.next) @@ -1476,7 +1486,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op)) if ((snode == NULL) || (snode->edittree == NULL)) return OPERATOR_CANCELLED; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); node_flag_toggle_exec(snode, NODE_PREVIEW); @@ -1540,7 +1550,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) if ((snode == NULL) || (snode->edittree == NULL)) return OPERATOR_CANCELLED; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); /* Toggle for all selected nodes */ hidden = 0; @@ -1588,7 +1598,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode = CTX_wm_space_node(C); bNode *node; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); for (node = snode->edittree->nodes.first; node; node = node->next) { /* Only allow muting of nodes having a mute func! */ @@ -1626,7 +1636,7 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode = CTX_wm_space_node(C); bNode *node, *next; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); for (node = snode->edittree->nodes.first; node; node = next) { next = node->next; @@ -1667,7 +1677,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode = CTX_wm_space_node(C); bNode *node, *next; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); for (node = snode->edittree->nodes.first; node; node = next) { next = node->next; @@ -1924,7 +1934,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) bNode *node; bNodeLink *link, *newlink; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); /* clear current clipboard */ BKE_node_clipboard_clear(); @@ -2037,7 +2047,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) if (!all_nodes_valid) return OPERATOR_CANCELLED; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); /* deselect old nodes */ node_deselect_all(snode); @@ -2445,7 +2455,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op) void *lock; ImBuf *ibuf; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index de119cf04fb..b69808d4e81 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -55,7 +55,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -64,7 +63,6 @@ #include "node_intern.h" /* own include */ #include "NOD_common.h" -#include "NOD_socket.h" static int node_group_operator_active(bContext *C) { @@ -144,7 +142,7 @@ static int node_group_edit_exec(bContext *C, wmOperator *op) bNode *gnode; const bool exit = RNA_boolean_get(op->ptr, "exit"); - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); gnode = node_group_get_active(C, node_idname); @@ -352,7 +350,7 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op) const char *node_idname = group_node_idname(C); bNode *gnode; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); gnode = node_group_get_active(C, node_idname); if (!gnode) @@ -522,7 +520,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op) int type = RNA_enum_get(op->ptr, "type"); float offx, offy; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); /* are we inside of a group? */ ngroup = snode->edittree; @@ -915,7 +913,7 @@ static int node_group_make_exec(bContext *C, wmOperator *op) bNode *gnode; Main *bmain = CTX_data_main(C); - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); if (!node_group_make_test_selected(ntree, NULL, ntree_idname, op->reports)) return OPERATOR_CANCELLED; @@ -966,7 +964,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op) bNode *gnode; Main *bmain = CTX_data_main(C); - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); gnode = node_group_get_active(C, node_idname); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 8dfc2ac8e83..c8951a1172e 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -57,7 +57,6 @@ #include "BLF_translation.h" #include "node_intern.h" /* own include */ -#include "NOD_common.h" /* ****************** Add *********************** */ @@ -368,7 +367,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) if (!node) return OPERATOR_CANCELLED; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); if (node_link_viewer(C, node) == OPERATOR_CANCELLED) return OPERATOR_CANCELLED; @@ -747,7 +746,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]); - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); nldrag = node_link_init(snode, cursor, detach); @@ -803,7 +802,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); const bool replace = RNA_boolean_get(op->ptr, "replace"); - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); snode_autoconnect(snode, 1, replace); @@ -874,7 +873,7 @@ static int cut_links_exec(bContext *C, wmOperator *op) bool found = false; bNodeLink *link, *next; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); for (link = snode->edittree->links.first; link; link = next) { next = link->next; @@ -884,7 +883,8 @@ static int cut_links_exec(bContext *C, wmOperator *op) if (cut_links_intersect(link, mcoords, i)) { if (found == false) { - ED_preview_kill_jobs(C); + /* TODO(sergey): Why did we kill jobs twice? */ + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); found = true; } @@ -941,7 +941,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op)) bNodeTree *ntree = snode->edittree; bNode *node; - ED_preview_kill_jobs(C); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); for (node = ntree->nodes.first; node; node = node->next) { if (node->flag & SELECT) { diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index ab0619604a9..8b68ac013c2 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -30,7 +30,6 @@ #include "DNA_node_types.h" #include "DNA_screen_types.h" -#include "DNA_space_types.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -54,7 +53,6 @@ #include "ED_util.h" -#include "node_intern.h" /************************* Node Socket Manipulation **************************/ diff --git a/source/blender/editors/space_node/node_toolbar.c b/source/blender/editors/space_node/node_toolbar.c index dd5bad3f8ad..e3e263f2e44 100644 --- a/source/blender/editors/space_node/node_toolbar.c +++ b/source/blender/editors/space_node/node_toolbar.c @@ -28,27 +28,18 @@ * \ingroup nodes */ - -#include "MEM_guardedalloc.h" - #include "BLI_utildefines.h" #include "DNA_node_types.h" #include "BKE_context.h" -#include "BKE_node.h" #include "BKE_screen.h" #include "WM_api.h" #include "WM_types.h" -#include "RNA_access.h" - #include "ED_screen.h" -#include "UI_interface.h" -#include "UI_resources.h" - #include "node_intern.h" /* own include */ diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index e28c775ad88..e3baddef158 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -28,8 +28,6 @@ * \ingroup spnode */ - - #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -515,6 +513,11 @@ static void node_area_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn) ED_area_tag_refresh(sa); } break; + case NC_GPENCIL: + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) { + ED_area_tag_redraw(sa); + } + break; } } @@ -670,7 +673,7 @@ static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent * return 1; } else if (drag->type == WM_DRAG_PATH) { - if (ELEM(drag->icon, 0, ICON_FILE_IMAGE)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)) /* rule might not work? */ return 1; } return 0; @@ -699,9 +702,11 @@ static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); + RNA_struct_property_unset(drop->ptr, "filepath"); } - if (drag->path[0]) { + else if (drag->path[0]) { RNA_string_set(drop->ptr, "filepath", drag->path); + RNA_struct_property_unset(drop->ptr, "name"); } } @@ -768,6 +773,8 @@ static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi case NC_GPENCIL: if (wmn->action == NA_EDITED) ED_region_tag_redraw(ar); + else if (wmn->data & ND_GPENCIL_EDITMODE) + ED_region_tag_redraw(ar); break; } } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 61c4fe3cd02..9bc043b384e 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1018,6 +1018,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break; case eModifierType_LaplacianDeform: UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ + case eModifierType_DataTransfer: + UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break; case eModifierType_PointCache: UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ /* Default */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index d735b5e75cf..4f13454ef34 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -30,7 +30,6 @@ #include "DNA_space_types.h" -#include "BLI_utildefines.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 6f5bf712d55..23586a6a509 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -290,6 +290,10 @@ static eOLDrawState tree_element_active_material( } } if (set != OL_SETSEL_NONE) { + /* Tagging object for update seems a bit stupid here, but looks like we have to do it + * for render views to update. See T42973. + * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */ + DAG_id_tag_update((ID *)ob, OB_RECALC_OB); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); } return OL_DRAWSEL_NONE; diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index f8a90c942bc..4aa36da594b 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1371,59 +1371,42 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb) /* Filtering ----------------------------------------------- */ -static int outliner_filter_has_name(TreeElement *te, const char *name, int flags) +static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags) { -#if 0 - int found = 0; - - /* determine if match */ - if (flags & SO_FIND_CASE_SENSITIVE) { - if (flags & SO_FIND_COMPLETE) - found = strcmp(te->name, name) == 0; - else - found = strstr(te->name, name) != NULL; - } - else { - if (flags & SO_FIND_COMPLETE) - found = BLI_strcasecmp(te->name, name) == 0; - else - found = BLI_strcasestr(te->name, name) != NULL; - } -#else - int fn_flag = 0; - int found = 0; - + if ((flags & SO_FIND_CASE_SENSITIVE) == 0) fn_flag |= FNM_CASEFOLD; - if (flags & SO_FIND_COMPLETE) { - found = fnmatch(name, te->name, fn_flag) == 0; - } - else { - char fn_name[sizeof(((struct SpaceOops *)NULL)->search_string) + 2]; - BLI_snprintf(fn_name, sizeof(fn_name), "*%s*", name); - found = fnmatch(fn_name, te->name, fn_flag) == 0; - } - return found; -#endif + return fnmatch(name, te->name, fn_flag) == 0; } static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) { TreeElement *te, *ten; TreeStoreElem *tselem; - + char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2]; + char *search_string; + /* although we don't have any search string, we return true * since the entire tree is ok then... */ if (soops->search_string[0] == 0) return 1; + if (soops->search_flags & SO_FIND_COMPLETE) { + search_string = soops->search_string; + } + else { + /* Implicitly add heading/trailing wildcards if needed. */ + BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff)); + search_string = search_buff; + } + for (te = lb->first; te; te = ten) { ten = te->next; - if (0 == outliner_filter_has_name(te, soops->search_string, soops->search_flags)) { + if (!outliner_filter_has_name(te, search_string, soops->search_flags)) { /* item isn't something we're looking for, but... * - if the subtree is expanded, check if there are any matches that can be easily found * so that searching for "cu" in the default scene will still match the Cube @@ -1553,10 +1536,19 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) tselem = TREESTORE(ten); lib = (Library *)tselem->id; if (lib && lib->parent) { - BLI_remlink(&soops->tree, ten); par = (TreeElement *)lib->parent->id.newid; - BLI_addtail(&par->subtree, ten); - ten->parent = par; + if (tselem->id->flag & LIB_INDIRECT) { + /* Only remove from 'first level' if lib is not also directly used. */ + BLI_remlink(&soops->tree, ten); + BLI_addtail(&par->subtree, ten); + ten->parent = par; + } + else { + /* Else, make a new copy of the libtree for our parent. */ + TreeElement *dupten = outliner_add_element(soops, &par->subtree, lib, NULL, 0, 0); + outliner_add_library_contents(mainvar, soops, dupten, lib); + dupten->parent = par; + } } ten = nten; } diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c index 9077d0cf8ed..d265ae62db6 100644 --- a/source/blender/editors/space_script/script_edit.c +++ b/source/blender/editors/space_script/script_edit.c @@ -32,7 +32,6 @@ #include <string.h> #include <stdio.h> -#include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BKE_context.h" @@ -131,7 +130,7 @@ static int script_reload_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; #else - (void)C, (void)op; /* unused */ + UNUSED_VARS(C, op); return OPERATOR_CANCELLED; #endif } diff --git a/source/blender/editors/space_script/script_ops.c b/source/blender/editors/space_script/script_ops.c index 045df87d8db..41c07596a3b 100644 --- a/source/blender/editors/space_script/script_ops.c +++ b/source/blender/editors/space_script/script_ops.c @@ -32,19 +32,7 @@ #include <stdlib.h> #include <math.h> - -#include "DNA_screen_types.h" -#include "DNA_space_types.h" - -#include "BLI_math.h" -#include "BLI_blenlib.h" - -#include "BKE_context.h" - -#include "RNA_access.h" - #include "WM_api.h" -#include "WM_types.h" #include "script_intern.h" @@ -63,4 +51,3 @@ void script_keymap(wmKeyConfig *UNUSED(keyconf)) { /* Script space is deprecated, and doesn't need a keymap */ } - diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c index fd2cd268a27..759dcd3d0a4 100644 --- a/source/blender/editors/space_script/space_script.c +++ b/source/blender/editors/space_script/space_script.c @@ -35,7 +35,6 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "BLI_math.h" #include "BLI_utildefines.h" #include "BKE_context.h" @@ -53,7 +52,6 @@ #include "UI_view2d.h" #ifdef WITH_PYTHON -#include "BPY_extern.h" #endif #include "script_intern.h" // own include diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 4cf9c0c95c2..d9aff2781f0 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -43,6 +43,7 @@ set(SRC sequencer_edit.c sequencer_modifier.c sequencer_ops.c + sequencer_preview.c sequencer_scopes.c sequencer_select.c sequencer_view.c diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index a94ce52aca5..38a01bcd78c 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -40,7 +40,6 @@ #include "DNA_scene_types.h" #include "DNA_mask_types.h" -#include "BLF_translation.h" #include "BKE_context.h" #include "BKE_global.h" @@ -61,7 +60,6 @@ #include "ED_screen.h" #include "ED_sequencer.h" -#include "UI_view2d.h" #include "BKE_sound.h" @@ -626,7 +624,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel(ot, FOLDERFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie"); @@ -675,7 +673,7 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory"); @@ -774,7 +772,7 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); } diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c index d75eeca2c67..70c6da0bfb3 100644 --- a/source/blender/editors/space_sequencer/sequencer_buttons.c +++ b/source/blender/editors/space_sequencer/sequencer_buttons.c @@ -46,12 +46,12 @@ #include "WM_api.h" #include "WM_types.h" -#include "UI_interface.h" #include "sequencer_intern.h" /* **************************** buttons ********************************* */ +#if 0 static int sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNUSED(pt)) { SpaceSeq *sseq = CTX_wm_space_seq(C); @@ -59,9 +59,11 @@ static int sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNUS /* don't show the gpencil if we are not showing the image */ return ED_space_sequencer_check_show_imbuf(sseq); } +#endif -void sequencer_buttons_register(ARegionType *art) +void sequencer_buttons_register(ARegionType *UNUSED(art)) { +#if 0 PanelType *pt; pt = MEM_callocN(sizeof(PanelType), "spacetype sequencer panel gpencil"); @@ -72,6 +74,7 @@ void sequencer_buttons_register(ARegionType *art) pt->draw = ED_gpencil_panel_standard; pt->poll = sequencer_grease_pencil_panel_poll; BLI_addtail(&art->paneltypes, pt); +#endif } /* **************** operator to open/close properties view ************* */ diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 90ba1044677..afb650f8cfd 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -34,6 +34,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_threads.h" #include "IMB_imbuf_types.h" @@ -69,6 +70,7 @@ #include "WM_api.h" + /* own include */ #include "sequencer_intern.h" @@ -86,9 +88,9 @@ #undef SEQP_BEGIN #undef SEQ_END -static void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2); +static Sequence *special_seq_update = NULL; -static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[3]) +void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3]) { unsigned char blendcol[3]; SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; @@ -179,14 +181,14 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[ } } -static void drawseqwave(Scene *scene, Sequence *seq, float x1, float y1, float x2, float y2, float stepsize) +static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequence *seq, float x1, float y1, float x2, float y2, float stepsize) { /* * x1 is the starting x value to draw the wave, * x2 the end x value, same for y1 and y2 * stepsize is width of a pixel. */ - if (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM) { + if ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)) { int i, j, pos; int length = floor((x2 - x1) / stepsize) + 1; float ymid = (y1 + y2) / 2; @@ -194,20 +196,30 @@ static void drawseqwave(Scene *scene, Sequence *seq, float x1, float y1, float x float samplestep; float startsample, endsample; float value; - + bSound *sound = seq->sound; + SoundWaveform *waveform; - - if (!seq->sound->waveform) - sound_read_waveform(seq->sound); - - if (!seq->sound->waveform) - return; /* zero length sound */ - + + if (!sound->mutex) + sound->mutex = BLI_mutex_alloc(); + + BLI_mutex_lock(sound->mutex); + if (!seq->sound->waveform) { + if (!(sound->flags & SOUND_FLAGS_WAVEFORM_LOADING)) { + /* prevent sounds from reloading */ + seq->sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING; + BLI_mutex_unlock(sound->mutex); + sequencer_preview_add_sound(C, seq); + } + else { + BLI_mutex_unlock(sound->mutex); + } + return; /* nothing to draw */ + } + BLI_mutex_unlock(sound->mutex); + waveform = seq->sound->waveform; - - if (!waveform) - return; - + startsample = floor((seq->startofs + seq->anim_startofs) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND); endsample = ceil((seq->startofs + seq->anim_startofs + seq->enddisp - seq->startdisp) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND); samplestep = (endsample - startsample) * stepsize / (x2 - x1); @@ -303,7 +315,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE)) drawmeta_stipple(1); - get_seq_color3ubv(scene, seq, col); + color3ubv_from_seq(scene, seq, col); glColor4ubv(col); @@ -338,7 +350,7 @@ static float draw_seq_handle_size_get_clamped(Sequence *seq, const float pixelx) const float maxhandle = pixelx * SEQ_HANDLE_SIZE_MAX; float size = CLAMPIS(seq->handsize, minhandle, maxhandle); - /* ensure we're not greater then half width */ + /* ensure we're not greater than half width */ return min_ff(size, ((float)(seq->enddisp - seq->startdisp) / 2.0f) / pixelx); } @@ -422,112 +434,6 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla } } -static void draw_seq_extensions(Scene *scene, ARegion *ar, Sequence *seq) -{ - float x1, x2, y1, y2, pixely, a; - unsigned char col[3], blendcol[3]; - View2D *v2d = &ar->v2d; - - if (seq->type >= SEQ_TYPE_EFFECT) return; - - x1 = seq->startdisp; - x2 = seq->enddisp; - - y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; - y2 = seq->machine + SEQ_STRIP_OFSTOP; - - pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); - - if (pixely <= 0) return; /* can happen when the view is split/resized */ - - blendcol[0] = blendcol[1] = blendcol[2] = 120; - - if (seq->startofs) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - get_seq_color3ubv(scene, seq, col); - - if (seq->flag & SELECT) { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); - glColor4ub(col[0], col[1], col[2], 170); - } - else { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); - glColor4ub(col[0], col[1], col[2], 110); - } - - glRectf((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); - - if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); - else glColor4ub(col[0], col[1], col[2], 160); - - fdrawbox((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); //outline - - glDisable(GL_BLEND); - } - if (seq->endofs) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - get_seq_color3ubv(scene, seq, col); - - if (seq->flag & SELECT) { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); - glColor4ub(col[0], col[1], col[2], 170); - } - else { - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); - glColor4ub(col[0], col[1], col[2], 110); - } - - glRectf(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); - - if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); - else glColor4ub(col[0], col[1], col[2], 160); - - fdrawbox(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); //outline - - glDisable(GL_BLEND); - } - if (seq->startstill) { - get_seq_color3ubv(scene, seq, col); - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); - glColor3ubv((GLubyte *)col); - - draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2); - - /* feint pinstripes, helps see exactly which is extended and which isn't, - * especially when the extension is very small */ - if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24); - else UI_GetColorPtrShade3ubv(col, col, -16); - - glColor3ubv((GLubyte *)col); - - for (a = y1; a < y2; a += pixely * 2.0f) { - fdrawline(x1, a, (float)(seq->start), a); - } - } - if (seq->endstill) { - get_seq_color3ubv(scene, seq, col); - UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); - glColor3ubv((GLubyte *)col); - - draw_shadedstrip(seq, col, (float)(seq->start + seq->len), y1, x2, y2); - - /* feint pinstripes, helps see exactly which is extended and which isn't, - * especially when the extension is very small */ - if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, 24); - else UI_GetColorPtrShade3ubv(col, col, -16); - - glColor3ubv((GLubyte *)col); - - for (a = y1; a < y2; a += pixely * 2.0f) { - fdrawline((float)(seq->start + seq->len), a, x2, a); - } - } -} - /* draw info text on a sequence strip */ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float y1, float y2, const unsigned char background_col[3]) { @@ -634,7 +540,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float } /* draws a shaded strip, made from gradient + flat color + gradient */ -static void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2) +void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2) { float ymid1, ymid2; @@ -691,12 +597,117 @@ static void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, floa } } +void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq) +{ + float x1, x2, y1, y2, pixely, a; + unsigned char col[3], blendcol[3]; + View2D *v2d = &ar->v2d; + + x1 = seq->startdisp; + x2 = seq->enddisp; + + y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; + y2 = seq->machine + SEQ_STRIP_OFSTOP; + + pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); + + if (pixely <= 0) return; /* can happen when the view is split/resized */ + + blendcol[0] = blendcol[1] = blendcol[2] = 120; + + if (seq->startofs) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + color3ubv_from_seq(scene, seq, col); + + if (seq->flag & SELECT) { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); + glColor4ub(col[0], col[1], col[2], 170); + } + else { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); + glColor4ub(col[0], col[1], col[2], 110); + } + + glRectf((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); + + if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); + else glColor4ub(col[0], col[1], col[2], 160); + + fdrawbox((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); //outline + + glDisable(GL_BLEND); + } + if (seq->endofs) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + color3ubv_from_seq(scene, seq, col); + + if (seq->flag & SELECT) { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); + glColor4ub(col[0], col[1], col[2], 170); + } + else { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); + glColor4ub(col[0], col[1], col[2], 110); + } + + glRectf(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); + + if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); + else glColor4ub(col[0], col[1], col[2], 160); + + fdrawbox(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); //outline + + glDisable(GL_BLEND); + } + if (seq->startstill) { + color3ubv_from_seq(scene, seq, col); + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); + glColor3ubv((GLubyte *)col); + + draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2); + + /* feint pinstripes, helps see exactly which is extended and which isn't, + * especially when the extension is very small */ + if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24); + else UI_GetColorPtrShade3ubv(col, col, -16); + + glColor3ubv((GLubyte *)col); + + for (a = y1; a < y2; a += pixely * 2.0f) { + fdrawline(x1, a, (float)(seq->start), a); + } + } + if (seq->endstill) { + color3ubv_from_seq(scene, seq, col); + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); + glColor3ubv((GLubyte *)col); + + draw_shadedstrip(seq, col, (float)(seq->start + seq->len), y1, x2, y2); + + /* feint pinstripes, helps see exactly which is extended and which isn't, + * especially when the extension is very small */ + if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, 24); + else UI_GetColorPtrShade3ubv(col, col, -16); + + glColor3ubv((GLubyte *)col); + + for (a = y1; a < y2; a += pixely * 2.0f) { + fdrawline((float)(seq->start + seq->len), a, x2, a); + } + } +} + + /* * Draw a sequence strip, bounds check already made * ARegion is currently only used to get the windows width in pixels * so wave file sample drawing precision is zoom adjusted */ -static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline_tint, float pixelx) +static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, ARegion *ar, Sequence *seq, int outline_tint, float pixelx) { View2D *v2d = &ar->v2d; float x1, x2, y1, y2; @@ -714,8 +725,8 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline /* get the correct color per strip type*/ - //get_seq_color3ubv(scene, seq, col); - get_seq_color3ubv(scene, seq, background_col); + //color3ubv_from_seq(scene, seq, col); + color3ubv_from_seq(scene, seq, background_col); /* draw the main strip body */ if (is_single_image) { /* single image */ @@ -726,11 +737,13 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline else { /* normal operation */ draw_shadedstrip(seq, background_col, x1, y1, x2, y2); } - - /* draw additional info and controls */ - if (!is_single_image) - draw_seq_extensions(scene, ar, seq); - + + if (!is_single_image) { + if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { + draw_sequence_extensions(scene, ar, seq); + } + } + draw_seq_handle(v2d, seq, handsize_clamped, SEQ_LEFTHANDLE); draw_seq_handle(v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE); @@ -740,7 +753,9 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline /* draw sound wave */ if (seq->type == SEQ_TYPE_SOUND_RAM) { - drawseqwave(scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx); + if (!(sseq->flag & SEQ_NO_WAVEFORMS)) { + drawseqwave(C, sseq, scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx); + } } /* draw lock */ @@ -773,7 +788,7 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline glDisable(GL_POLYGON_STIPPLE); } - get_seq_color3ubv(scene, seq, col); + color3ubv_from_seq(scene, seq, col); if ((G.moving & G_TRANSFORM_SEQ) && (seq->flag & SELECT)) { if (seq->flag & SEQ_OVERLAP) { col[0] = 255; col[1] = col[2] = 40; @@ -817,19 +832,29 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline } } -static Sequence *special_seq_update = NULL; +void sequencer_special_update_set(Sequence *seq) +{ + special_seq_update = seq; +} -static void UNUSED_FUNCTION(set_special_seq_update) (int val) +Sequence *ED_sequencer_special_preview_get(void) { -// int x; + return special_seq_update; +} - /* if mouse over a sequence && LEFTMOUSE */ - if (val) { -// XXX special_seq_update = find_nearest_seq(&x); - } - else { - special_seq_update = NULL; - } +void ED_sequencer_special_preview_set(bContext *C, const int mval[2]) +{ + Scene *scene = CTX_data_scene(C); + ARegion *ar = CTX_wm_region(C); + int hand; + Sequence *seq; + seq = find_nearest_seq(scene, &ar->v2d, &hand, mval); + sequencer_special_update_set(seq); +} + +void ED_sequencer_special_preview_clear(void) +{ + sequencer_special_update_set(NULL); } ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs) @@ -842,9 +867,6 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int short is_break = G.is_break; render_size = sseq->render_size; - if (render_size == 99) { - render_size = 100; - } if (render_size == 0) { render_size = scene->r.size; } @@ -859,7 +881,10 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int rectx = (render_size * (float)scene->r.xsch) / 100.0f + 0.5f; recty = (render_size * (float)scene->r.ysch) / 100.0f + 0.5f; - context = BKE_sequencer_new_render_data(bmain->eval_ctx, bmain, scene, rectx, recty, proxy_size); + BKE_sequencer_new_render_data( + bmain->eval_ctx, bmain, scene, + rectx, recty, proxy_size, + &context); /* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled * by Esc pressed somewhere in the past @@ -924,7 +949,7 @@ static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scop return scope; } -void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay) +void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay, bool draw_backdrop) { struct Main *bmain = CTX_data_main(C); struct ImBuf *ibuf = NULL; @@ -980,7 +1005,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq viewrecty /= proxy_size / 100.0f; } - if (!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) { + if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_backdrop) { UI_GetThemeColor3fv(TH_SEQ_PREVIEW, col); glClearColor(col[0], col[1], col[2], 0.0); glClear(GL_COLOR_BUFFER_BIT); @@ -1055,23 +1080,25 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq /* without this colors can flicker from previous opengl state */ glColor4ub(255, 255, 255, 255); - UI_view2d_totRect_set(v2d, viewrectx + 0.5f, viewrecty + 0.5f); - UI_view2d_curRect_validate(v2d); - - /* setting up the view - actual drawing starts here */ - UI_view2d_view_ortho(v2d); - - /* only draw alpha for main buffer */ - if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { - if (sseq->flag & SEQ_USE_ALPHA) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax); - glColor4f(1.0, 1.0, 1.0, 1.0); + if (!draw_backdrop) { + UI_view2d_totRect_set(v2d, viewrectx + 0.5f, viewrecty + 0.5f); + UI_view2d_curRect_validate(v2d); + + /* setting up the view - actual drawing starts here */ + UI_view2d_view_ortho(v2d); + + /* only draw alpha for main buffer */ + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + if (sseq->flag & SEQ_USE_ALPHA) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax); + glColor4f(1.0, 1.0, 1.0, 1.0); + } } } - + if (scope) { IMB_freeImBuf(ibuf); ibuf = scope; @@ -1161,6 +1188,14 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, format, type, display_buffer); + if (draw_backdrop) { + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + } glBegin(GL_QUADS); if (draw_overlay) { @@ -1183,6 +1218,25 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin); } } + else if (draw_backdrop) { + float aspect = BLI_rcti_size_x(&ar->winrct) / (float)BLI_rcti_size_y(&ar->winrct); + float image_aspect = viewrectx / viewrecty; + float imagex, imagey; + + if (aspect >= image_aspect) { + imagex = image_aspect / aspect; + imagey = 1.0f; + } + else { + imagex = 1.0f; + imagey = aspect / image_aspect; + } + + glTexCoord2f(0.0f, 0.0f); glVertex2f(-imagex, -imagey); + glTexCoord2f(0.0f, 1.0f); glVertex2f(-imagex, imagey); + glTexCoord2f(1.0f, 1.0f); glVertex2f(imagex, imagey); + glTexCoord2f(1.0f, 0.0f); glVertex2f(imagex, -imagey); + } else { glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin); glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax); @@ -1190,6 +1244,15 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin); } glEnd(); + + if (draw_backdrop) { + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + } + glBindTexture(GL_TEXTURE_2D, last_texid); glDisable(GL_TEXTURE_2D); if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) @@ -1199,6 +1262,16 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq if (glsl_used) IMB_colormanagement_finish_glsl_draw(); + if (cache_handle) + IMB_display_buffer_release(cache_handle); + + if (!scope) + IMB_freeImBuf(ibuf); + + if (draw_backdrop) { + return; + } + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { float x1 = v2d->tot.xmin; @@ -1248,9 +1321,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq ED_gpencil_draw_2dimage(C); } } - - if (!scope) - IMB_freeImBuf(ibuf); /* ortho at pixel level */ UI_view2d_view_restore(C); @@ -1287,9 +1357,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq NULL, C); } } - - if (cache_handle) - IMB_display_buffer_release(cache_handle); } #if 0 @@ -1366,6 +1433,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar) { Scene *scene = CTX_data_scene(C); View2D *v2d = &ar->v2d; + SpaceSeq *sseq = CTX_wm_space_seq(C); Sequence *last_seq = BKE_sequencer_active_get(scene); int sel = 0, j; float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); @@ -1386,7 +1454,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar) else if (seq->machine > v2d->cur.ymax) continue; /* strip passed all tests unscathed... so draw it now */ - draw_seq_strip(scene, ar, seq, outline_tint, pixelx); + draw_seq_strip(C, sseq, scene, ar, seq, outline_tint, pixelx); } /* draw selected next time round */ @@ -1395,7 +1463,16 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar) /* draw the last selected last (i.e. 'active' in other parts of Blender), removes some overlapping error */ if (last_seq) - draw_seq_strip(scene, ar, last_seq, 120, pixelx); + draw_seq_strip(C, sseq, scene, ar, last_seq, 120, pixelx); + + /* draw highlight when previewing a single strip */ + if (special_seq_update) { + const Sequence *seq = special_seq_update; + glEnable(GL_BLEND); + glColor4ub(255, 255, 255, 48); + glRectf(seq->startdisp, seq->machine + SEQ_STRIP_OFSBOTTOM, seq->enddisp, seq->machine + SEQ_STRIP_OFSTOP); + glDisable(GL_BLEND); + } } static void seq_draw_sfra_efra(Scene *scene, View2D *v2d) @@ -1473,6 +1550,11 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) // NOTE: the gridlines are currently spaced every 25 frames, which is only fine for 25 fps, but maybe not for 30... UI_view2d_constant_grid_draw(v2d); + if (sseq->draw_flag & SEQ_DRAW_BACKDROP) { + draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, true); + UI_view2d_view_ortho(v2d); + } + ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); seq_draw_sfra_efra(scene, v2d); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 4ad521993be..81af6dccc70 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -49,7 +49,6 @@ #include "BKE_report.h" #include "BKE_sound.h" -#include "IMB_imbuf.h" #include "WM_api.h" #include "WM_types.h" @@ -62,9 +61,11 @@ #include "ED_screen.h" #include "ED_transform.h" #include "ED_sequencer.h" +#include "ED_space_api.h" #include "UI_view2d.h" + /* own include */ #include "sequencer_intern.h" @@ -179,6 +180,10 @@ static void seq_proxy_build_job(const bContext *C) LinkData *link; Sequence *seq; + if (ed == NULL) { + return; + } + wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies", WM_JOB_PROGRESS, WM_JOB_TYPE_SEQ_BUILD_PROXY); @@ -385,7 +390,7 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ displen = (float)abs(seq->startdisp - seq->enddisp); if (displen / pixelx > 16) { /* don't even try to grab the handles of small strips */ - /* Set the max value to handle to 1/3 of the total len when its less then 28. + /* Set the max value to handle to 1/3 of the total len when its less than 28. * This is important because otherwise selecting handles happens even when you click in the middle */ if ((displen / 3) < 30 * pixelx) { @@ -494,6 +499,13 @@ bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq) ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF)); } +bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq) +{ + return (ELEM(sseq->view, SEQ_VIEW_SEQUENCE, SEQ_VIEW_SEQUENCE_PREVIEW) && + ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF)); +} + + int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3, const char **error_str) { Editing *ed = BKE_sequencer_editing_get(scene, false); @@ -1129,7 +1141,7 @@ int sequencer_strip_has_path_poll(bContext *C) return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (SEQ_HAS_PATH(seq))); } -int sequencer_view_poll(bContext *C) +int sequencer_view_preview_poll(bContext *C) { SpaceSeq *sseq = CTX_wm_space_seq(C); Editing *ed = BKE_sequencer_editing_get(CTX_data_scene(C), false); @@ -1139,6 +1151,15 @@ int sequencer_view_poll(bContext *C) return 0; } +int sequencer_view_strips_poll(bContext *C) +{ + SpaceSeq *sseq = CTX_wm_space_seq(C); + if (sseq && ED_space_sequencer_check_show_strip(sseq)) + return 1; + + return 0; +} + /* snap operator*/ static int sequencer_snap_exec(bContext *C, wmOperator *op) { @@ -1231,7 +1252,6 @@ void SEQUENCER_OT_snap(struct wmOperatorType *ot) RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will be snapped", INT_MIN, INT_MAX); } - typedef struct SlipData { int init_mouse[2]; float init_mouseloc[2]; @@ -1241,6 +1261,7 @@ typedef struct SlipData { int num_seq; bool slow; int slow_offset; /* offset at the point where offset was turned on */ + void *draw_handle; } SlipData; static void transseq_backup(TransSeq *ts, Sequence *seq) @@ -1274,15 +1295,30 @@ static void transseq_restore(TransSeq *ts, Sequence *seq) seq->len = ts->len; } -static int slip_add_sequences_rec(ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool first_level) +static void draw_slip_extensions(const bContext *C, ARegion *ar, void *data) +{ + Scene *scene = CTX_data_scene(C); + SlipData *td = data; + int i; + + for (i = 0; i < td->num_seq; i++) { + Sequence *seq = td->seq_array[i]; + + if ((seq->type != SEQ_TYPE_META) && td->trim[i]) { + draw_sequence_extensions(scene, ar, seq); + } + } +} + +static int slip_add_sequences_rec(ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool do_trim) { Sequence *seq; int num_items = 0; for (seq = seqbasep->first; seq; seq = seq->next) { - if (!first_level || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) { + if (!do_trim || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) { seq_array[offset + num_items] = seq; - trim[offset + num_items] = first_level; + trim[offset + num_items] = do_trim; num_items++; if (seq->type == SEQ_TYPE_META) { @@ -1322,6 +1358,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve SlipData *data; Scene *scene = CTX_data_scene(C); Editing *ed = BKE_sequencer_editing_get(scene, false); + ARegion *ar = CTX_wm_region(C); float mouseloc[2]; int num_seq, i; View2D *v2d = UI_view2d_fromcontext(C); @@ -1344,6 +1381,8 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve transseq_backup(data->ts + i, data->seq_array[i]); } + data->draw_handle = ED_region_draw_cb_activate(ar->type, draw_slip_extensions, data, REGION_DRAW_POST_VIEW); + UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]); copy_v2_v2_int(data->init_mouse, event->mval); @@ -1353,6 +1392,9 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve WM_event_add_modal_handler(C, op); + /* notify so we draw extensions immediately */ + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_RUNNING_MODAL; } @@ -1463,6 +1505,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even Scene *scene = CTX_data_scene(C); SlipData *data = (SlipData *)op->customdata; ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); switch (event->type) { case MOUSEMOVE: @@ -1504,6 +1547,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even case LEFTMOUSE: { + ED_region_draw_cb_exit(ar->type, data->draw_handle); MEM_freeN(data->seq_array); MEM_freeN(data->trim); MEM_freeN(data->ts); @@ -1532,6 +1576,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even BKE_sequence_calc(scene, seq); } + ED_region_draw_cb_exit(ar->type, data->draw_handle); + MEM_freeN(data->seq_array); MEM_freeN(data->ts); MEM_freeN(data->trim); @@ -1587,7 +1633,6 @@ void SEQUENCER_OT_slip(struct wmOperatorType *ot) INT32_MIN, INT32_MAX); } - /* mute operator */ static int sequencer_mute_exec(bContext *C, wmOperator *op) { @@ -2810,74 +2855,13 @@ void SEQUENCER_OT_view_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } - -static int find_next_prev_edit(Scene *scene, int cfra, - const short side, - const bool do_skip_mute, const bool do_center) -{ - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq; - - int dist, best_dist, best_frame = cfra; - int seq_frames[2], seq_frames_tot; - - best_dist = MAXFRAME * 2; - - if (ed == NULL) return cfra; - - for (seq = ed->seqbasep->first; seq; seq = seq->next) { - int i; - - if (do_skip_mute && (seq->flag & SEQ_MUTE)) { - continue; - } - - if (do_center) { - seq_frames[0] = (seq->startdisp + seq->enddisp) / 2; - seq_frames_tot = 1; - } - else { - seq_frames[0] = seq->startdisp; - seq_frames[1] = seq->enddisp; - - seq_frames_tot = 2; - } - - for (i = 0; i < seq_frames_tot; i++) { - const int seq_frame = seq_frames[i]; - - dist = MAXFRAME * 2; - - switch (side) { - case SEQ_SIDE_LEFT: - if (seq_frame < cfra) { - dist = cfra - seq_frame; - } - break; - case SEQ_SIDE_RIGHT: - if (seq_frame > cfra) { - dist = seq_frame - cfra; - } - break; - } - - if (dist < best_dist) { - best_frame = seq_frame; - best_dist = dist; - } - } - } - - return best_frame; -} - static bool strip_jump_internal(Scene *scene, const short side, const bool do_skip_mute, const bool do_center) { bool changed = false; int cfra = CFRA; - int nfra = find_next_prev_edit(scene, cfra, side, do_skip_mute, do_center); + int nfra = BKE_sequencer_find_next_prev_edit(scene, cfra, side, do_skip_mute, do_center, false); if (nfra != cfra) { CFRA = nfra; @@ -3350,7 +3334,7 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot) ot->invoke = WM_border_select_invoke; ot->exec = view_ghost_border_exec; ot->modal = WM_border_select_modal; - ot->poll = sequencer_view_poll; + ot->poll = sequencer_view_preview_poll; ot->cancel = WM_border_select_cancel; /* flags */ @@ -3361,13 +3345,43 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot) } /* rebuild_proxy operator */ -static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) + +static int sequencer_rebuild_proxy_invoke(bContext *C, wmOperator *UNUSED(op), + const wmEvent *UNUSED(event)) { seq_proxy_build_job(C); return OPERATOR_FINISHED; } +static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq; + + if (ed == NULL) { + return OPERATOR_CANCELLED; + } + + SEQP_BEGIN(ed, seq) + { + if ((seq->flag & SELECT)) { + struct SeqIndexBuildContext *context; + short stop = 0, do_update; + float progress; + context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq); + BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress); + BKE_sequencer_proxy_rebuild_finish(context, 0); + BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + } + } + SEQ_END + + return OPERATOR_FINISHED; +} + void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot) { /* identifiers */ @@ -3376,8 +3390,8 @@ void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot) ot->description = "Rebuild all selected proxies and timecode indices using the job system"; /* api callbacks */ + ot->invoke = sequencer_rebuild_proxy_invoke; ot->exec = sequencer_rebuild_proxy_exec; - ot->poll = ED_operator_sequencer_active; /* flags */ ot->flag = OPTYPE_REGISTER; @@ -3619,8 +3633,7 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); } - diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 438696d0327..5f1c9317fd9 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -45,6 +45,7 @@ struct ARegion; struct ARegionType; struct Scene; struct Main; +struct SequencePreview; /* space_sequencer.c */ struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa); @@ -52,7 +53,12 @@ struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa); /* sequencer_draw.c */ void draw_timeline_seq(const struct bContext *C, struct ARegion *ar); -void draw_image_seq(const struct bContext *C, struct Scene *scene, struct ARegion *ar, struct SpaceSeq *sseq, int cfra, int offset, bool draw_overlay); +void draw_image_seq(const struct bContext *C, struct Scene *scene, struct ARegion *ar, struct SpaceSeq *sseq, int cfra, int offset, bool draw_overlay, bool draw_backdrop); +void color3ubv_from_seq(struct Scene *curscene, struct Sequence *seq, unsigned char col[3]); +void draw_shadedstrip(struct Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2); +void draw_sequence_extensions(struct Scene *scene, struct ARegion *ar, struct Sequence *seq); + +void sequencer_special_update_set(Sequence *seq); /* UNUSED */ // void seq_reset_imageofs(struct SpaceSeq *sseq); @@ -73,7 +79,8 @@ int sequencer_edit_poll(struct bContext *C); /* UNUSED */ //int sequencer_strip_poll(struct bContext *C); int sequencer_strip_has_path_poll(struct bContext *C); -int sequencer_view_poll(struct bContext *C); +int sequencer_view_preview_poll(struct bContext *C); +int sequencer_view_strips_poll(struct bContext *C); /* externs */ extern EnumPropertyItem sequencer_prop_effect_types[]; @@ -150,13 +157,6 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot); void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot); void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot); -/* RNA enums, just to be more readable */ -enum { - SEQ_SIDE_NONE = 0, - SEQ_SIDE_LEFT, - SEQ_SIDE_RIGHT, - SEQ_SIDE_BOTH -}; enum { SEQ_CUT_SOFT, SEQ_CUT_HARD @@ -199,5 +199,8 @@ void SEQUENCER_OT_strip_modifier_move(struct wmOperatorType *ot); /* sequencer_view.c */ void SEQUENCER_OT_sample(struct wmOperatorType *ot); +/* sequencer_preview.c */ +void sequencer_preview_add_sound(const struct bContext *C, struct Sequence *seq); + #endif /* __SEQUENCER_INTERN_H__ */ diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c index ff40bf1e638..83f3f9bc961 100644 --- a/source/blender/editors/space_sequencer/sequencer_modifier.c +++ b/source/blender/editors/space_sequencer/sequencer_modifier.c @@ -29,24 +29,14 @@ * \ingroup spseq */ -#include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "BLI_math.h" #include "BLI_utildefines.h" #include "DNA_scene_types.h" -#include "DNA_mask_types.h" -#include "DNA_userdef_types.h" #include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_library.h" -#include "BKE_main.h" #include "BKE_sequencer.h" -#include "BKE_movieclip.h" -#include "BKE_mask.h" -#include "BKE_report.h" #include "WM_api.h" #include "WM_types.h" @@ -54,8 +44,6 @@ #include "RNA_define.h" #include "RNA_enum_types.h" -#include "UI_interface.h" -#include "UI_resources.h" /* own include */ #include "sequencer_intern.h" diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index 88646b55e23..9b5ef18f7cd 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -40,6 +40,8 @@ #include "ED_markers.h" #include "ED_transform.h" /* transform keymap */ +#include "BKE_sequencer.h" + #include "sequencer_intern.h" diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c new file mode 100644 index 00000000000..da00b0ff6e1 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_preview.c @@ -0,0 +1,172 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2003-2009, Antony Riakiotakis + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_sequencer/sequencer_preview.c + * \ingroup spseq + */ + +#include "DNA_sequence_types.h" +#include "DNA_sound_types.h" + +#include "BLI_listbase.h" +#include "BLI_threads.h" + +#include "BKE_sound.h" +#include "BKE_context.h" +#include "BKE_global.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" + +#include "MEM_guardedalloc.h" + +#include "sequencer_intern.h" + +typedef struct PreviewJob { + ListBase previews; + ThreadMutex *mutex; + Scene *scene; + int total; + int processed; +} PreviewJob; + +typedef struct PreviewJobAudio { + struct PreviewJobAudio *next, *prev; + bSound *sound; + int lr; /* sample left or right */ + int startframe; + bool waveform; /* reload sound or waveform */ +} PreviewJobAudio; + +static void free_preview_job(void *data) +{ + PreviewJob *pj = (PreviewJob *)data; + + BLI_mutex_free(pj->mutex); + BLI_freelistN(&pj->previews); + MEM_freeN(pj); +} + +/* only this runs inside thread */ +static void preview_startjob(void *data, short *stop, short *do_update, float *progress) +{ + PreviewJob *pj = data; + PreviewJobAudio *previewjb; + + BLI_mutex_lock(pj->mutex); + previewjb = pj->previews.first; + BLI_mutex_unlock(pj->mutex); + + while (previewjb) { + PreviewJobAudio *preview_next; + bSound *sound = previewjb->sound; + + sound_read_waveform(sound, stop); + + if (*stop || G.is_break) { + BLI_mutex_lock(pj->mutex); + previewjb = previewjb->next; + BLI_mutex_unlock(pj->mutex); + while (previewjb) { + sound = previewjb->sound; + + /* make sure we cleanup the loading flag! */ + BLI_mutex_lock(sound->mutex); + sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + BLI_mutex_unlock(sound->mutex); + + BLI_mutex_lock(pj->mutex); + previewjb = previewjb->next; + BLI_mutex_unlock(pj->mutex); + } + + BLI_mutex_lock(pj->mutex); + BLI_freelistN(&pj->previews); + pj->total = 0; + pj->processed = 0; + BLI_mutex_unlock(pj->mutex); + break; + } + + BLI_mutex_lock(pj->mutex); + preview_next = previewjb->next; + BLI_freelinkN(&pj->previews, previewjb); + previewjb = preview_next; + pj->processed++; + *progress = (pj->total > 0) ? (float)pj->processed / (float)pj->total : 1.0; + *do_update = true; + BLI_mutex_unlock(pj->mutex); + } +} + +static void preview_endjob(void *data) +{ + PreviewJob *pj = data; + + WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene); +} + + +void sequencer_preview_add_sound(const bContext *C, Sequence *seq) +{ + /* first, get the preview job, if it exists */ + wmJob *wm_job; + PreviewJob *pj; + ScrArea *sa = CTX_wm_area(C); + PreviewJobAudio *audiojob = MEM_callocN(sizeof(PreviewJobAudio), "preview_audio"); + wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Strip Previews", + WM_JOB_PROGRESS, WM_JOB_TYPE_SEQ_BUILD_PREVIEW); + + pj = WM_jobs_customdata_get(wm_job); + + if (!pj) { + pj = MEM_callocN(sizeof(PreviewJob), "preview rebuild job"); + + pj->mutex = BLI_mutex_alloc(); + pj->scene = CTX_data_scene(C); + + WM_jobs_customdata_set(wm_job, pj, free_preview_job); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER); + WM_jobs_callbacks(wm_job, preview_startjob, NULL, NULL, preview_endjob); + } + + /* attempt to lock mutex of job here */ + + audiojob->sound = seq->sound; + + BLI_mutex_lock(pj->mutex); + BLI_addtail(&pj->previews, audiojob); + pj->total++; + BLI_mutex_unlock(pj->mutex); + + if (!WM_jobs_is_running(wm_job)) { + G.is_break = false; + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + + ED_area_tag_redraw(sa); +} diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index 9b3b9f23036..24b3776da6d 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -55,7 +55,7 @@ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3]) static void scope_put_pixel(unsigned char *table, unsigned char *pos) { - char newval = table[*pos]; + unsigned char newval = table[*pos]; pos[0] = pos[1] = pos[2] = newval; pos[3] = 255; } @@ -148,8 +148,8 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); int x, y; - unsigned char *src = (unsigned char *) ibuf->rect; - unsigned char *tgt = (unsigned char *) rval->rect; + const unsigned char *src = (unsigned char *)ibuf->rect; + unsigned char *tgt = (unsigned char *)rval->rect; int w = ibuf->x + 3; int h = 515; float waveform_gamma = 0.2; @@ -166,7 +166,7 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) unsigned char *last_p = NULL; for (x = 0; x < ibuf->x; x++) { - unsigned char *rgb = src + 4 * (ibuf->x * y + x); + const unsigned char *rgb = src + 4 * (ibuf->x * y + x); float v = (float)rgb_to_luma_byte(rgb) / 255.0f; unsigned char *p = tgt; p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1); @@ -189,7 +189,7 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); int x, y; - float *src = ibuf->rect_float; + const float *src = ibuf->rect_float; unsigned char *tgt = (unsigned char *) rval->rect; int w = ibuf->x + 3; int h = 515; @@ -245,8 +245,8 @@ static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); int x, y; - unsigned char *src = (unsigned char *) ibuf->rect; - unsigned char *tgt = (unsigned char *) rval->rect; + const unsigned char *src = (const unsigned char *)ibuf->rect; + unsigned char *tgt = (unsigned char *)rval->rect; int w = ibuf->x + 3; int sw = ibuf->x / 3; int h = 515; @@ -264,7 +264,7 @@ static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf) for (x = 0; x < ibuf->x; x++) { int c; - unsigned char *rgb = src + 4 * (ibuf->x * y + x); + const unsigned char *rgb = src + 4 * (ibuf->x * y + x); for (c = 0; c < 3; c++) { unsigned char *p = tgt; p += 4 * (w * ((rgb[c] * (h - 3)) / 255 + 1) + c * sw + x / 3 + 1); @@ -290,8 +290,8 @@ static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); int x, y; - float *src = ibuf->rect_float; - unsigned char *tgt = (unsigned char *) rval->rect; + const float *src = ibuf->rect_float; + unsigned char *tgt = (unsigned char *)rval->rect; int w = ibuf->x + 3; int sw = ibuf->x / 3; int h = 515; @@ -455,7 +455,7 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); int x, y; unsigned int nr, ng, nb; - unsigned char *src = (unsigned char *) ibuf->rect; + const unsigned char *src = (unsigned char *)ibuf->rect; unsigned int bins[3][HIS_STEPS]; @@ -468,7 +468,7 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) memset(cur_bins, 0, sizeof(cur_bins)); for (x = 0; x < ibuf->x; x++) { - unsigned char *pixel = src + (y * ibuf->x + x) * 4; + const unsigned char *pixel = src + (y * ibuf->x + x) * 4; cur_bins[0][pixel[0]]++; cur_bins[1][pixel[1]]++; @@ -532,7 +532,7 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); int nr, ng, nb, x, y; - float *src = ibuf->rect_float; + const float *src = ibuf->rect_float; unsigned int bins[3][HIS_STEPS]; @@ -635,7 +635,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect); int x, y; - char *src = (char *) ibuf->rect; + const char *src = (const char *) ibuf->rect; char *tgt = (char *) rval->rect; float rgb[3], yuv[3]; int w = 515; @@ -659,7 +659,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf) for (y = 0; y < ibuf->y; y++) { for (x = 0; x < ibuf->x; x++) { const char *src1 = src + 4 * (ibuf->x * y + x); - const char *p; + char *p; rgb[0] = (float)src1[0] / 255.0f; rgb[1] = (float)src1[1] / 255.0f; @@ -681,7 +681,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect); int x, y; - float *src = ibuf->rect_float; + const float *src = ibuf->rect_float; char *tgt = (char *) rval->rect; float rgb[3], yuv[3]; int w = 515; diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 933daf4adee..6792bbe0577 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -357,25 +357,22 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e case SEQ_SELECT_LR_MOUSE: x = UI_view2d_region_to_view_x(v2d, event->mval[0]); break; - case SEQ_SELECT_LR_LEFT: - x = CFRA - 1; - break; case SEQ_SELECT_LR_RIGHT: - x = CFRA + 1; + x = CFRA; break; } SEQP_BEGIN (ed, seq) { if (x < CFRA) { - if (seq->enddisp < CFRA) { + if (seq->enddisp <= CFRA) { seq->flag |= SELECT; recurs_sel_seq(seq); } } else { - if (seq->startdisp > CFRA) { + if (seq->startdisp >= CFRA) { seq->flag |= SELECT; recurs_sel_seq(seq); } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index c0cfaed7867..6231f02907a 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -328,7 +328,7 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl) SpaceSeq *sseqn = MEM_dupallocN(sl); /* clear or remove stuff from old */ -// XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd); +// XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd, false); memset(&sseqn->scopes, 0, sizeof(sseqn->scopes)); @@ -352,6 +352,10 @@ static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn if (wmn->data == ND_SPACE_SEQUENCER) sequencer_scopes_tag_refresh(sa); break; + case NC_GPENCIL: + if (wmn->data & ND_GPENCIL_EDITMODE) + ED_area_tag_redraw(sa); + break; } } @@ -559,7 +563,7 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar) if (sseq->mainb == SEQ_DRAW_SEQUENCE) sseq->mainb = SEQ_DRAW_IMG_IMBUF; if (!show_split || sseq->overlay_type != SEQ_DRAW_OVERLAY_REFERENCE) - draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false); + draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, false); if (show_split && sseq->overlay_type != SEQ_DRAW_OVERLAY_CURRENT) { int over_cfra; @@ -570,7 +574,7 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar) over_cfra = scene->r.cfra + scene->ed->over_ofs; if (over_cfra != scene->r.cfra || sseq->overlay_type != SEQ_DRAW_OVERLAY_RECT) - draw_image_seq(C, scene, ar, sseq, scene->r.cfra, over_cfra - scene->r.cfra, true); + draw_image_seq(C, scene, ar, sseq, scene->r.cfra, over_cfra - scene->r.cfra, true, false); } if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_playing(wm)) { @@ -585,7 +589,7 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED /* context changes */ switch (wmn->category) { case NC_GPENCIL: - if (wmn->action == NA_EDITED) { + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) { ED_region_tag_redraw(ar); } break; @@ -641,7 +645,7 @@ static void sequencer_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED /* context changes */ switch (wmn->category) { case NC_GPENCIL: - if (wmn->data == ND_DATA) { + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) { ED_region_tag_redraw(ar); } break; diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index c8ca4e1a7da..31662c02966 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -44,6 +44,8 @@ #include "BKE_text.h" #include "BKE_screen.h" +#include "ED_text.h" + #include "BIF_gl.h" #include "UI_interface.h" @@ -380,7 +382,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w int a, fstart, fpos; /* utf8 chars */ int mi, ma, mstart, mend; /* mem */ char fmt_prev = 0xff; - + /* don't draw lines below this */ + const int clip_min_y = -(int)(st->lheight_dpi - 1); + flatten_string(st, &fs, str); str = fs.buf; max = w / st->cwidth; @@ -423,7 +427,8 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; end = (wrap += max - padding); - if (y <= 0) break; + if (y <= clip_min_y) + break; } else if (str[mi] == ' ' || str[mi] == '-') { wrap = i + 1; mend = mi + 1; @@ -431,7 +436,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w } /* Draw the remaining text */ - for (a = fstart, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) { + for (a = fstart, ma = mstart; str[ma] && y > clip_min_y; a++, ma += BLI_str_utf8_size_safe(str + ma)) { if (use_syntax) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } @@ -1322,6 +1327,8 @@ void draw_text_main(SpaceText *st, ARegion *ar) int i, x, y, winx, linecount = 0, lineno = 0; int wraplinecount = 0, wrap_skip = 0; int margin_column_x; + /* don't draw lines below this */ + const int clip_min_y = -(int)(st->lheight_dpi - 1); /* if no text, nothing to do */ if (!text) @@ -1329,7 +1336,7 @@ void draw_text_main(SpaceText *st, ARegion *ar) /* dpi controlled line height and font size */ st->lheight_dpi = (U.widget_unit * st->lheight) / 20; - st->viewlines = (st->lheight_dpi) ? (int)ar->winy / (st->lheight_dpi + TXT_LINE_SPACING) : 0; + st->viewlines = (st->lheight_dpi) ? (int)(ar->winy - clip_min_y) / (st->lheight_dpi + TXT_LINE_SPACING) : 0; text_update_drawcache(st, ar); @@ -1393,7 +1400,7 @@ void draw_text_main(SpaceText *st, ARegion *ar) /* draw the text */ UI_ThemeColor(TH_TEXT); - for (i = 0; y > 0 && i < st->viewlines && tmp; i++, tmp = tmp->next) { + for (i = 0; y > clip_min_y && i < st->viewlines && tmp; i++, tmp = tmp->next) { if (st->showsyntax && !tmp->format) tft->format_line(st, tmp, false); @@ -1542,3 +1549,37 @@ void text_update_cursor_moved(bContext *C) text_scroll_to_cursor__area(st, sa, true); } + +/** + * Takes a cursor (row, character) and returns x,y pixel coords. + */ +bool ED_text_region_location_from_cursor(SpaceText *st, ARegion *ar, const int cursor_co[2], int r_pixel_co[2]) +{ + TextLine *line = NULL; + + if (!st->text) { + goto error; + } + + line = BLI_findlink(&st->text->lines, cursor_co[0]); + if (!line || (cursor_co[1] < 0) || (cursor_co[1] > line->len)) { + goto error; + } + else { + int offl, offc; + int linenr_offset = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET; + /* handle tabs as well! */ + int char_pos = text_get_char_pos(st, line->line, cursor_co[1]); + + wrap_offset(st, ar, line, cursor_co[1], &offl, &offc); + r_pixel_co[0] = (char_pos + offc - st->left) * st->cwidth + linenr_offset; + r_pixel_co[1] = (cursor_co[0] + offl - st->top) * (st->lheight_dpi + TXT_LINE_SPACING); + r_pixel_co[1] = (ar->winy - (r_pixel_co[1] + TXT_OFFSET)) - st->lheight_dpi; + } + return true; + + +error: + r_pixel_co[0] = r_pixel_co[1] = -1; + return false; +} diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c index 02bac251065..92a3cce12e6 100644 --- a/source/blender/editors/space_text/text_header.c +++ b/source/blender/editors/space_text/text_header.c @@ -34,7 +34,6 @@ #include "BLI_blenlib.h" -#include "BLF_translation.h" #include "BKE_context.h" #include "BKE_screen.h" diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index 5483cf04db7..f577714c480 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -50,8 +50,8 @@ void draw_text_main(struct SpaceText *st, struct ARegion *ar); void text_update_line_edited(struct TextLine *line); void text_update_edited(struct Text *text); void text_update_character_width(struct SpaceText *st); -void text_scroll_to_cursor(struct SpaceText *st, struct ARegion *ar, bool center); -void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *sa, bool center); +void text_scroll_to_cursor(struct SpaceText *st, struct ARegion *ar, const bool center); +void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *sa, const bool center); void text_update_cursor_moved(struct bContext *C); #define TXT_OFFSET ((int)(0.5f * U.widget_unit)) diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index ffabefdfb29..1cf0316aa06 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -300,7 +300,7 @@ void TEXT_OT_open(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE | PYSCRIPTFILE, FILE_SPECIAL, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path RNA_def_boolean(ot->srna, "internal", 0, "Make internal", "Make text file internal after loading"); } @@ -577,7 +577,7 @@ void TEXT_OT_save_as(wmOperatorType *ot) ot->poll = text_edit_poll; /* properties */ - WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE | PYSCRIPTFILE, FILE_SPECIAL, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path } @@ -714,88 +714,6 @@ void TEXT_OT_refresh_pyconstraints(wmOperatorType *ot) /******************* paste operator *********************/ -static char *txt_copy_selected(Text *text) -{ - TextLine *tmp, *linef, *linel; - char *buf = NULL; - int charf, charl, length = 0; - - if (!text) return NULL; - if (!text->curl) return NULL; - if (!text->sell) return NULL; - - if (!txt_has_sel(text)) return NULL; - - if (text->curl == text->sell) { - linef = linel = text->curl; - - if (text->curc < text->selc) { - charf = text->curc; - charl = text->selc; - } - else { - charf = text->selc; - charl = text->curc; - } - } - else if (txt_get_span(text->curl, text->sell) < 0) { - linef = text->sell; - linel = text->curl; - - charf = text->selc; - charl = text->curc; - } - else { - linef = text->curl; - linel = text->sell; - - charf = text->curc; - charl = text->selc; - } - - if (linef == linel) { - length = charl - charf; - - buf = MEM_callocN(length + 1, "cut buffera"); - - BLI_strncpy(buf, linef->line + charf, length + 1); - } - else { - length += linef->len - charf; - length += charl; - length++; /* For the '\n' */ - - tmp = linef->next; - while (tmp && tmp != linel) { - length += tmp->len + 1; - tmp = tmp->next; - } - - buf = MEM_callocN(length + 1, "cut bufferb"); - - strncpy(buf, linef->line + charf, linef->len - charf); - length = linef->len - charf; - - buf[length++] = '\n'; - - tmp = linef->next; - while (tmp && tmp != linel) { - strncpy(buf + length, tmp->line, tmp->len); - length += tmp->len; - - buf[length++] = '\n'; - - tmp = tmp->next; - } - strncpy(buf + length, linel->line, charl); - length += charl; - - buf[length] = 0; - } - - return buf; -} - static int text_paste_exec(bContext *C, wmOperator *op) { const bool selection = RNA_boolean_get(op->ptr, "selection"); @@ -876,7 +794,10 @@ static void txt_copy_clipboard(Text *text) { char *buf; - buf = txt_copy_selected(text); + if (!txt_has_sel(text)) + return; + + buf = txt_sel_to_buf(text); if (buf) { WM_clipboard_text_set(buf, 0); diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 09b4123a977..820d1d68f8d 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -32,6 +32,7 @@ #include <string.h> #include <stdio.h> +#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -307,6 +308,9 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) case ID_OB: ob_to_keylist(&ads, (Object *)id, &keys, NULL); break; + case ID_GD: + gpencil_to_keylist(&ads, (bGPdata *)id, &keys); + break; } /* build linked-list for searching */ @@ -336,16 +340,23 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); + bGPdata *gpd = CTX_data_gpencil_data(C); View2D *v2d = &ar->v2d; bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0); + /* draw grease pencil keyframes (if available) */ + if (gpd) { + UI_ThemeColor(TH_TIME_GP_KEYFRAME); + time_draw_idblock_keyframes(v2d, (ID *)gpd, onlysel); + } + /* draw scene keyframes first * - don't try to do this when only drawing active/selected data keyframes, * since this can become quite slow */ if (onlysel == 0) { /* set draw color */ - glColor3ub(0xDD, 0xA7, 0x00); + UI_ThemeColorShade(TH_TIME_KEYFRAME, -50); time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel); } @@ -354,7 +365,7 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) * OR the onlysel flag was set, which means that only active object's keyframes should * be considered */ - glColor3ub(0xDD, 0xD7, 0x00); + UI_ThemeColor(TH_TIME_KEYFRAME); if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) { /* draw keyframes for active object only */ diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 0bd094b6a33..f986e909c7f 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -47,9 +47,7 @@ #include "WM_api.h" #include "WM_types.h" -#include "UI_view2d.h" -#include "userpref_intern.h" // own include /* ******************** default callbacks for userpref space ***************** */ diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index 8dd6c3c0271..0783eacc65c 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -32,5 +32,4 @@ #include <string.h> #include <stdio.h> -#include "userpref_intern.h" diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index 17f90fc54e3..d8b18140cde 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -54,7 +54,6 @@ #include "ED_armature.h" #include "ED_keyframes_draw.h" -#include "BLF_api.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index f25e4f143e6..691da78f26b 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -61,7 +61,6 @@ #include "ED_armature.h" #include "ED_keyframes_draw.h" -#include "BLF_api.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index fa9ba23e454..755c633531d 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -60,7 +60,6 @@ #include "UI_resources.h" -#include "GPU_buffers.h" #include "GPU_extensions.h" #include "GPU_draw.h" #include "GPU_material.h" @@ -97,7 +96,7 @@ typedef struct drawTFace_userData { BLI_INLINE int edge_vis_index(const int index) { return index * 2; } BLI_INLINE int edge_sel_index(const int index) { return index * 2 + 1; } -static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me) +static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me, bool draw_select_edges) { BLI_bitmap *bitmap_edge_flags = BLI_BITMAP_NEW(me->totedge * 2, __func__); MPoly *mp; @@ -113,8 +112,17 @@ static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me) ml = me->mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++) { - BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_vis_index(ml->e)); - if (select_set) BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_sel_index(ml->e)); + if ((draw_select_edges == false) && + (select_set && BLI_BITMAP_TEST(bitmap_edge_flags, edge_sel_index(ml->e)))) + { + BLI_BITMAP_DISABLE(bitmap_edge_flags, edge_vis_index(ml->e)); + } + else { + BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_vis_index(ml->e)); + if (select_set) { + BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_sel_index(ml->e)); + } + } } } } @@ -129,21 +137,26 @@ static DMDrawOption draw_mesh_face_select__setHiddenOpts(void *userData, int ind Mesh *me = data->me; if (me->drawflag & ME_DRAWEDGES) { - if ((me->drawflag & ME_HIDDENEDGES) || (BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index)))) + if ((BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index)))) return DM_DRAW_OPTION_NORMAL; else return DM_DRAW_OPTION_SKIP; } - else if (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index))) + else if (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) && + BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))) + { return DM_DRAW_OPTION_NORMAL; - else + } + else { return DM_DRAW_OPTION_SKIP; + } } static DMDrawOption draw_mesh_face_select__setSelectOpts(void *userData, int index) { drawMeshFaceSelect_userData *data = userData; - return (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP; + return (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) && + BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP; } /* draws unselected */ @@ -158,12 +171,12 @@ static DMDrawOption draw_mesh_face_select__drawFaceOptsInv(void *userData, int i return DM_DRAW_OPTION_SKIP; } -void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm) +void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool draw_select_edges) { drawMeshFaceSelect_userData data; data.me = me; - data.edge_flags = get_tface_mesh_marked_edge_info(me); + data.edge_flags = get_tface_mesh_marked_edge_info(me, draw_select_edges); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); @@ -562,14 +575,6 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, const bool has_mc } } -static DMDrawOption draw_mcol__set_draw_legacy(MTFace *UNUSED(tface), const bool has_mcol, int UNUSED(matnr)) -{ - if (has_mcol) - return DM_DRAW_OPTION_NORMAL; - else - return DM_DRAW_OPTION_NO_MCOL; -} - static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mcol), int matnr) { Material *ma = give_current_material(Gtexdraw.ob, matnr + 1); @@ -668,48 +673,48 @@ static void update_tface_color_layer(DerivedMesh *dm) } } -static DMDrawOption draw_tface_mapped__set_draw(void *userData, int index) +static DMDrawOption draw_tface_mapped__set_draw(void *userData, int origindex, int UNUSED(mat_nr)) { Mesh *me = ((drawTFace_userData *)userData)->me; /* array checked for NULL before calling */ - MPoly *mpoly = &me->mpoly[index]; + MPoly *mpoly = &me->mpoly[origindex]; - BLI_assert(index >= 0 && index < me->totpoly); + BLI_assert(origindex >= 0 && origindex < me->totpoly); if (mpoly->flag & ME_HIDE) { return DM_DRAW_OPTION_SKIP; } else { - MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[index] : NULL; + MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[origindex] : NULL; MTFace mtf = {{{0}}}; int matnr = mpoly->mat_nr; if (tpoly) { ME_MTEXFACE_CPY(&mtf, tpoly); } - + return draw_tface__set_draw(&mtf, (me->mloopcol != NULL), matnr); } } -static DMDrawOption draw_em_tf_mapped__set_draw(void *userData, int index) +static DMDrawOption draw_em_tf_mapped__set_draw(void *userData, int origindex, int mat_nr) { drawEMTFMapped_userData *data = userData; BMEditMesh *em = data->em; BMFace *efa; - if (UNLIKELY(index >= em->bm->totface)) + if (UNLIKELY(origindex >= em->bm->totface)) return DM_DRAW_OPTION_NORMAL; - efa = BM_face_at_index(em->bm, index); + efa = BM_face_at_index(em->bm, origindex); if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { return DM_DRAW_OPTION_SKIP; } else { MTFace mtf = {{{0}}}; - int matnr = efa->mat_nr; + int matnr = (mat_nr != -1) ? mat_nr : efa->mat_nr; if (data->has_mtface) { MTexPoly *tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); @@ -929,24 +934,16 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData, uvflag); } } - else { - if (GPU_buffer_legacy(dm)) { - if (draw_flags & DRAW_MODIFIERS_PREVIEW) - dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL, uvflag); - else - dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL, uvflag); - } - else { - drawTFace_userData userData; - - update_tface_color_layer(dm); - - userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE); - userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); - userData.me = NULL; - - dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag); - } + else { + drawTFace_userData userData; + + update_tface_color_layer(dm); + + userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE); + userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); + userData.me = NULL; + + dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag); } /* draw game engine text hack */ @@ -956,8 +953,10 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d draw_textured_end(); /* draw edges and selected faces over textured mesh */ - if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) - draw_mesh_face_select(rv3d, me, dm); + if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) { + bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0; + draw_mesh_face_select(rv3d, me, dm, draw_select_edges); + } /* reset from negative scale correction */ glFrontFace(GL_CCW); @@ -1153,8 +1152,10 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, glMatrixMode(GL_MODELVIEW); /* faceselect mode drawing over textured mesh */ - if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) - draw_mesh_face_select(rv3d, ob->data, dm); + if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) { + bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0; + draw_mesh_face_select(rv3d, ob->data, dm, draw_select_edges); + } } /* Vertex Paint and Weight Paint */ @@ -1189,7 +1190,7 @@ void draw_mesh_paint_weight_faces(DerivedMesh *dm, const bool use_light, } dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, GPU_enable_material, NULL, user_data, - DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH); + DM_DRAW_USE_COLORS); if (use_light) { draw_mesh_paint_light_end(); @@ -1206,12 +1207,11 @@ void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light, if (me->mloopcol) { dm->drawMappedFaces(dm, facemask_cb, GPU_enable_material, NULL, user_data, - DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH); + DM_DRAW_USE_COLORS); } else { glColor3f(1.0f, 1.0f, 1.0f); - dm->drawMappedFaces(dm, facemask_cb, GPU_enable_material, NULL, user_data, - DM_DRAW_ALWAYS_SMOOTH); + dm->drawMappedFaces(dm, facemask_cb, GPU_enable_material, NULL, user_data, 0); } if (use_light) { @@ -1279,7 +1279,8 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, /* draw face selection on top */ if (draw_flags & DRAW_FACE_SELECT) { - draw_mesh_face_select(rv3d, me, dm); + bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0; + draw_mesh_face_select(rv3d, me, dm, draw_select_edges); } else if ((use_light == false) || (ob->dtx & OB_DRAWWIRE)) { const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) || !(ob->mode & OB_MODE_WEIGHT_PAINT); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 28f806a9b7b..1cbc8e5567c 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -2953,21 +2953,23 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, if (!sel_only) wireCol[3] = 255; } - if (ts->selectmode == SCE_SELECT_FACE) { - draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); - } - else if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) { + if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) { if (cageDM->drawMappedEdgesInterp && ((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT))) { - glShadeModel(GL_SMOOTH); if (draw_dm_edges_weight_check(me, v3d)) { + glShadeModel(GL_SMOOTH); draw_dm_edges_weight_interp(em, cageDM, ts->weightuser); + glShadeModel(GL_FLAT); + } + else if (ts->selectmode == SCE_SELECT_FACE) { + draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); } else { + glShadeModel(GL_SMOOTH); draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol); + glShadeModel(GL_FLAT); } - glShadeModel(GL_FLAT); } else { draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); @@ -3375,7 +3377,6 @@ static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index) efa = BM_face_at_index(em->bm, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - GPU_enable_material(efa->mat_nr + 1, NULL); return DM_DRAW_OPTION_NORMAL; } else { @@ -3773,7 +3774,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D glFrontFace(GL_CCW); if (draw_flags & DRAW_FACE_SELECT) - draw_mesh_face_select(rv3d, me, dm); + draw_mesh_face_select(rv3d, me, dm, false); } else { draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags); @@ -6859,15 +6860,18 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, glDepthMask(0); if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - DerivedMesh *dm = ob->derivedFinal; + DerivedMesh *dm; bool has_faces = false; - if (dm) - DM_update_materials(dm, ob); #ifdef SEQUENCER_DAG_WORKAROUND ensure_curve_cache(scene, ob); #endif + dm = ob->derivedFinal; + if (dm) { + DM_update_materials(dm, ob); + } + if (dm) { has_faces = dm->getNumTessFaces(dm) > 0; } @@ -7975,7 +7979,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, cpack(0); if (use_faceselect) { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, em->bm, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, NULL, NULL, em->bm, 0); if (check_ob_drawface_dot(scene, v3d, ob->dt)) { glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); @@ -7987,7 +7991,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, } else { - dm->drawMappedFaces(dm, bbs_mesh_mask__setSolidDrawOptions, GPU_enable_material, NULL, em->bm, 0); + dm->drawMappedFaces(dm, bbs_mesh_mask__setSolidDrawOptions, NULL, NULL, em->bm, 0); } } @@ -8048,9 +8052,9 @@ static void bbs_mesh_solid_faces(Scene *scene, Object *ob) DM_update_materials(dm, ob); if ((me->editflag & ME_EDIT_PAINT_FACE_SEL)) - dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, GPU_enable_material, NULL, me, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, NULL, NULL, me, 0); else - dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, GPU_enable_material, NULL, me, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, NULL, NULL, me, 0); dm->release(dm); } diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 59798f97d93..a220e1e39b0 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -27,8 +27,6 @@ * \ingroup spview3d */ - - #include <string.h> #include <math.h> @@ -38,7 +36,6 @@ #include "DNA_screen_types.h" #include "DNA_smoke_types.h" #include "DNA_view3d_types.h" -#include "DNA_property_types.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -53,8 +50,6 @@ #include "ED_mesh.h" -#include "BLF_api.h" - #include "view3d_intern.h" // own include struct GPUTexture; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index b3accb431ee..55d5273b198 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -414,7 +414,7 @@ static void view3d_free(SpaceLink *sl) /* matcap material, its preview rect gets freed via icons */ if (vd->defmaterial) { if (vd->defmaterial->gpumaterial.first) - GPU_material_free(vd->defmaterial); + GPU_material_free(&vd->defmaterial->gpumaterial); BKE_previewimg_free(&vd->defmaterial->preview); MEM_freeN(vd->defmaterial); } @@ -599,7 +599,7 @@ static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent return 1; } else if (drag->type == WM_DRAG_PATH) { - if (ELEM(drag->icon, 0, ICON_FILE_IMAGE)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)) /* rule might not work? */ return 1; } return 0; @@ -665,10 +665,14 @@ static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { ID *id = (ID *)drag->poin; - if (id) + if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); - if (drag->path[0]) + RNA_struct_property_unset(drop->ptr, "filepath"); + } + else if (drag->path[0]) { RNA_string_set(drop->ptr, "filepath", drag->path); + RNA_struct_property_unset(drop->ptr, "image"); + } } @@ -950,8 +954,9 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN break; case NC_GPENCIL: - if (wmn->action == NA_EDITED) + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) { ED_region_tag_redraw(ar); + } break; } } @@ -1007,6 +1012,10 @@ static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa) if (wmn->data == ND_SPACE_VIEW3D) ED_region_tag_redraw(ar); break; + case NC_GPENCIL: + if (wmn->data & ND_GPENCIL_EDITMODE) + ED_region_tag_redraw(ar); + break; } } @@ -1104,7 +1113,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa ED_region_tag_redraw(ar); break; case NC_GPENCIL: - if (wmn->data == ND_DATA || wmn->action == NA_EDITED) + if ((wmn->data & (ND_DATA | ND_GPENCIL_EDITMODE)) || (wmn->action == NA_EDITED)) ED_region_tag_redraw(ar); break; case NC_IMAGE: @@ -1168,7 +1177,8 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot case NC_WORLD: switch (wmn->data) { case ND_WORLD_DRAW: - if (v3d->flag2 & V3D_RENDER_OVERRIDE) + case ND_WORLD: + if (v3d->flag3 & V3D_SHOW_WORLD) ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); break; } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 899be6359ee..88f43ab340f 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -60,6 +60,7 @@ #include "BKE_editmesh.h" #include "BKE_deform.h" #include "BKE_object.h" +#include "BKE_object_deform.h" #include "WM_api.h" #include "WM_types.h" @@ -68,7 +69,6 @@ #include "ED_armature.h" #include "ED_gpencil.h" -#include "ED_object.h" #include "ED_mesh.h" #include "ED_screen.h" @@ -844,9 +844,9 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) col = uiLayoutColumn(bcol, true); - vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); + vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); for (i = 0, dg = ob->defbase.first; dg; i++, dg = dg->next) { - bool locked = dg->flag & DG_LOCK_WEIGHT; + bool locked = (dg->flag & DG_LOCK_WEIGHT) != 0; if (vgroup_validmap[i]) { MDeformWeight *dw = defvert_find_index(dv, i); if (dw) { @@ -1185,14 +1185,6 @@ void view3d_buttons_register(ARegionType *art) pt->poll = view3d_panel_transform_poll; BLI_addtail(&art->paneltypes, pt); - pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel gpencil"); - strcpy(pt->idname, "VIEW3D_PT_gpencil"); - strcpy(pt->label, N_("Grease Pencil")); /* XXX C panels are not available through RNA (bpy.types)! */ - strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw_header = ED_gpencil_panel_standard_header; - pt->draw = ED_gpencil_panel_standard; - BLI_addtail(&art->paneltypes, pt); - pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup"); strcpy(pt->idname, "VIEW3D_PT_vgroup"); strcpy(pt->label, N_("Vertex Weights")); /* XXX C panels are not available through RNA (bpy.types)! */ diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index ee0f3da18b4..95e918abdcf 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -51,14 +51,12 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" -#include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BKE_object.h" #include "BKE_depsgraph.h" /* for object updating */ -#include "ED_keyframing.h" #include "ED_screen.h" #include "view3d_intern.h" /* own include */ @@ -266,6 +264,8 @@ void ED_view3d_cameracontrol_update( BKE_object_apply_mat4(v3d->camera, view_mat, true, true); + DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + copy_v3_v3(v3d->camera->size, size_back); id_key = &v3d->camera->id; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index e921a436c85..65721d52dff 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -787,7 +787,16 @@ static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) { Camera *cam; cam = v3d->camera->data; - name = (cam->type != CAM_ORTHO) ? IFACE_("Camera Persp") : IFACE_("Camera Ortho"); + if (cam->type == CAM_PERSP) { + name = IFACE_("Camera Persp"); + } + else if (cam->type == CAM_ORTHO) { + name = IFACE_("Camera Ortho"); + } + else { + BLI_assert(cam->type == CAM_PANO); + name = IFACE_("Camera Pano"); + } } else { name = IFACE_("Object as Camera"); @@ -1362,7 +1371,7 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) else glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); - glClearColor(0.0, 0.0, 0.0, 0.0); + glClearColor(0.0, 0.0, 0.0, 0.0); if (v3d->zbuf) { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -2646,10 +2655,7 @@ static void view3d_draw_objects( if (!draw_offscreen) { /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */ - rv3d->gridview = v3d->grid; - if (scene->unit.system) { - rv3d->gridview /= scene->unit.scale_length; - } + rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit); if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { @@ -2659,6 +2665,7 @@ static void view3d_draw_objects( else { if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { ED_region_pixelspace(ar); + *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ drawgrid(&scene->unit, ar, v3d, grid_unit); /* XXX make function? replaces persp(1) */ glMatrixMode(GL_PROJECTION); @@ -2801,6 +2808,203 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d) gpu_update_lamps_shadows(scene, v3d); } +/* + * Function to clear the view + */ +static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool force) +{ + /* clear background */ + if (scene->world && ((v3d->flag3 & V3D_SHOW_WORLD) || force)) { + float alpha = (force) ? 1.0f : 0.0; + bool glsl = GPU_glsl_support() && BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes; + + if (glsl) { + RegionView3D *rv3d = ar->regiondata; + GPUMaterial *gpumat = GPU_material_world(scene, scene->world); + + /* calculate full shader for background */ + GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, (v3d->scenelock != 0)); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glShadeModel(GL_SMOOTH); + glBegin(GL_QUADS); + glVertex3f(-1.0, -1.0, 1.0); + glVertex3f(1.0, -1.0, 1.0); + glVertex3f(1.0, 1.0, 1.0); + glVertex3f(-1.0, 1.0, 1.0); + glEnd(); + glShadeModel(GL_FLAT); + + GPU_material_unbind(gpumat); + + glDepthFunc(GL_LEQUAL); + glDisable(GL_DEPTH_TEST); + } + else if (scene->world->skytype & WO_SKYBLEND) { /* blend sky */ + int x, y; + float col_hor[3]; + float col_zen[3]; + +#define VIEWGRAD_RES_X 16 +#define VIEWGRAD_RES_Y 16 + + GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4]; + static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3]; + static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4]; + static bool buf_calculated = false; + + IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings, + &scene->display_settings); + IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings, + &scene->display_settings); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glShadeModel(GL_SMOOTH); + + /* calculate buffers the first time only */ + if (!buf_calculated) { + for (x = 0; x < VIEWGRAD_RES_X; x++) { + for (y = 0; y < VIEWGRAD_RES_Y; y++) { + const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1); + const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1); + + /* -1..1 range */ + grid_pos[x][y][0] = (xf - 0.5f) * 2.0f; + grid_pos[x][y][1] = (yf - 0.5f) * 2.0f; + grid_pos[x][y][2] = 1.0; + } + } + + for (x = 0; x < VIEWGRAD_RES_X - 1; x++) { + for (y = 0; y < VIEWGRAD_RES_Y - 1; y++) { + indices[x][y][0] = x * VIEWGRAD_RES_X + y; + indices[x][y][1] = x * VIEWGRAD_RES_X + y + 1; + indices[x][y][2] = (x + 1) * VIEWGRAD_RES_X + y + 1; + indices[x][y][3] = (x + 1) * VIEWGRAD_RES_X + y; + } + } + + buf_calculated = true; + } + + for (x = 0; x < VIEWGRAD_RES_X; x++) { + for (y = 0; y < VIEWGRAD_RES_Y; y++) { + const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1); + const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1); + const float mval[2] = {xf * (float)ar->winx, yf * ar->winy}; + const float z_up[3] = {0.0f, 0.0f, 1.0f}; + float out[3]; + GLubyte *col_ub = grid_col[x][y]; + + float col_fac; + float col_fl[3]; + + ED_view3d_win_to_vector(ar, mval, out); + + if (scene->world->skytype & WO_SKYPAPER) { + if (scene->world->skytype & WO_SKYREAL) { + col_fac = fabsf(((float)y / (float)VIEWGRAD_RES_Y) - 0.5f) * 2.0f; + } + else { + col_fac = (float)y / (float)VIEWGRAD_RES_Y; + } + } + else { + if (scene->world->skytype & WO_SKYREAL) { + col_fac = fabsf((angle_normalized_v3v3(z_up, out) / (float)M_PI) - 0.5f) * 2.0f; + } + else { + col_fac = 1.0f - (angle_normalized_v3v3(z_up, out) / (float)M_PI); + } + } + + interp_v3_v3v3(col_fl, col_hor, col_zen, col_fac); + + rgb_float_to_uchar(col_ub, col_fl); + col_ub[3] = alpha * 255; + } + } + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, grid_pos); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col); + + glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + glDepthFunc(GL_LEQUAL); + glDisable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glShadeModel(GL_FLAT); + +#undef VIEWGRAD_RES_X +#undef VIEWGRAD_RES_Y + } + else { /* solid sky */ + float col_hor[3]; + IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings, + &scene->display_settings); + + glClearColor(col_hor[0], col_hor[1], col_hor[2], alpha); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + } + else { + if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glShadeModel(GL_SMOOTH); + glBegin(GL_QUADS); + UI_ThemeColor(TH_LOW_GRAD); + glVertex3f(-1.0, -1.0, 1.0); + glVertex3f(1.0, -1.0, 1.0); + UI_ThemeColor(TH_HIGH_GRAD); + glVertex3f(1.0, 1.0, 1.0); + glVertex3f(-1.0, 1.0, 1.0); + glEnd(); + glShadeModel(GL_FLAT); + + glDepthFunc(GL_LEQUAL); + glDisable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } + else { + UI_ThemeClearColor(TH_HIGH_GRAD); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + } +} + /* ED_view3d_draw_offscreen_init should be called before this to initialize * stuff like shadow buffers */ @@ -2808,6 +3012,7 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky) { + struct bThemeState theme_state; int bwinx, bwiny; rcti brect; @@ -2825,7 +3030,7 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, ar->winrct.xmax = winx; ar->winrct.ymax = winy; - /* set theme */ + UI_Theme_Store(&theme_state); UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); /* set flags */ @@ -2836,25 +3041,18 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, * warning! can be slow so only free animated images - campbell */ GPU_free_images_anim(); } - + /* setup view matrices */ + view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat); + /* clear opengl buffers */ if (do_sky) { - float sky_color[3]; - - ED_view3d_offscreen_sky_color_get(scene, sky_color); - glClearColor(sky_color[0], sky_color[1], sky_color[2], 1.0f); + view3d_main_area_clear(scene, v3d, ar, true); } else { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - - /* setup view matrices */ - view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat); - - /* main drawing call */ view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true); @@ -2879,8 +3077,7 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, glPopMatrix(); - /* XXX, without this the sequencer flickers with opengl draw enabled, need to find out why - campbell */ - glColor4ub(255, 255, 255, 255); + UI_Theme_Restore(&theme_state); G.f &= ~G_RENDER_OGL; } @@ -2951,13 +3148,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in if (ibuf->rect_float && ibuf->rect) IMB_rect_from_float(ibuf); - + return ibuf; } /* creates own 3d views, used by the sequencer */ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height, unsigned int flag, int drawtype, - bool use_solid_tex, bool draw_background, int alpha_mode, char err_out[256]) + bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]) { View3D v3d = {NULL}; ARegion ar = {NULL}; @@ -2972,6 +3169,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w v3d.lay = scene->lay; v3d.drawtype = drawtype; v3d.flag2 = V3D_RENDER_OVERRIDE; + + if (use_gpencil) + v3d.flag2 |= V3D_SHOW_GPENCIL; if (use_solid_tex) v3d.flag2 |= V3D_SOLID_TEX; @@ -3205,178 +3405,6 @@ static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, A ED_region_info_draw(ar, rv3d->render_engine->text, 1, fill_color); } -/* - * Function to clear the view - */ -static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) -{ - /* clear background */ - if (scene->world && (v3d->flag2 & V3D_RENDER_OVERRIDE)) { /* clear with solid color */ - if (scene->world->skytype & WO_SKYBLEND) { /* blend sky */ - int x, y; - float col_hor[3]; - float col_zen[3]; - -#define VIEWGRAD_RES_X 16 -#define VIEWGRAD_RES_Y 16 - - GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4]; - static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3]; - static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4]; - static bool buf_calculated = false; - - IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings, - &scene->display_settings); - IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings, - &scene->display_settings); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glShadeModel(GL_SMOOTH); - - /* calculate buffers the first time only */ - if (!buf_calculated) { - for (x = 0; x < VIEWGRAD_RES_X; x++) { - for (y = 0; y < VIEWGRAD_RES_Y; y++) { - const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1); - const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1); - - /* -1..1 range */ - grid_pos[x][y][0] = (xf - 0.5f) * 2.0f; - grid_pos[x][y][1] = (yf - 0.5f) * 2.0f; - grid_pos[x][y][2] = 1.0; - } - } - - for (x = 0; x < VIEWGRAD_RES_X - 1; x++) { - for (y = 0; y < VIEWGRAD_RES_Y - 1; y++) { - indices[x][y][0] = x * VIEWGRAD_RES_X + y; - indices[x][y][1] = x * VIEWGRAD_RES_X + y + 1; - indices[x][y][2] = (x + 1) * VIEWGRAD_RES_X + y + 1; - indices[x][y][3] = (x + 1) * VIEWGRAD_RES_X + y; - } - } - - buf_calculated = true; - } - - for (x = 0; x < VIEWGRAD_RES_X; x++) { - for (y = 0; y < VIEWGRAD_RES_Y; y++) { - const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1); - const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1); - const float mval[2] = {xf * (float)ar->winx, yf * ar->winy}; - const float z_up[3] = {0.0f, 0.0f, 1.0f}; - float out[3]; - GLubyte *col_ub = grid_col[x][y]; - - float col_fac; - float col_fl[3]; - - ED_view3d_win_to_vector(ar, mval, out); - - if (scene->world->skytype & WO_SKYPAPER) { - if (scene->world->skytype & WO_SKYREAL) { - col_fac = fabsf(((float)y / (float)VIEWGRAD_RES_Y) - 0.5f) * 2.0f; - } - else { - col_fac = (float)y / (float)VIEWGRAD_RES_Y; - } - } - else { - if (scene->world->skytype & WO_SKYREAL) { - col_fac = fabsf((angle_normalized_v3v3(z_up, out) / (float)M_PI) - 0.5f) * 2.0f; - } - else { - col_fac = 1.0f - (angle_normalized_v3v3(z_up, out) / (float)M_PI); - } - } - - interp_v3_v3v3(col_fl, col_hor, col_zen, col_fac); - - rgb_float_to_uchar(col_ub, col_fl); - col_ub[3] = 0; - } - } - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, grid_pos); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col); - - glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - glShadeModel(GL_FLAT); - -#undef VIEWGRAD_RES_X -#undef VIEWGRAD_RES_Y - } - else { /* solid sky */ - float col_hor[3]; - IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings, - &scene->display_settings); - - glClearColor(col_hor[0], col_hor[1], col_hor[2], 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - } - else { - if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glShadeModel(GL_SMOOTH); - glBegin(GL_QUADS); - UI_ThemeColor(TH_LOW_GRAD); - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - UI_ThemeColor(TH_HIGH_GRAD); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(-1.0, 1.0, 1.0); - glEnd(); - glShadeModel(GL_FLAT); - - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - else { - UI_ThemeClearColor(TH_HIGH_GRAD); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - } -} - - #ifdef WITH_GAMEENGINE static void update_lods(Scene *scene, float camera_pos[3]) { @@ -3422,7 +3450,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3 #endif /* clear the background */ - view3d_main_area_clear(scene, v3d, ar); + view3d_main_area_clear(scene, v3d, ar, false); /* enables anti-aliasing for 3D view drawing */ if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index d3bd59cacc8..aab307babe8 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -49,7 +49,6 @@ #include "BKE_camera.h" #include "BKE_context.h" #include "BKE_font.h" -#include "BKE_image.h" #include "BKE_library.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -626,9 +625,9 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) * center, in other cases it's not clear what rotation center shall be * so just rotate around object origin */ - if (ob->mode & OB_MODE_SCULPT) { + if (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT)) { float stroke[3]; - ED_sculpt_stroke_get_average(ob, stroke); + BKE_paint_stroke_get_average(scene, ob, stroke); copy_v3_v3(lastofs, stroke); } else { @@ -1119,6 +1118,8 @@ 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) { @@ -1153,17 +1154,25 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event_code == VIEW_APPLY) { viewrotate_apply(vod, event->x, event->y); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } } else if (event_code == VIEW_CONFIRM) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true); ED_view3d_depth_tag_update(vod->rv3d); + use_autokey = true; + ret = OPERATOR_FINISHED; + } - viewops_data_free(C, op); + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true); + } - return OPERATOR_FINISHED; + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op); } - return OPERATOR_RUNNING_MODAL; + return ret; } /** @@ -1221,26 +1230,31 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(vod->ar); } - if (event->type == MOUSEPAN) { + if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) { /* Rotate direction we keep always same */ - if (U.uiflag2 & USER_TRACKPAD_NATURAL) - viewrotate_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy); - else - viewrotate_apply(vod, event->prevx, event->prevy); - - ED_view3d_depth_tag_update(vod->rv3d); - - viewops_data_free(C, op); - - return OPERATOR_FINISHED; - } - else if (event->type == MOUSEROTATE) { - /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ - viewrotate_apply(vod, event->prevx, event->y); + int x, y; + + if (event->type == MOUSEPAN) { + if (U.uiflag2 & USER_TRACKPAD_NATURAL) { + x = 2 * event->x - event->prevx; + y = 2 * event->y - event->prevy; + } + else { + x = event->prevx; + y = event->prevy; + } + } + else { + /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ + x = event->prevx; + y = event->y; + } + + viewrotate_apply(vod, x, y); ED_view3d_depth_tag_update(vod->rv3d); - + viewops_data_free(C, op); - + return OPERATOR_FINISHED; } else { @@ -1946,6 +1960,8 @@ 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) { @@ -1972,17 +1988,25 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event_code == VIEW_APPLY) { viewmove_apply(vod, event->x, event->y); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } } else if (event_code == VIEW_CONFIRM) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); ED_view3d_depth_tag_update(vod->rv3d); + use_autokey = true; + ret = OPERATOR_FINISHED; + } - viewops_data_free(C, op); + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); + } - return OPERATOR_FINISHED; + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op); } - return OPERATOR_RUNNING_MODAL; + return ret; } static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -2214,6 +2238,8 @@ 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) { @@ -2244,16 +2270,25 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event_code == VIEW_APPLY) { viewzoom_apply(vod, &event->x, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } } else if (event_code == VIEW_CONFIRM) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); ED_view3d_depth_tag_update(vod->rv3d); - viewops_data_free(C, op); + use_autokey = true; + ret = OPERATOR_FINISHED; + } - return 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 OPERATOR_RUNNING_MODAL; + return ret; } static int viewzoom_exec(bContext *C, wmOperator *op) @@ -2315,6 +2350,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) ED_view3d_depth_tag_update(rv3d); ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true); ED_region_tag_redraw(ar); @@ -2389,8 +2425,10 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) vod->origy = vod->oldy = vod->origy + event->x - event->prevx; viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0); } + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); + ED_view3d_depth_tag_update(vod->rv3d); - + viewops_data_free(C, op); return OPERATOR_FINISHED; } @@ -2486,6 +2524,8 @@ 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) { @@ -2512,16 +2552,25 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event_code == VIEW_APPLY) { viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } } else if (event_code == VIEW_CONFIRM) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); ED_view3d_depth_tag_update(vod->rv3d); - viewops_data_free(C, op); + use_autokey = true; + ret = OPERATOR_FINISHED; + } - return OPERATOR_FINISHED; + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); } - return OPERATOR_RUNNING_MODAL; + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op); + } + + return ret; } static int viewdolly_exec(bContext *C, wmOperator *op) @@ -2926,8 +2975,10 @@ static int viewselected_exec(bContext *C, wmOperator *op) else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { ok = PE_minmax(scene, min, max); } - else if (ob && (ob->mode & OB_MODE_SCULPT)) { - ok = ED_sculpt_minmax(C, min, max); + else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) { + BKE_paint_stroke_get_average(scene, ob, min); + copy_v3_v3(max, min); + ok = true; ok_dist = 0; /* don't zoom */ } else { @@ -3970,6 +4021,8 @@ 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) { @@ -3996,16 +4049,25 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event_code == VIEW_APPLY) { viewroll_apply(vod, event->x, event->y); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } } else if (event_code == VIEW_CONFIRM) { - ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false); ED_view3d_depth_tag_update(vod->rv3d); - viewops_data_free(C, op); + use_autokey = true; + ret = OPERATOR_FINISHED; + } - return OPERATOR_FINISHED; + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false); } - return OPERATOR_RUNNING_MODAL; + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, op); + } + + return ret; } static EnumPropertyItem prop_view_roll_items[] = { @@ -4279,32 +4341,16 @@ static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op)) static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { View3D *v3d = CTX_wm_view3d(C); - Image *ima = NULL; + Image *ima; BGpic *bgpic; - char name[MAX_ID_NAME - 2]; - - /* check input variables */ - if (RNA_struct_property_is_set(op->ptr, "filepath")) { - char path[FILE_MAX]; - - RNA_string_get(op->ptr, "filepath", path); - ima = BKE_image_load_exists(path); - } - else if (RNA_struct_property_is_set(op->ptr, "name")) { - RNA_string_get(op->ptr, "name", name); - ima = (Image *)BKE_libblock_find_name(ID_IM, name); - } + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); + /* may be NULL, continue anyway */ + bgpic = background_image_add(C); - - if (ima) { - bgpic->ima = ima; - - id_us_plus(&ima->id); - - if (!(v3d->flag & V3D_DISPBGPICS)) - v3d->flag |= V3D_DISPBGPICS; - } + bgpic->ima = ima; + + v3d->flag |= V3D_DISPBGPICS; WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -4330,7 +4376,8 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) /* properties */ RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign"); - RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file"); + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY); } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 4c19f59a148..11ed9867e2f 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -32,12 +32,9 @@ #include <stdio.h> #include <stdlib.h> -#include "DNA_brush_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "BLI_math.h" -#include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLF_translation.h" @@ -45,8 +42,6 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_main.h" -#include "BKE_modifier.h" -#include "BKE_paint.h" #include "BKE_screen.h" #include "BKE_editmesh.h" diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 84ac4f7d02d..d3a9f5ca967 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -163,7 +163,9 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* drawmesh.c */ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, struct DerivedMesh *dm, const int draw_flags); -void draw_mesh_face_select(struct RegionView3D *rv3d, struct Mesh *me, struct DerivedMesh *dm); +void draw_mesh_face_select( + struct RegionView3D *rv3d, struct Mesh *me, struct DerivedMesh *dm, + bool draw_select_edges); void draw_mesh_paint_weight_faces(struct DerivedMesh *dm, const bool do_light, void *facemask_cb, void *user_data); void draw_mesh_paint_vcolor_faces(struct DerivedMesh *dm, const bool use_light, diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 6a505959820..5df348408df 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -42,6 +42,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_context.h" #include "BKE_main.h" @@ -77,7 +78,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - BLI_make_file_string("/", str, BLI_temp_dir_base(), "copybuffer.blend"); + BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); BKE_copybuffer_save(str, op->reports); BKE_report(op->reports, RPT_INFO, "Copied selected objects to buffer"); @@ -102,7 +103,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) { char str[FILE_MAX]; - BLI_make_file_string("/", str, BLI_temp_dir_base(), "copybuffer.blend"); + BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); if (BKE_copybuffer_paste(C, str, op->reports)) { WM_event_add_notifier(C, NC_WINDOW, NULL); diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 48bc6448194..eba31866f54 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -70,7 +70,7 @@ * \param r_co hit location. * \param r_no hit normal (optional). * \param co_ss Screenspace coordinate. - * \param use_depth Snap to the closest element, use when using more then one snap type. + * \param use_depth Snap to the closest element, use when using more than one snap type. * \param use_obedit Use editmode cage. * \param use_vert Snap to verts. * \param use_edge Snap to edges. diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 08a69830c03..38ecbed3b5f 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -93,7 +93,6 @@ #include "ED_mball.h" #include "UI_interface.h" -#include "UI_resources.h" #include "view3d_intern.h" /* own include */ diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 0e17d8fc354..f127f375a9f 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -39,7 +39,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 9faca757c62..5a3893f733f 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -37,9 +37,7 @@ #include "BLI_math.h" #include "BLI_rect.h" -#include "BLI_listbase.h" #include "BLI_utildefines.h" -#include "BLI_callbacks.h" #include "BKE_anim.h" #include "BKE_action.h" @@ -55,7 +53,6 @@ #include "BIF_gl.h" #include "BIF_glutil.h" -#include "GPU_draw.h" #include "GPU_select.h" #include "WM_api.h" @@ -64,14 +61,16 @@ #include "ED_screen.h" #include "ED_armature.h" -#include "RE_engine.h" #ifdef WITH_GAMEENGINE -#include "BL_System.h" +# include "BLI_listbase.h" +# include "BLI_callbacks.h" + +# include "GPU_draw.h" + +# include "BL_System.h" #endif -#include "RNA_access.h" -#include "RNA_define.h" #include "view3d_intern.h" /* own include */ @@ -356,6 +355,7 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d); ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } if ((rv3d->viewlock & RV3D_LOCKED) == 0) { @@ -382,6 +382,10 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv; ED_view3d_camera_lock_sync(v3d, rv3d); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); + } + } if (rv3d->viewlock & RV3D_BOXVIEW) @@ -492,26 +496,22 @@ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) Object *camera_ob = v3d ? v3d->camera : scene->camera; float r_co[3]; /* the new location to apply */ + float r_scale; /* only for ortho cameras */ if (camera_ob == NULL) { BKE_report(op->reports, RPT_ERROR, "No active camera"); return OPERATOR_CANCELLED; } - else if (camera_ob->type != OB_CAMERA) { - BKE_report(op->reports, RPT_ERROR, "Object not a camera"); - return OPERATOR_CANCELLED; - } - else if (((Camera *)camera_ob->data)->type == R_ORTHO) { - BKE_report(op->reports, RPT_ERROR, "Orthographic cameras not supported"); - return OPERATOR_CANCELLED; - } /* this function does all the important stuff */ - if (BKE_camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co)) { - + if (BKE_camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co, &r_scale)) { ObjectTfmProtectedChannels obtfm; float obmat_new[4][4]; + if ((camera_ob->type == OB_CAMERA) && (((Camera *)camera_ob->data)->type == CAM_ORTHO)) { + ((Camera *)camera_ob->data)->ortho_scale = r_scale; + } + copy_m4_m4(obmat_new, camera_ob->obmat); copy_v3_v3(obmat_new[3], r_co); diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 9b9b7a8d258..191eeb05c71 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -42,8 +42,6 @@ #include "BLF_translation.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" #include "BIF_gl.h" diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 9547f0bc77f..b727b96c8cc 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -200,6 +200,12 @@ static bool transdata_check_local_center(TransInfo *t, short around) ); } +bool transdata_check_local_islands(TransInfo *t, short around) +{ + return ((around == V3D_LOCAL) && ( + (t->obedit && ELEM(t->obedit->type, OB_MESH)))); +} + /* ************************** SPACE DEPENDANT CODE **************************** */ void setTransformViewMatrices(TransInfo *t) @@ -579,7 +585,10 @@ void removeAspectRatio(TransInfo *t, float vec[2]) static void viewRedrawForce(const bContext *C, TransInfo *t) { - if (t->spacetype == SPACE_VIEW3D) { + if (t->options & CTX_GPENCIL_STROKES) { + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + } + else if (t->spacetype == SPACE_VIEW3D) { if (t->options & CTX_PAINT_CURVE) { wmWindow *window = CTX_wm_window(C); WM_paint_cursor_tag_redraw(window, t->ar); @@ -2007,6 +2016,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve options |= CTX_TEXTURE; } } + + if ((prop = RNA_struct_find_property(op->ptr, "gpencil_strokes")) && RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) { + options |= CTX_GPENCIL_STROKES; + } + } t->options = options; @@ -4061,6 +4076,11 @@ static void initTranslation(TransInfo *t) t->snap[1] = ED_node_grid_size() * NODE_GRID_STEPS; t->snap[2] = ED_node_grid_size(); } + else if (t->spacetype == SPACE_IPO) { + t->snap[0] = 0.0f; + t->snap[1] = 1.0; + t->snap[2] = 0.1f; + } else { t->snap[0] = 0.0f; t->snap[1] = t->snap[2] = 1.0f; @@ -5837,12 +5857,12 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) l_ed_sel = l_ed_sel->prev; if (sld->perc < 0.0f) { - if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->v_b)) { + if (BM_vert_in_face(sv->v_b, l_ed_sel->radial_next->f)) { f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f); } } else if (sld->perc > 0.0f) { - if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->v_a)) { + if (BM_vert_in_face(sv->v_a, l_ed_sel->radial_next->f)) { f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f); } } @@ -5902,18 +5922,18 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) BMLoop *l_adj = NULL; if (sld->perc < 0.0f) { - if (BM_vert_in_face(e_sel->l->f, sv->v_b)) { + if (BM_vert_in_face(sv->v_b, e_sel->l->f)) { l_adj = e_sel->l; } - else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_b)) { + else if (BM_vert_in_face(sv->v_b, e_sel->l->radial_next->f)) { l_adj = e_sel->l->radial_next; } } else if (sld->perc > 0.0f) { - if (BM_vert_in_face(e_sel->l->f, sv->v_a)) { + if (BM_vert_in_face(sv->v_a, e_sel->l->f)) { l_adj = e_sel->l; } - else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_a)) { + else if (BM_vert_in_face(sv->v_a, e_sel->l->radial_next->f)) { l_adj = e_sel->l->radial_next; } } @@ -7121,10 +7141,11 @@ static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN]) WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); } -static void applySeqSlideValue(TransInfo *t, const float val[2]) +static void applySeqSlideValue(TransInfo *t, const float val[2], int frame) { TransData *td = t->data; int i; + TransSeq *ts = t->customData; for (i = 0; i < t->total; i++, td++) { float tvec[2]; @@ -7139,15 +7160,21 @@ static void applySeqSlideValue(TransInfo *t, const float val[2]) mul_v2_fl(tvec, td->factor); - td->loc[0] = td->iloc[0] + tvec[0]; + if (t->modifiers & MOD_SNAP_INVERT) { + td->loc[0] = frame + td->factor * (td->iloc[0] - ts->min); + } + else { + td->loc[0] = td->iloc[0] + tvec[0]; + } + td->loc[1] = td->iloc[1] + tvec[1]; } } -static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2])) +static void applySeqSlide(TransInfo *t, const int mval[2]) { char str[MAX_INFO_LEN]; - + int snap_frame = 0; if (t->con.mode & CON_APPLY) { float pvec[3] = {0.0f, 0.0f, 0.0f}; float tvec[3]; @@ -7155,7 +7182,8 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2])) copy_v3_v3(t->values, tvec); } else { - snapGridIncrement(t, t->values); + snap_frame = snapSequenceBounds(t, mval); + // snapGridIncrement(t, t->values); applyNumInput(&t->num, t->values); } @@ -7163,7 +7191,7 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2])) t->values[1] = floor(t->values[1] + 0.5f); headerSeqSlide(t, t->values, str); - applySeqSlideValue(t, t->values); + applySeqSlideValue(t, t->values, snap_frame); recalcData(t); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 67d55639528..0d824be862e 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -173,6 +173,13 @@ typedef struct TransDataSeq { } TransDataSeq; +typedef struct TransSeq { + TransDataSeq *tdseq; + int min; + int max; + bool snap_left; +} TransSeq; + /* for NLA transform (stored in td->extra pointer) */ typedef struct TransDataNla { ID *id; /* ID-block NLA-data is attached to */ @@ -545,6 +552,7 @@ void special_aftertrans_update(struct bContext *C, TransInfo *t); int special_transform_moving(TransInfo *t); void transform_autoik_update(TransInfo *t, short mode); +bool transdata_check_local_islands(TransInfo *t, short around); int count_set_pose_transflags(int *out_mode, short around, struct Object *ob); @@ -588,6 +596,8 @@ typedef enum { void snapGridIncrement(TransInfo *t, float *val); void snapGridIncrementAction(TransInfo *t, float *val, GearsType action); +int snapSequenceBounds(TransInfo *t, const int mval[2]); + bool activeSnap(TransInfo *t); bool validSnap(TransInfo *t); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index e2859b2821a..c1350b1f076 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -54,7 +54,6 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_smallhash.h" #include "BLI_listbase.h" #include "BLI_linklist_stack.h" #include "BLI_string.h" @@ -90,7 +89,6 @@ #include "BKE_editmesh.h" #include "BKE_tracking.h" #include "BKE_mask.h" -#include "BKE_lattice.h" #include "BIK_api.h" @@ -107,6 +105,7 @@ #include "ED_uvedit.h" #include "ED_clip.h" #include "ED_mask.h" +#include "ED_gpencil.h" #include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */ #include "WM_types.h" @@ -218,6 +217,9 @@ static void set_prop_dist(TransInfo *t, const bool with_dist) float _proj_vec[3]; const float *proj_vec = NULL; + /* support for face-islands */ + const bool use_island = transdata_check_local_islands(t, t->around); + if (t->flag & T_PROP_PROJECTED) { if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = t->ar->regiondata; @@ -239,7 +241,12 @@ static void set_prop_dist(TransInfo *t, const bool with_dist) for (i = 0, td = t->data; i < t->total; i++, td++) { if (td->flag & TD_SELECTED) { - sub_v3_v3v3(vec, tob->center, td->center); + if (use_island) { + sub_v3_v3v3(vec, tob->iloc, td->iloc); + } + else { + sub_v3_v3v3(vec, tob->center, td->center); + } mul_m3_v3(tob->mtx, vec); if (proj_vec) { @@ -251,6 +258,10 @@ static void set_prop_dist(TransInfo *t, const bool with_dist) dist_sq = len_squared_v3(vec); if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) { tob->rdist = sqrtf(dist_sq); + if (use_island) { + copy_v3_v3(tob->center, td->center); + copy_m3_m3(tob->axismtx, td->axismtx); + } } } else { @@ -2806,8 +2817,8 @@ void flushTransUVs(TransInfo *t) td->loc2d[1] = td->loc[1] * invy; if ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) { - td->loc2d[0] = floorf(width * td->loc2d[0] + 0.5f) / width; - td->loc2d[1] = floorf(height * td->loc2d[1] + 0.5f) / height; + td->loc2d[0] = roundf(width * td->loc2d[0]) / width; + td->loc2d[1] = roundf(height * td->loc2d[1]) / height; } } } @@ -3769,7 +3780,6 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) BezTriple *bezt; int count = 0, i; - float cfra; float mtx[3][3], smtx[3][3]; const bool is_translation_mode = graph_edit_is_translation_mode(t); const bool use_handle = !(sipo->flag & SIPO_NOHANDLES); @@ -3804,7 +3814,12 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(&ac, ale); FCurve *fcu = (FCurve *)ale->key_data; - + float cfra; + + /* F-Curve may not have any keyframes */ + if (fcu->bezt == NULL) + continue; + /* convert current-frame to action-time (slightly less accurate, especially under * higher scaling ratios, but is faster than converting all points) */ @@ -3812,45 +3827,27 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); else cfra = (float)CFRA; - - /* F-Curve may not have any keyframes */ - if (fcu->bezt == NULL) - continue; - + /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse */ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) { - const bool sel2 = bezt->f2 & SELECT; - const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2; - const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2; - - if (is_translation_mode) { - /* for 'normal' pivots - just include anything that is selected. - * this works a bit differently in translation modes */ - if (sel2) { + const bool sel2 = (bezt->f2 & SELECT) != 0; + const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2; + const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2; + + if (!is_translation_mode || !(sel2)) { + if (sel1) { count++; } - else { - if (sel1) count++; - if (sel3) count++; - } - } - else if (use_local_center) { - /* for local-pivot we only need to count the number of selected handles only, - * so that centerpoints don't get moved wrong - */ - if (bezt->ipo == BEZT_IPO_BEZ) { - if (sel1) count++; - if (sel3) count++; + + if (sel3) { + count++; } - /* else if (sel2) count++; // TODO: could this cause problems? */ - /* - yes this causes problems, because no td is created for the center point */ } - else { - /* for 'normal' pivots - just include anything that is selected */ - if (sel1) count++; - if (sel2) count++; - if (sel3) count++; + + /* only include main vert if selected */ + if (sel2 && !use_local_center) { + count++; } } } @@ -3899,8 +3896,13 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(&ac, ale); FCurve *fcu = (FCurve *)ale->key_data; - bool intvals = (fcu->flag & FCURVE_INT_VALUES); + bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0; float unit_scale; + float cfra; + + /* F-Curve may not have any keyframes */ + if (fcu->bezt == NULL) + continue; /* convert current-frame to action-time (slightly less accurate, especially under * higher scaling ratios, but is faster than converting all points) @@ -3909,19 +3911,15 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); else cfra = (float)CFRA; - - /* F-Curve may not have any keyframes */ - if (fcu->bezt == NULL) - continue; - + unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag); /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) { - const bool sel2 = bezt->f2 & SELECT; - const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2; - const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2; + const bool sel2 = (bezt->f2 & SELECT) != 0; + const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2; + const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2; TransDataCurveHandleFlags *hdata = NULL; /* short h1=1, h2=1; */ /* UNUSED */ @@ -4528,10 +4526,47 @@ static int SeqToTransData_Recursive(TransInfo *t, ListBase *seqbase, TransData * } } } - return tot; } + +static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts) +{ + Sequence *seq; + int recursive, count, flag; + int max = INT32_MIN, min = INT32_MAX; + + for (seq = seqbase->first; seq; seq = seq->next) { + + /* just to get the flag since there are corner cases where this isn't totally obvious */ + SeqTransInfo(t, seq, &recursive, &count, &flag); + + /* use 'flag' which is derived from seq->flag but modified for special cases */ + if (flag & SELECT) { + if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) { + if (flag & SEQ_LEFTSEL) { + min = min_ii(seq->startdisp, min); + max = max_ii(seq->startdisp, max); + } + if (flag & SEQ_RIGHTSEL) { + min = min_ii(seq->enddisp, min); + max = max_ii(seq->enddisp, max); + } + } + else { + min = min_ii(seq->startdisp, min); + max = max_ii(seq->enddisp, max); + } + } + } + + if (ts) { + ts->max = max; + ts->min = min; + } +} + + static void freeSeqData(TransInfo *t) { Editing *ed = BKE_sequencer_editing_get(t->scene, false); @@ -4694,6 +4729,8 @@ static void freeSeqData(TransInfo *t) } if ((t->customData != NULL) && (t->flag & T_FREE_CUSTOMDATA)) { + TransSeq *ts = t->customData; + MEM_freeN(ts->tdseq); MEM_freeN(t->customData); t->customData = NULL; } @@ -4713,6 +4750,8 @@ static void createTransSeqData(bContext *C, TransInfo *t) TransData *td = NULL; TransData2D *td2d = NULL; TransDataSeq *tdsq = NULL; + TransSeq *ts = NULL; + int xmouse; int count = 0; @@ -4723,12 +4762,11 @@ static void createTransSeqData(bContext *C, TransInfo *t) t->customFree = freeSeqData; + xmouse = (int)UI_view2d_region_to_view_x(v2d, t->imval[0]); + /* which side of the current frame should be allowed */ if (t->mode == TFM_TIME_EXTEND) { /* only side on which mouse is gets transformed */ - float xmouse, ymouse; - - UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &xmouse, &ymouse); t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; } else { @@ -4768,15 +4806,19 @@ static void createTransSeqData(bContext *C, TransInfo *t) return; } + t->customData = ts = MEM_mallocN(sizeof(TransSeq), "transseq"); td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransSeq TransData"); td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransSeq TransData2D"); - tdsq = t->customData = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq"); + ts->tdseq = tdsq = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq"); t->flag |= T_FREE_CUSTOMDATA; - - /* loop 2: build transdata array */ SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq); + SeqTransDataBounds(t, ed->seqbasep, ts); + + /* set the snap mode based on how close the mouse is at the end/start points */ + if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) + ts->snap_left = true; #undef XXX_DURIAN_ANIM_TX_HACK } @@ -5572,7 +5614,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } - if (t->spacetype == SPACE_SEQ) { + if (t->options & CTX_GPENCIL_STROKES) { + /* pass */ + } + else if (t->spacetype == SPACE_SEQ) { /* freeSeqData in transform_conversions.c does this * keep here so the else at the end wont run... */ @@ -7239,6 +7284,230 @@ void flushTransPaintCurve(TransInfo *t) } +static void createTransGPencil(bContext *C, TransInfo *t) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl; + TransData *td = NULL; + float mtx[3][3], smtx[3][3]; + + const Scene *scene = CTX_data_scene(C); + const int cfra = CFRA; + + const int propedit = (t->flag & T_PROP_EDIT); + const int propedit_connected = (t->flag & T_PROP_CONNECTED); + + + /* == Grease Pencil Strokes to Transform Data == + * Grease Pencil stroke points can be a mixture of 2D (screen-space), + * or 3D coordinates. However, they're always saved as 3D points. + * For now, we just do these without creating TransData2D for the 2D + * strokes. This may cause issues in future though. + */ + t->total = 0; + + if (gpd == NULL) + return; + + /* First Pass: Count the number of datapoints required for the strokes, + * (and additional info about the configuration - e.g. 2D/3D?) + */ + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* only editable and visible layers are considered */ + if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 && + (gpl->actframe != NULL)) + { + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps; + + for (gps = gpf->strokes.first; gps; gps = gps->next) { + if (propedit) { + /* Proportional Editing... */ + if (propedit_connected) { + /* connected only - so only if selected */ + if (gps->flag & GP_STROKE_SELECT) + t->total += gps->totpoints; + } + else { + /* everything goes - connection status doesn't matter */ + t->total += gps->totpoints; + } + } + else { + /* only selected stroke points are considered */ + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + // TODO: 2D vs 3D? + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) + t->total++; + } + } + } + } + } + } + + /* Stop trying if nothing selected */ + if (t->total == 0) { + return; + } + + /* Allocate memory for data */ + t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(GPencil)"); + td = t->data; + + unit_m3(smtx); + unit_m3(mtx); + + /* Second Pass: Build transdata array */ + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* only editable and visible layers are considered */ + if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 && + (gpl->actframe != NULL)) + { + bGPDframe *gpf = gpl->actframe; + bGPDstroke *gps; + + /* Make a new frame to work on if the layer's frame and the current scene frame don't match up + * - This is useful when animating as it saves that "uh-oh" moment when you realize you've + * spent too much time editing the wrong frame... + */ + // XXX: should this be allowed when framelock is enabled? + if (gpf->framenum != cfra) { + bGPDframe *new_frame = gpencil_frame_duplicate(gpf); + bGPDframe *gf; + bool found = false; + + /* Find frame to insert it before */ + for (gf = gpf->next; gf; gf = gf->next) { + if (gf->framenum > cfra) { + /* Add it here */ + BLI_insertlinkbefore(&gpl->frames, gf, new_frame); + + found = true; + break; + } + else if (gf->framenum == cfra) { + /* This only happens when we're editing with framelock on... + * - Delete the new frame and don't do anything else here... + */ + //printf("GP Frame convert to TransData - Copy aborted for frame %d -> %d\n", gpf->framenum, gf->framenum); + free_gpencil_strokes(new_frame); + MEM_freeN(new_frame); + new_frame = NULL; + + found = true; + break; + } + } + + if (found == false) { + /* Add new frame to the end */ + BLI_addtail(&gpl->frames, new_frame); + } + + /* Edit the new frame instead, if it did get created + added */ + if (new_frame) { + // TODO: tag this one as being "newly created" so that we can remove it if the edit is cancelled + new_frame->framenum = cfra; + + gpf = new_frame; + } + } + + /* Loop over strokes, adding TransData for points as needed... */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + TransData *head = td; + TransData *tail = td; + bool stroke_ok; + + /* What we need to include depends on proportional editing settings... */ + if (propedit) { + if (propedit_connected) { + /* A) "Connected" - Only those in selected strokes */ + stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; + } + else { + /* B) All points, always */ + stroke_ok = true; + } + } + else { + /* C) Only selected points in selected strokes */ + stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; + } + + /* Do stroke... */ + if (stroke_ok && gps->totpoints) { + bGPDspoint *pt; + int i; + +#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or propedit breaks */ + const float ninv = 1.0f / gps->totpoints; + float center[3] = {0.0f}; + + /* compute midpoint of stroke */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + madd_v3_v3v3fl(center, center, &pt->x, ninv); + } +#endif + + /* add all necessary points... */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + bool point_ok; + + /* include point? */ + if (propedit) { + /* Always all points in strokes that get included */ + point_ok = true; + } + else { + /* Only selected points in selected strokes */ + point_ok = (pt->flag & GP_SPOINT_SELECT) != 0; + } + + /* do point... */ + if (point_ok) { + copy_v3_v3(td->iloc, &pt->x); + copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local? + + td->loc = &pt->x; + + td->flag = 0; + + if (pt->flag & GP_SPOINT_SELECT) + td->flag |= TD_SELECTED; + + /* configure 2D points so that they don't play up... */ + if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) { + td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; + // XXX: matrices may need to be different? + } + + copy_m3_m3(td->smtx, smtx); + copy_m3_m3(td->mtx, mtx); + unit_m3(td->axismtx); // XXX? + + td++; + tail++; + } + } + + /* March over these points, and calculate the proportional editing distances */ + if (propedit && (head != tail)) { + /* XXX: for now, we are similar enough that this works... */ + calc_distanceCurveVerts(head, tail - 1); + } + } + } + } + } +} + + void createTransData(bContext *C, TransInfo *t) { Scene *scene = t->scene; @@ -7259,6 +7528,16 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } + else if (t->options & CTX_GPENCIL_STROKES) { + t->flag |= T_POINTS; // XXX... + createTransGPencil(C, t); + + if (t->data && (t->flag & T_PROP_EDIT)) { + sort_trans_data(t); // makes selected become first in array + set_prop_dist(t, 1); + sort_trans_data_dist(t); + } + } else if (t->spacetype == SPACE_IMAGE) { t->flag |= T_POINTS | T_2D_EDIT; if (t->options & CTX_MASK) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 52f02e5dc86..fcf789546e8 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -109,21 +109,7 @@ void getViewVector(TransInfo *t, float coord[3], float vec[3]) { if (t->persp != RV3D_ORTHO) { - float p1[4], p2[4]; - - copy_v3_v3(p1, coord); - p1[3] = 1.0f; - copy_v3_v3(p2, p1); - p2[3] = 1.0f; - mul_m4_v4(t->viewmat, p2); - - p2[0] = 2.0f * p2[0]; - p2[1] = 2.0f * p2[1]; - p2[2] = 2.0f * p2[2]; - - mul_m4_v4(t->viewinv, p2); - - sub_v3_v3v3(vec, p1, p2); + sub_v3_v3v3(vec, coord, t->viewinv[3]); } else { copy_v3_v3(vec, t->viewinv[2]); @@ -975,6 +961,9 @@ void recalcData(TransInfo *t) else if (t->options & CTX_PAINT_CURVE) { flushTransPaintCurve(t); } + else if (t->options & CTX_GPENCIL_STROKES) { + /* pass? */ + } else if (t->spacetype == SPACE_IMAGE) { recalcData_image(t); } @@ -1205,7 +1194,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* exceptional case */ if (t->around == V3D_LOCAL) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { - t->options |= CTX_NO_PET; + const bool use_island = transdata_check_local_islands(t, t->around); + + if (!use_island) { + t->options |= CTX_NO_PET; + } } } @@ -1325,6 +1318,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (t->obedit) { t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional); } + else if (t->options & CTX_GPENCIL_STROKES) { + t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional); + } else if (t->options & CTX_MASK) { if (ts->proportional_mask) { t->flag |= T_PROP_EDIT; diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index ece681b228e..25dee50a192 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -324,6 +324,9 @@ static void transformops_loopsel_hack(bContext *C, wmOperator *op) } } } +#else +/* prevent removal by cleanup */ +# error "loopslide hack removed!" #endif /* USE_LOOPSLIDE_HACK */ @@ -543,7 +546,11 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) } } } - + + if (flags & P_GPENCIL_EDIT) { + RNA_def_boolean(ot->srna, "gpencil_strokes", 0, "Edit Grease Pencil", "Edit selected Grease Pencil strokes"); + } + if ((flags & P_OPTIONS) && !(flags & P_NO_TEXSPACE)) { RNA_def_boolean(ot->srna, "texture_space", 0, "Edit Texture Space", "Edit Object data texture space"); prop = RNA_def_boolean(ot->srna, "remove_on_cancel", 0, "Remove on Cancel", "Remove elements on cancel"); @@ -578,7 +585,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot) RNA_def_float_vector_xyz(ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS); + Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS | P_GPENCIL_EDIT); } static void TRANSFORM_OT_resize(struct wmOperatorType *ot) @@ -598,7 +605,7 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot) RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS); + Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT); } static int skin_resize_poll(bContext *C) @@ -652,7 +659,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) prop = RNA_def_float_vector(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); RNA_def_property_subtype(prop, PROP_ANGLE); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); } static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) @@ -675,7 +682,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) prop = RNA_def_float(ot->srna, "value", 0.0f, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); RNA_def_property_subtype(prop, PROP_ANGLE); - Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP); + Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT); } static void TRANSFORM_OT_tilt(struct wmOperatorType *ot) @@ -721,7 +728,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot) RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); } static void TRANSFORM_OT_shear(struct wmOperatorType *ot) @@ -741,7 +748,7 @@ static void TRANSFORM_OT_shear(struct wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); // XXX Shear axis? } @@ -803,7 +810,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot) RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); } static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) @@ -821,7 +828,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL); + Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT); } static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index ba93d4463b7..79262396fb4 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -24,7 +24,6 @@ * \ingroup edtransform */ - #include <string.h> #include <stddef.h> #include <ctype.h> @@ -57,10 +56,6 @@ #include "ED_armature.h" -#include "RNA_define.h" - -#include "UI_interface.h" - #include "transform.h" /* *********************** TransSpace ************************** */ @@ -738,7 +733,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], v_pair_swap = true; } else if (eed && BM_edge_is_boundary(eed)) { - /* pradictable direction for boundary edges */ + /* predictable direction for boundary edges */ if (eed->l->v != v_pair[0]) { v_pair_swap = true; } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index cd636591212..4a2927ace00 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -59,6 +59,7 @@ #include "BKE_anim.h" /* for duplis */ #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_sequencer.h" #include "BKE_main.h" #include "BKE_tracking.h" @@ -2430,6 +2431,27 @@ void snapGridIncrement(TransInfo *t, float *val) snapGridIncrementAction(t, val, action); } +int snapSequenceBounds(TransInfo *t, const int mval[2]) +{ + float xmouse, ymouse; + int frame; + int mframe; + TransSeq *ts = t->customData; + /* reuse increment, strictly speaking could be another snap mode, but leave as is */ + if (!(t->modifiers & MOD_SNAP_INVERT)) + return 0; + + /* convert to frame range */ + UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse); + mframe = iroundf(xmouse); + /* now find the closest sequence */ + frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true); + + if (!ts->snap_left) + frame = frame - (ts->max - ts->min); + + return frame; +} static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action) { @@ -2457,6 +2479,19 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1); } } + else if ((t->spacetype == SPACE_IPO) && (t->mode == TFM_TRANSLATION)) { + View2D *v2d = &t->ar->v2d; + View2DGrid *grid; + SpaceIpo *sipo = t->sa->spacedata.first; + int unity = V2D_UNIT_VALUES; + int unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE; + + /* grid */ + grid = UI_view2d_grid_calc(t->scene, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, t->ar->winx, t->ar->winy); + + UI_view2d_grid_size(grid, &asp[0], &asp[1]); + UI_view2d_grid_free(grid); + } for (i = 0; i <= max_index; i++) { val[i] = fac[action] * asp[i] * floorf(val[i] / (fac[action] * asp[i]) + 0.5f); diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 86b96968047..32d4f2e5a15 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -174,7 +174,7 @@ bool ED_editors_flush_edits(const bContext *C, bool for_render) } else { /* Set reorder=false so that saving the file doesn't reorder - * the BMesh's elements */ + * the BMesh's elements */ BKE_sculptsession_bm_to_me(ob, false); } } diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c index ef95e4cb3ff..2428ee21367 100644 --- a/source/blender/editors/util/editmode_undo.c +++ b/source/blender/editors/util/editmode_undo.c @@ -48,8 +48,6 @@ #include "ED_util.h" #include "ED_mesh.h" -#include "UI_interface.h" -#include "UI_resources.h" #include "util_intern.h" diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 6c0efad6f26..fac57490b44 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -29,8 +29,6 @@ * \ingroup edutil */ - - #include <stdlib.h> #include <string.h> #include <math.h> @@ -47,6 +45,7 @@ #include "BKE_blender.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_screen.h" #include "ED_armature.h" @@ -124,6 +123,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); @@ -146,7 +146,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { if (U.uiflag & USER_GLOBALUNDO) { - ED_viewport_render_kill_jobs(C, true); + ED_viewport_render_kill_jobs(wm, bmain, true); BKE_undo_name(C, undoname); } } @@ -199,7 +199,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) /* for example, texface stores image pointers */ undo_editmode_clear(); - ED_viewport_render_kill_jobs(C, true); + ED_viewport_render_kill_jobs(wm, bmain, true); if (undoname) BKE_undo_name(C, undoname); @@ -379,7 +379,7 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) { int retval; - ED_viewport_render_kill_jobs(C, true); + ED_viewport_render_kill_jobs(wm, CTX_data_main(C), true); if (G.debug & G_DEBUG) printf("redo_cb: operator redo %s\n", op->type->name); @@ -583,7 +583,7 @@ static int undo_history_exec(bContext *C, wmOperator *op) ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item ); } else { - ED_viewport_render_kill_jobs(C, true); + ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); BKE_undo_number(C, item); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); } diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c index d0db3595c37..a15259e7d2d 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -53,7 +53,6 @@ #include "ED_uvedit.h" #include "UI_interface.h" -#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 4c93cfa2cc5..b2c4970479a 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -43,7 +43,6 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_alloca.h" #include "BLI_buffer.h" #include "BLI_bitmap.h" diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 8865bc6775b..d1fd8d969a4 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -72,7 +72,6 @@ void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditM /* utility tool functions */ void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); -void uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy); /* operators */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index b58944e4003..c70fcdbbd94 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -3189,8 +3189,8 @@ static void UV_OT_select_lasso(wmOperatorType *ot) static void uv_snap_to_pixel(float uvco[2], float w, float h) { - uvco[0] = ((float)((int)((uvco[0] * w) + 0.5f))) / w; - uvco[1] = ((float)((int)((uvco[1] * h) + 0.5f))) / h; + uvco[0] = roundf(uvco[0] * w) / w; + uvco[1] = roundf(uvco[1] * h) / h; } static void uv_snap_cursor_to_pixels(SpaceImage *sima) @@ -3877,6 +3877,15 @@ static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *e ARegion *ar = CTX_wm_region(C); float location[2]; + if (ar->regiontype == RGN_TYPE_WINDOW) { + if (event->mval[1] <= 16) { + SpaceImage *sima = CTX_wm_space_image(C); + if (sima && ED_space_image_show_cache(sima)) { + return OPERATOR_PASS_THROUGH; + } + } + } + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]); RNA_float_set_array(op->ptr, "location", location); diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 79f53e1d971..569fe1c326d 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -35,7 +35,6 @@ #include "BLI_boxpack2d.h" #include "BLI_convexhull2d.h" -#include "uvedit_intern.h" #include "uvedit_parametrizer.h" #include <math.h> @@ -3403,8 +3402,8 @@ static void p_chart_stretch_minimize(PChart *chart, RNG *rng) static int p_compare_geometric_uv(const void *a, const void *b) { - PVert *v1 = *(PVert **)a; - PVert *v2 = *(PVert **)b; + const PVert *v1 = *(const PVert * const *)a; + const PVert *v2 = *(const PVert * const *)b; if (v1->uv[0] < v2->uv[0]) return -1; @@ -3789,11 +3788,14 @@ static PBool p_node_intersect(SmoothNode *node, float co[2]) /* smoothing */ -static int p_compare_float(const void *a, const void *b) +static int p_compare_float(const void *a_, const void *b_) { - if (*((float *)a) < *((float *)b)) + const float a = *(const float *)a_; + const float b = *(const float *)b_; + + if (a < b) return -1; - else if (*((float *)a) == *((float *)b)) + else if (a == b) return 0; else return 1; @@ -4194,7 +4196,7 @@ void param_delete(ParamHandle *handle) static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts, ParamKey *vkeys, float **co, float **uv, - ParamBool *pin, ParamBool *select, float normal[3]) + ParamBool *pin, ParamBool *select, const float normal[3]) { int *boundary = BLI_array_alloca(boundary, nverts); int i; diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 9359baa5020..c5931cf2943 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1354,16 +1354,15 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) /* Stitch hash initialization functions */ static unsigned int uv_edge_hash(const void *key) { - UvEdge *edge = (UvEdge *)key; - return - BLI_ghashutil_uinthash(edge->uv2) + - BLI_ghashutil_uinthash(edge->uv1); + const UvEdge *edge = key; + return (BLI_ghashutil_uinthash(edge->uv2) + + BLI_ghashutil_uinthash(edge->uv1)); } static bool uv_edge_compare(const void *a, const void *b) { - UvEdge *edge1 = (UvEdge *)a; - UvEdge *edge2 = (UvEdge *)b; + const UvEdge *edge1 = a; + const UvEdge *edge2 = b; if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { return 0; @@ -1660,7 +1659,7 @@ static int stitch_init(bContext *C, wmOperator *op) return 0; } - uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy); + ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy); state->aspect = aspx / aspy; /* Entirely possible if redoing last operator that static island is bigger than total number of islands. diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 6a33351753e..b5e27ab0cf6 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -190,7 +190,7 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit) return false; } -void uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy) +void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy) { bool sloppy = true; bool selected = false; @@ -264,7 +264,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm, if (correct_aspect) { float aspx, aspy; - uvedit_get_aspect(scene, ob, bm, &aspx, &aspy); + ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy); if (aspx != aspy) param_aspect_ratio(handle, aspx, aspy); @@ -376,7 +376,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B if (correct_aspect) { float aspx, aspy; - uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); + ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); if (aspx != aspy) param_aspect_ratio(handle, aspx, aspy); @@ -1010,7 +1010,7 @@ static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); + ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); if (aspx == aspy) return; diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt index cb187eca6ac..6860afe64c2 100644 --- a/source/blender/freestyle/CMakeLists.txt +++ b/source/blender/freestyle/CMakeLists.txt @@ -392,6 +392,8 @@ set(SRC intern/scene_graph/NodeGroup.h intern/scene_graph/NodeLight.cpp intern/scene_graph/NodeLight.h + intern/scene_graph/NodeSceneRenderLayer.cpp + intern/scene_graph/NodeSceneRenderLayer.h intern/scene_graph/NodeShape.cpp intern/scene_graph/NodeShape.h intern/scene_graph/NodeTransform.cpp diff --git a/source/blender/freestyle/intern/application/AppConfig.cpp b/source/blender/freestyle/intern/application/AppConfig.cpp index cf7959ffaef..44f8e9b135e 100644 --- a/source/blender/freestyle/intern/application/AppConfig.cpp +++ b/source/blender/freestyle/intern/application/AppConfig.cpp @@ -31,7 +31,7 @@ using namespace std; extern "C" { -#include "BLI_path_util.h" +#include "BKE_appdir.h" } namespace Freestyle { @@ -43,7 +43,7 @@ Path::Path() { // get the root directory // soc - setRootDir(BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, NULL)); + setRootDir(BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, NULL)); _pInstance = this; } diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index 7ecb4164caf..f8931d32f56 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -40,6 +40,7 @@ extern "C" { #include "../scene_graph/NodeDrawingStyle.h" #include "../scene_graph/NodeShape.h" #include "../scene_graph/NodeTransform.h" +#include "../scene_graph/NodeSceneRenderLayer.h" #include "../scene_graph/ScenePrettyPrinter.h" #include "../scene_graph/VertexRep.h" @@ -67,6 +68,7 @@ extern "C" { #include "BKE_global.h" #include "BLI_utildefines.h" +#include "BLI_path_util.h" #include "DNA_freestyle_types.h" @@ -219,11 +221,10 @@ bool Controller::hitViewMapCache() if (!_EnableViewMapCache) { return false; } - real hashCode = sceneHashFunc.getValue(); - if (prevSceneHash == hashCode) { + if (sceneHashFunc.match()) { return (NULL != _ViewMap); } - prevSceneHash = hashCode; + sceneHashFunc.store(); return false; } @@ -280,10 +281,27 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl) return 0; if (_EnableViewMapCache) { + + NodeCamera *cam; + if (freestyle_proj[3][3] != 0.0) + cam = new NodeOrthographicCamera; + else + cam = new NodePerspectiveCamera; + double proj[16]; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + proj[i * 4 + j] = freestyle_proj[i][j]; + } + } + cam->setProjectionMatrix(proj); + _RootNode->AddChild(cam); + _RootNode->AddChild(new NodeSceneRenderLayer(*srl)); + sceneHashFunc.reset(); - blenderScene->accept(sceneHashFunc); + //blenderScene->accept(sceneHashFunc); + _RootNode->accept(sceneHashFunc); if (G.debug & G_DEBUG_FREESTYLE) { - printf("Scene hash : %.16e\n", sceneHashFunc.getValue()); + cout << "Scene hash : " << sceneHashFunc.toString() << endl; } if (hitViewMapCache()) { ClearRootNode(); @@ -864,10 +882,13 @@ void Controller::ResetRenderCount() Render *Controller::RenderStrokes(Render *re, bool render) { + int totmesh = 0; _Chrono.start(); BlenderStrokeRenderer *blenderRenderer = new BlenderStrokeRenderer(re, ++_render_count); - if (render) + if (render) { _Canvas->Render(blenderRenderer); + totmesh = blenderRenderer->GenerateScene(); + } real d = _Chrono.stop(); if (G.debug & G_DEBUG_FREESTYLE) { cout << "Temporary scene generation: " << d << endl; @@ -886,8 +907,8 @@ Render *Controller::RenderStrokes(Render *re, bool render) float mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0); float megs_peak_memory = (peak_memory) / (1024.0 * 1024.0); - printf("%d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n", - freestyle_render->i.totvert, freestyle_render->i.totface, + printf("%d objs, %d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n", + totmesh, freestyle_render->i.totvert, freestyle_render->i.totface, megs_used_memory, mmap_used_memory, megs_peak_memory); } delete blenderRenderer; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 09701ab6acd..29f3bfe0d94 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -66,6 +66,8 @@ extern "C" { namespace Freestyle { +const char *BlenderStrokeRenderer::uvNames[] = {"along_stroke", "along_stroke_tips"}; + BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : StrokeRenderer() { freestyle_bmain = re->freestyle_bmain; @@ -208,6 +210,8 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer() if (_use_shading_nodes) BLI_ghash_free(_nodetree_hash, NULL, NULL); + + FreeStrokeGroups(); } float BlenderStrokeRenderer::get_stroke_vertex_z(void) const @@ -414,10 +418,10 @@ Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTr input_uvmap->locy = node->locy; NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage; if (node->custom1 & 1) { // use_tips - BLI_strncpy(storage->uv_map, "along_stroke_tips", sizeof(storage->uv_map)); + BLI_strncpy(storage->uv_map, uvNames[1], sizeof(storage->uv_map)); } else { - BLI_strncpy(storage->uv_map, "along_stroke", sizeof(storage->uv_map)); + BLI_strncpy(storage->uv_map, uvNames[0], sizeof(storage->uv_map)); } fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV @@ -440,6 +444,11 @@ Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTr void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const { + RenderStrokeRepBasic(iStrokeRep); +} + +void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const +{ if (_use_shading_nodes) { bNodeTree *nt = iStrokeRep->getNodeTree(); Material *ma = (Material *)BLI_ghash_lookup(_nodetree_hash, nt); @@ -509,10 +518,10 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const // We'll generate both with tips and without tips // coordinates, on two different UV layers. if (ma->mtex[a]->texflag & MTEX_TIPS) { - BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname)); + BLI_strncpy(ma->mtex[a]->uvname, uvNames[1], sizeof(ma->mtex[a]->uvname)); } else { - BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname)); + BLI_strncpy(ma->mtex[a]->uvname, uvNames[0], sizeof(ma->mtex[a]->uvname)); } a++; } @@ -521,7 +530,42 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const } } - RenderStrokeRepBasic(iStrokeRep); + const vector<Strip*>& strips = iStrokeRep->getStrips(); + const bool hasTex = iStrokeRep->hasTex(); + int totvert = 0, totedge = 0, totpoly = 0, totloop = 0; + int visible_faces, visible_segments; + for (vector<Strip*>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) { + Strip::vertex_container& strip_vertices = (*s)->vertices(); + + // count visible faces and strip segments + test_strip_visibility(strip_vertices, &visible_faces, &visible_segments); + if (visible_faces == 0) + continue; + + totvert += visible_faces + visible_segments * 2; + totedge += visible_faces * 2 + visible_segments; + totpoly += visible_faces; + totloop += visible_faces * 3; + } + + BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this); // FIXME + vector<StrokeGroup*> *groups = hasTex ? &self->texturedStrokeGroups : &self->strokeGroups; + StrokeGroup *group; + if (groups->empty() || !(groups->back()->totvert + totvert < MESH_MAX_VERTS && + groups->back()->totcol + 1 < MAXMAT)) + { + group = new StrokeGroup; + groups->push_back(group); + } + else { + group = groups->back(); + } + group->strokes.push_back(iStrokeRep); + group->totvert += totvert; + group->totedge += totedge; + group->totpoly += totpoly; + group->totloop += totloop; + group->totcol++; } // Check if the triangle is visible (i.e., within the render image boundary) @@ -578,127 +622,168 @@ void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container& strip } } -// Build a mesh object representing a stroke -void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const +// Release allocated memory for stroke groups +void BlenderStrokeRenderer::FreeStrokeGroups() { - vector<Strip*>& strips = iStrokeRep->getStrips(); - const bool hasTex = iStrokeRep->hasTex(); - Strip::vertex_container::iterator v[3]; - StrokeVertexRep *svRep[3]; - unsigned int vertex_index, edge_index, loop_index; - Vec2r p; + vector<StrokeGroup*>::const_iterator it, itend; - int totvert = 0, totedge = 0, totpoly = 0, totloop = 0; - int visible_faces, visible_segments; - - bool visible; - for (vector<Strip*>::iterator s = strips.begin(), send = strips.end(); s != send; ++s) { - Strip::vertex_container& strip_vertices = (*s)->vertices(); + for (it = strokeGroups.begin(), itend = strokeGroups.end(); + it != itend; ++it) + { + delete (*it); + } + for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); + it != itend; ++it) + { + delete (*it); + } +} - // count visible faces and strip segments - test_strip_visibility(strip_vertices, &visible_faces, &visible_segments); - if (visible_faces == 0) - continue; +// Build a scene populated by mesh objects representing stylized strokes +int BlenderStrokeRenderer::GenerateScene() +{ + vector<StrokeGroup*>::const_iterator it, itend; - totvert += visible_faces + visible_segments * 2; - totedge += visible_faces * 2 + visible_segments; - totpoly += visible_faces; - totloop += visible_faces * 3; + for (it = strokeGroups.begin(), itend = strokeGroups.end(); + it != itend; ++it) + { + GenerateStrokeMesh(*it, false); + } + for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); + it != itend; ++it) + { + GenerateStrokeMesh(*it, true); } + return strokeGroups.size() + texturedStrokeGroups.size(); +} +// Build a mesh object representing a group of stylized strokes +void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) +{ #if 0 Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, OB_MESH); #else Object *object_mesh = NewMesh(); #endif Mesh *mesh = (Mesh *)object_mesh->data; - mesh->mat = (Material **)MEM_mallocN(1 * sizeof(Material *), "MaterialList"); - mesh->mat[0] = iStrokeRep->getMaterial(); - mesh->totcol = 1; - test_object_materials(freestyle_bmain, (ID *)mesh); - // vertices allocation - mesh->totvert = totvert; // visible_faces + visible_segments * 2; - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + mesh->totvert = group->totvert; + mesh->totedge = group->totedge; + mesh->totpoly = group->totpoly; + mesh->totloop = group->totloop; + mesh->totcol = group->totcol; - // edges allocation - mesh->totedge = totedge; // visible_faces * 2 + visible_segments; - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + mesh->mvert = (MVert *)CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + mesh->medge = (MEdge *)CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + mesh->mpoly = (MPoly *)CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); + mesh->mloop = (MLoop *)CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); - // faces allocation - mesh->totpoly = totpoly; // visible_faces; - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); - - // loops allocation - mesh->totloop = totloop; // visible_faces * 3; - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); - - // uv maps + MVert *vertices = mesh->mvert; + MEdge *edges = mesh->medge; + MPoly *polys = mesh->mpoly; + MLoop *loops = mesh->mloop; MLoopUV *loopsuv[2] = { NULL }; - if (hasTex) { - loopsuv[0] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke"); - loopsuv[1] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke_tips"); - CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke"); - CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke_tips"); + if (hasTex) { + // First UV layer + CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, uvNames[0]); + CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, uvNames[0]); + CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 0); + CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 0); + BKE_mesh_update_customdata_pointers(mesh, true); + loopsuv[0] = mesh->mloopuv; + + // Second UV layer + CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, uvNames[1]); + CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, uvNames[1]); + CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 1); + CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 1); + BKE_mesh_update_customdata_pointers(mesh, true); + loopsuv[1] = mesh->mloopuv; } // colors and transparency (the latter represented by grayscale colors) MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Color"); MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Alpha"); + mesh->mloopcol = colors; - BKE_mesh_update_customdata_pointers(mesh, true); + mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList"); //////////////////// // Data copy //////////////////// - MVert *vertices = mesh->mvert; - MEdge *edges = mesh->medge; - MPoly *polys = mesh->mpoly; - MLoop *loops = mesh->mloop; + int vertex_index = 0, edge_index = 0, loop_index = 0, material_index = 0; + int visible_faces, visible_segments; + bool visible; + Strip::vertex_container::iterator v[3]; + StrokeVertexRep *svRep[3]; + Vec2r p; - vertex_index = edge_index = loop_index = 0; + for (vector<StrokeRep*>::const_iterator it = group->strokes.begin(), itend = group->strokes.end(); + it != itend; ++it) + { + mesh->mat[material_index] = (*it)->getMaterial(); + material_index++; - for (vector<Strip*>::iterator s = strips.begin(), send = strips.end(); s != send; ++s) { - Strip::vertex_container& strip_vertices = (*s)->vertices(); - int strip_vertex_count = strip_vertices.size(); + vector<Strip*>& strips = (*it)->getStrips(); + for (vector<Strip*>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) { + Strip::vertex_container& strip_vertices = (*s)->vertices(); + int strip_vertex_count = strip_vertices.size(); - // count visible faces and strip segments - test_strip_visibility(strip_vertices, &visible_faces, &visible_segments); - if (visible_faces == 0) - continue; + // count visible faces and strip segments + test_strip_visibility(strip_vertices, &visible_faces, &visible_segments); + if (visible_faces == 0) + continue; - v[0] = strip_vertices.begin(); - v[1] = v[0] + 1; - v[2] = v[0] + 2; + v[0] = strip_vertices.begin(); + v[1] = v[0] + 1; + v[2] = v[0] + 2; - visible = false; + visible = false; - // Note: Mesh generation in the following loop assumes stroke strips - // to be triangle strips. - for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) { - svRep[0] = *(v[0]); - svRep[1] = *(v[1]); - svRep[2] = *(v[2]); - if (!test_triangle_visibility(svRep)) { - visible = false; - } - else { - if (!visible) { - // first vertex - vertices->co[0] = svRep[0]->point2d()[0]; - vertices->co[1] = svRep[0]->point2d()[1]; - vertices->co[2] = get_stroke_vertex_z(); - vertices->no[0] = 0; - vertices->no[1] = 0; - vertices->no[2] = SHRT_MAX; - ++vertices; - ++vertex_index; + // Note: Mesh generation in the following loop assumes stroke strips + // to be triangle strips. + for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) { + svRep[0] = *(v[0]); + svRep[1] = *(v[1]); + svRep[2] = *(v[2]); + if (!test_triangle_visibility(svRep)) { + visible = false; + } + else { + if (!visible) { + // first vertex + vertices->co[0] = svRep[0]->point2d()[0]; + vertices->co[1] = svRep[0]->point2d()[1]; + vertices->co[2] = get_stroke_vertex_z(); + vertices->no[0] = 0; + vertices->no[1] = 0; + vertices->no[2] = SHRT_MAX; + ++vertices; + ++vertex_index; + + // second vertex + vertices->co[0] = svRep[1]->point2d()[0]; + vertices->co[1] = svRep[1]->point2d()[1]; + vertices->co[2] = get_stroke_vertex_z(); + vertices->no[0] = 0; + vertices->no[1] = 0; + vertices->no[2] = SHRT_MAX; + ++vertices; + ++vertex_index; + + // first edge + edges->v1 = vertex_index - 2; + edges->v2 = vertex_index - 1; + ++edges; + ++edge_index; + } + visible = true; - // second vertex - vertices->co[0] = svRep[1]->point2d()[0]; - vertices->co[1] = svRep[1]->point2d()[1]; + // vertex + vertices->co[0] = svRep[2]->point2d()[0]; + vertices->co[1] = svRep[2]->point2d()[1]; vertices->co[2] = get_stroke_vertex_z(); vertices->no[0] = 0; vertices->no[1] = 0; @@ -706,140 +791,127 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const ++vertices; ++vertex_index; - // first edge - edges->v1 = vertex_index - 2; - edges->v2 = vertex_index - 1; + // edges + edges->v1 = vertex_index - 1; + edges->v2 = vertex_index - 3; ++edges; ++edge_index; - } - visible = true; - - // vertex - vertices->co[0] = svRep[2]->point2d()[0]; - vertices->co[1] = svRep[2]->point2d()[1]; - vertices->co[2] = get_stroke_vertex_z(); - vertices->no[0] = 0; - vertices->no[1] = 0; - vertices->no[2] = SHRT_MAX; - ++vertices; - ++vertex_index; - - // edges - edges->v1 = vertex_index - 1; - edges->v2 = vertex_index - 3; - ++edges; - ++edge_index; - - edges->v1 = vertex_index - 1; - edges->v2 = vertex_index - 2; - ++edges; - ++edge_index; - - // poly - polys->loopstart = loop_index; - polys->totloop = 3; - ++polys; - - // Even and odd loops connect triangles vertices differently - bool is_odd = n % 2; - // loops - if (is_odd) { - loops[0].v = vertex_index - 1; - loops[0].e = edge_index - 2; - - loops[1].v = vertex_index - 3; - loops[1].e = edge_index - 3; - - loops[2].v = vertex_index - 2; - loops[2].e = edge_index - 1; - } - else { - loops[0].v = vertex_index - 1; - loops[0].e = edge_index - 1; - loops[1].v = vertex_index - 2; - loops[1].e = edge_index - 3; + edges->v1 = vertex_index - 1; + edges->v2 = vertex_index - 2; + ++edges; + ++edge_index; - loops[2].v = vertex_index - 3; - loops[2].e = edge_index - 2; - } - loops += 3; - loop_index += 3; - - // UV - if (hasTex) { - // First UV layer (loopsuv[0]) has no tips (texCoord(0)). - // Second UV layer (loopsuv[1]) has tips: (texCoord(1)). - for (int L = 0; L < 2; L++) { - if (is_odd) { - loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x(); - loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y(); - - loopsuv[L][1].uv[0] = svRep[0]->texCoord(L).x(); - loopsuv[L][1].uv[1] = svRep[0]->texCoord(L).y(); - - loopsuv[L][2].uv[0] = svRep[1]->texCoord(L).x(); - loopsuv[L][2].uv[1] = svRep[1]->texCoord(L).y(); - } - else { - loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x(); - loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y(); + // poly + polys->loopstart = loop_index; + polys->totloop = 3; + ++polys; + + // Even and odd loops connect triangles vertices differently + bool is_odd = n % 2; + // loops + if (is_odd) { + loops[0].v = vertex_index - 1; + loops[0].e = edge_index - 2; - loopsuv[L][1].uv[0] = svRep[1]->texCoord(L).x(); - loopsuv[L][1].uv[1] = svRep[1]->texCoord(L).y(); + loops[1].v = vertex_index - 3; + loops[1].e = edge_index - 3; - loopsuv[L][2].uv[0] = svRep[0]->texCoord(L).x(); - loopsuv[L][2].uv[1] = svRep[0]->texCoord(L).y(); + loops[2].v = vertex_index - 2; + loops[2].e = edge_index - 1; + } + else { + loops[0].v = vertex_index - 1; + loops[0].e = edge_index - 1; + + loops[1].v = vertex_index - 2; + loops[1].e = edge_index - 3; + + loops[2].v = vertex_index - 3; + loops[2].e = edge_index - 2; + } + loops += 3; + loop_index += 3; + + // UV + if (hasTex) { + // First UV layer (loopsuv[0]) has no tips (texCoord(0)). + // Second UV layer (loopsuv[1]) has tips: (texCoord(1)). + for (int L = 0; L < 2; L++) { + if (is_odd) { + loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x(); + loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y(); + + loopsuv[L][1].uv[0] = svRep[0]->texCoord(L).x(); + loopsuv[L][1].uv[1] = svRep[0]->texCoord(L).y(); + + loopsuv[L][2].uv[0] = svRep[1]->texCoord(L).x(); + loopsuv[L][2].uv[1] = svRep[1]->texCoord(L).y(); + } + else { + loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x(); + loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y(); + + loopsuv[L][1].uv[0] = svRep[1]->texCoord(L).x(); + loopsuv[L][1].uv[1] = svRep[1]->texCoord(L).y(); + + loopsuv[L][2].uv[0] = svRep[0]->texCoord(L).x(); + loopsuv[L][2].uv[1] = svRep[0]->texCoord(L).y(); + } + loopsuv[L] += 3; } - loopsuv[L] += 3; } - } - // colors and alpha transparency - if (is_odd) { - colors[0].r = (short)(255.0f * svRep[2]->color()[0]); - colors[0].g = (short)(255.0f * svRep[2]->color()[1]); - colors[0].b = (short)(255.0f * svRep[2]->color()[2]); - colors[0].a = (short)(255.0f * svRep[2]->alpha()); - - colors[1].r = (short)(255.0f * svRep[0]->color()[0]); - colors[1].g = (short)(255.0f * svRep[0]->color()[1]); - colors[1].b = (short)(255.0f * svRep[0]->color()[2]); - colors[1].a = (short)(255.0f * svRep[0]->alpha()); - - colors[2].r = (short)(255.0f * svRep[1]->color()[0]); - colors[2].g = (short)(255.0f * svRep[1]->color()[1]); - colors[2].b = (short)(255.0f * svRep[1]->color()[2]); - colors[2].a = (short)(255.0f * svRep[1]->alpha()); - } - else { - colors[0].r = (short)(255.0f * svRep[2]->color()[0]); - colors[0].g = (short)(255.0f * svRep[2]->color()[1]); - colors[0].b = (short)(255.0f * svRep[2]->color()[2]); - colors[0].a = (short)(255.0f * svRep[2]->alpha()); - - colors[1].r = (short)(255.0f * svRep[1]->color()[0]); - colors[1].g = (short)(255.0f * svRep[1]->color()[1]); - colors[1].b = (short)(255.0f * svRep[1]->color()[2]); - colors[1].a = (short)(255.0f * svRep[1]->alpha()); - - colors[2].r = (short)(255.0f * svRep[0]->color()[0]); - colors[2].g = (short)(255.0f * svRep[0]->color()[1]); - colors[2].b = (short)(255.0f * svRep[0]->color()[2]); - colors[2].a = (short)(255.0f * svRep[0]->alpha()); + // colors and alpha transparency + if (is_odd) { + colors[0].r = (short)(255.0f * svRep[2]->color()[0]); + colors[0].g = (short)(255.0f * svRep[2]->color()[1]); + colors[0].b = (short)(255.0f * svRep[2]->color()[2]); + colors[0].a = (short)(255.0f * svRep[2]->alpha()); + + colors[1].r = (short)(255.0f * svRep[0]->color()[0]); + colors[1].g = (short)(255.0f * svRep[0]->color()[1]); + colors[1].b = (short)(255.0f * svRep[0]->color()[2]); + colors[1].a = (short)(255.0f * svRep[0]->alpha()); + + colors[2].r = (short)(255.0f * svRep[1]->color()[0]); + colors[2].g = (short)(255.0f * svRep[1]->color()[1]); + colors[2].b = (short)(255.0f * svRep[1]->color()[2]); + colors[2].a = (short)(255.0f * svRep[1]->alpha()); + } + else { + colors[0].r = (short)(255.0f * svRep[2]->color()[0]); + colors[0].g = (short)(255.0f * svRep[2]->color()[1]); + colors[0].b = (short)(255.0f * svRep[2]->color()[2]); + colors[0].a = (short)(255.0f * svRep[2]->alpha()); + + colors[1].r = (short)(255.0f * svRep[1]->color()[0]); + colors[1].g = (short)(255.0f * svRep[1]->color()[1]); + colors[1].b = (short)(255.0f * svRep[1]->color()[2]); + colors[1].a = (short)(255.0f * svRep[1]->alpha()); + + colors[2].r = (short)(255.0f * svRep[0]->color()[0]); + colors[2].g = (short)(255.0f * svRep[0]->color()[1]); + colors[2].b = (short)(255.0f * svRep[0]->color()[2]); + colors[2].a = (short)(255.0f * svRep[0]->alpha()); + } + transp[0].r = transp[0].g = transp[0].b = colors[0].a; + transp[1].r = transp[1].g = transp[1].b = colors[1].a; + transp[2].r = transp[2].g = transp[2].b = colors[2].a; + colors += 3; + transp += 3; } - transp[0].r = transp[0].g = transp[0].b = colors[0].a; - transp[1].r = transp[1].g = transp[1].b = colors[1].a; - transp[2].r = transp[2].g = transp[2].b = colors[2].a; - colors += 3; - transp += 3; - } - } // loop over strip vertices - } // loop over strips -#if 0 - BLI_assert(totvert == vertex_index); - BLI_assert(totedge == edge_index); - BLI_assert(totloop == loop_index); + } // loop over strip vertices + } // loop over strips + } // loop over strokes + + test_object_materials(freestyle_bmain, (ID *)mesh); + +#if 0 // XXX + BLI_assert(mesh->totvert == vertex_index); + BLI_assert(mesh->totedge == edge_index); + BLI_assert(mesh->totloop == loop_index); + BLI_assert(mesh->totcol == material_index); BKE_mesh_validate(mesh, true); #endif } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h index 74e5d321df2..a381932e9e7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h @@ -53,6 +53,21 @@ public: Object *NewMesh() const; + struct StrokeGroup { + explicit StrokeGroup() : totvert(0), totedge(0), totpoly(0), totloop(0), totcol(0) {} + vector<StrokeRep*> strokes; + int totvert; + int totedge; + int totpoly; + int totloop; + int totcol; + }; + vector<StrokeGroup*> strokeGroups, texturedStrokeGroups; + + int GenerateScene(); + void GenerateStrokeMesh(StrokeGroup *group, bool hasTex); + void FreeStrokeGroups(); + Render *RenderScene(Render *re, bool render); static Material* GetStrokeShader(Main *bmain, bNodeTree *iNodeTree, bool do_id_user); @@ -68,12 +83,16 @@ protected: bool _use_shading_nodes; struct GHash *_nodetree_hash; + static const char *uvNames[]; + float get_stroke_vertex_z(void) const; unsigned int get_stroke_mesh_id(void) const; bool test_triangle_visibility(StrokeVertexRep *svRep[3]) const; void test_strip_visibility(Strip::vertex_container& strip_vertices, int *visible_faces, int *visible_segments) const; + vector<StrokeRep *> _strokeReps; + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStrokeRenderer") #endif diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp index dd678ee6fbd..ad54a81f156 100644 --- a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp +++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp @@ -92,10 +92,11 @@ ContextFunctions_get_border(PyObject *self) { BBox<Vec2i> border(ContextFunctions::GetBorderCF()); PyObject *v = PyTuple_New(4); - PyTuple_SET_ITEM(v, 0, PyLong_FromLong(border.getMin().x())); - PyTuple_SET_ITEM(v, 1, PyLong_FromLong(border.getMin().y())); - PyTuple_SET_ITEM(v, 2, PyLong_FromLong(border.getMax().x())); - PyTuple_SET_ITEM(v, 3, PyLong_FromLong(border.getMax().y())); + PyTuple_SET_ITEMS(v, + PyLong_FromLong(border.getMin().x()), + PyLong_FromLong(border.getMin().y()), + PyLong_FromLong(border.getMax().x()), + PyLong_FromLong(border.getMax().y())); return v; } diff --git a/source/blender/freestyle/intern/python/BPy_Convert.cpp b/source/blender/freestyle/intern/python/BPy_Convert.cpp index dbd836bc562..4e1a0a119aa 100644 --- a/source/blender/freestyle/intern/python/BPy_Convert.cpp +++ b/source/blender/freestyle/intern/python/BPy_Convert.cpp @@ -81,7 +81,7 @@ PyObject *Vector_from_Vec2f(Vec2f& vec) float vec_data[2]; // because vec->_coord is protected vec_data[0] = vec.x(); vec_data[1] = vec.y(); - return Vector_CreatePyObject(vec_data, 2, Py_NEW, NULL); + return Vector_CreatePyObject(vec_data, 2, NULL); } PyObject *Vector_from_Vec3f(Vec3f& vec) @@ -90,7 +90,7 @@ PyObject *Vector_from_Vec3f(Vec3f& vec) vec_data[0] = vec.x(); vec_data[1] = vec.y(); vec_data[2] = vec.z(); - return Vector_CreatePyObject(vec_data, 3, Py_NEW, NULL); + return Vector_CreatePyObject(vec_data, 3, NULL); } PyObject *Vector_from_Vec3r(Vec3r& vec) @@ -99,7 +99,7 @@ PyObject *Vector_from_Vec3r(Vec3r& vec) vec_data[0] = vec.x(); vec_data[1] = vec.y(); vec_data[2] = vec.z(); - return Vector_CreatePyObject(vec_data, 3, Py_NEW, NULL); + return Vector_CreatePyObject(vec_data, 3, NULL); } PyObject *BPy_Id_from_Id(Id& id) @@ -401,8 +401,9 @@ PyObject *BPy_CurvePoint_from_CurvePoint(CurvePoint& cp) PyObject *BPy_directedViewEdge_from_directedViewEdge(ViewVertex::directedViewEdge& dve) { PyObject *py_dve = PyTuple_New(2); - PyTuple_SET_ITEM(py_dve, 0, BPy_ViewEdge_from_ViewEdge(*(dve.first))); - PyTuple_SET_ITEM(py_dve, 1, PyBool_from_bool(dve.second)); + PyTuple_SET_ITEMS(py_dve, + BPy_ViewEdge_from_ViewEdge(*(dve.first)), + PyBool_from_bool(dve.second)); return py_dve; } diff --git a/source/blender/freestyle/intern/python/BPy_Convert.h b/source/blender/freestyle/intern/python/BPy_Convert.h index e6e763e763e..35c1e58369c 100644 --- a/source/blender/freestyle/intern/python/BPy_Convert.h +++ b/source/blender/freestyle/intern/python/BPy_Convert.h @@ -92,6 +92,7 @@ extern "C" { /////////////////////////////////////////////////////////////////////////////////////////// #include "mathutils/mathutils.h" +#include "generic/python_utildefines.h" //============================== // C++ => Python diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp index 5b8d50eb5eb..f4ead300d5e 100644 --- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp +++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp @@ -60,6 +60,7 @@ extern "C" { #include "FRS_freestyle.h" #include "RNA_access.h" +#include "BKE_appdir.h" #include "DNA_scene_types.h" #include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */ @@ -152,7 +153,7 @@ static PyObject *Freestyle_blendRamp(PyObject *self, PyObject *args) return NULL; } ramp_blend(type, a, fac, b); - return Vector_CreatePyObject(a, 3, Py_NEW, NULL); + return Vector_CreatePyObject(a, 3, NULL); } #include "BKE_texture.h" /* do_colorband() */ @@ -186,7 +187,7 @@ static PyObject *Freestyle_evaluateColorRamp(PyObject *self, PyObject *args) PyErr_SetString(PyExc_ValueError, "failed to evaluate the color ramp"); return NULL; } - return Vector_CreatePyObject(out, 4, Py_NEW, NULL); + return Vector_CreatePyObject(out, 4, NULL); } #include "DNA_color_types.h" @@ -492,7 +493,7 @@ PyObject *Freestyle_Init(void) PyDict_SetItemString(PySys_GetObject("modules"), module_definition.m_name, module); // update 'sys.path' for Freestyle Python API modules - const char * const path = BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, "freestyle"); + const char * const path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "freestyle"); if (path) { char modpath[FILE_MAX]; BLI_join_dirfile(modpath, sizeof(modpath), path, "modules"); diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp index d3cb44f5903..57ec15f4150 100644 --- a/source/blender/freestyle/intern/python/BPy_Operators.cpp +++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp @@ -532,8 +532,9 @@ static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject return NULL; } vector<StrokeShader *> shaders; + shaders.reserve(PyList_Size(obj2)); for (int i = 0; i < PyList_Size(obj2); i++) { - PyObject *py_ss = PyList_GetItem(obj2, i); + PyObject *py_ss = PyList_GET_ITEM(obj2, i); if (!BPy_StrokeShader_Check(py_ss)) { PyErr_SetString(PyExc_TypeError, "Operators.create(): 2nd argument must be a list of StrokeShader objects"); return NULL; diff --git a/source/blender/freestyle/intern/python/BPy_SShape.cpp b/source/blender/freestyle/intern/python/BPy_SShape.cpp index e5a38171ecd..11ed07df5de 100644 --- a/source/blender/freestyle/intern/python/BPy_SShape.cpp +++ b/source/blender/freestyle/intern/python/BPy_SShape.cpp @@ -227,13 +227,14 @@ PyDoc_STRVAR(SShape_vertices_doc, static PyObject *SShape_vertices_get(BPy_SShape *self, void *UNUSED(closure)) { - PyObject *py_vertices = PyList_New(0); vector< SVertex * > vertices = self->ss->getVertexList(); vector< SVertex * >::iterator it; + PyObject *py_vertices = PyList_New(vertices.size()); + unsigned int i = 0; for (it = vertices.begin(); it != vertices.end(); it++) { - PyList_Append(py_vertices, BPy_SVertex_from_SVertex(*(*it))); + PyList_SET_ITEM(py_vertices, i++, BPy_SVertex_from_SVertex(*(*it))); } return py_vertices; @@ -246,13 +247,14 @@ PyDoc_STRVAR(SShape_edges_doc, static PyObject *SShape_edges_get(BPy_SShape *self, void *UNUSED(closure)) { - PyObject *py_edges = PyList_New(0); vector< FEdge * > edges = self->ss->getEdgeList(); vector< FEdge * >::iterator it; + PyObject *py_edges = PyList_New(edges.size()); + unsigned int i = 0; for (it = edges.begin(); it != edges.end(); it++) { - PyList_Append(py_edges, Any_BPy_FEdge_from_FEdge(*(*it))); + PyList_SET_ITEM(py_edges, i++, Any_BPy_FEdge_from_FEdge(*(*it))); } return py_edges; diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp index 2c767eacaec..6c6e821a1e4 100644 --- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp +++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp @@ -207,12 +207,13 @@ PyDoc_STRVAR(ViewShape_vertices_doc, static PyObject *ViewShape_vertices_get(BPy_ViewShape *self, void *UNUSED(closure)) { - PyObject *py_vertices = PyList_New(0); - vector<ViewVertex *> vertices = self->vs->vertices(); vector<ViewVertex *>::iterator it; + PyObject *py_vertices = PyList_New(vertices.size()); + unsigned int i = 0; + for (it = vertices.begin(); it != vertices.end(); it++) { - PyList_Append( py_vertices, Any_BPy_ViewVertex_from_ViewVertex(*(*it))); + PyList_SET_ITEM(py_vertices, i++, Any_BPy_ViewVertex_from_ViewVertex(*(*it))); } return py_vertices; } @@ -227,8 +228,10 @@ static int ViewShape_vertices_set(BPy_ViewShape *self, PyObject *value, void *UN PyErr_SetString(PyExc_TypeError, "value must be a list of ViewVertex objects"); return -1; } - for (int i = 0; i < PyList_Size(list); i++) { - item = PyList_GetItem(list, i); + + v.reserve(PyList_Size(list)); + for (unsigned int i = 0; i < PyList_Size(list); i++) { + item = PyList_GET_ITEM(list, i); if (BPy_ViewVertex_Check(item)) { v.push_back(((BPy_ViewVertex *)item)->vv); } @@ -248,13 +251,13 @@ PyDoc_STRVAR(ViewShape_edges_doc, static PyObject *ViewShape_edges_get(BPy_ViewShape *self, void *UNUSED(closure)) { - PyObject *py_edges = PyList_New(0); - vector<ViewEdge *> edges = self->vs->edges(); vector<ViewEdge *>::iterator it; + PyObject *py_edges = PyList_New(edges.size()); + unsigned int i = 0; for (it = edges.begin(); it != edges.end(); it++) { - PyList_Append(py_edges, BPy_ViewEdge_from_ViewEdge(*(*it))); + PyList_SET_ITEM(py_edges, i++, BPy_ViewEdge_from_ViewEdge(*(*it))); } return py_edges; } @@ -269,8 +272,10 @@ static int ViewShape_edges_set(BPy_ViewShape *self, PyObject *value, void *UNUSE PyErr_SetString(PyExc_TypeError, "value must be a list of ViewEdge objects"); return -1; } + + v.reserve(PyList_Size(list)); for (int i = 0; i < PyList_Size(list); i++) { - item = PyList_GetItem(list, i); + item = PyList_GET_ITEM(list, i); if (BPy_ViewEdge_Check(item)) { v.push_back(((BPy_ViewEdge *)item)->ve); } diff --git a/source/blender/freestyle/intern/python/Director.cpp b/source/blender/freestyle/intern/python/Director.cpp index 653fd0b1d29..9f85e84e297 100644 --- a/source/blender/freestyle/intern/python/Director.cpp +++ b/source/blender/freestyle/intern/python/Director.cpp @@ -265,8 +265,9 @@ int Director_BPy_UnaryFunction0D___call__(void *uf0D, void *py_uf0D, Interface0D } else if (BPy_UnaryFunction0DVectorViewShape_Check(obj)) { vector<ViewShape*> vec; + vec.reserve(PyList_Size(result)); for (int i = 0; i < PyList_Size(result); i++) { - ViewShape *b = ((BPy_ViewShape *)PyList_GetItem(result, i))->vs; + ViewShape *b = ((BPy_ViewShape *)PyList_GET_ITEM(result, i))->vs; vec.push_back(b); } ((UnaryFunction0D< vector<ViewShape*> > *)uf0D)->result = vec; @@ -318,8 +319,9 @@ int Director_BPy_UnaryFunction1D___call__(void *uf1D, void *py_uf1D, Interface1D } else if (BPy_UnaryFunction1DVectorViewShape_Check(obj)) { vector<ViewShape*> vec; + vec.reserve(PyList_Size(result)); for (int i = 1; i < PyList_Size(result); i++) { - ViewShape *b = ((BPy_ViewShape *)PyList_GetItem(result, i))->vs; + ViewShape *b = ((BPy_ViewShape *)PyList_GET_ITEM(result, i))->vs; vec.push_back(b); } ((UnaryFunction1D< vector<ViewShape*> > *)uf1D)->result = vec; diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp index 6f47ce93ca8..1d51bf287af 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp @@ -342,13 +342,14 @@ PyDoc_STRVAR(SVertex_normals_doc, static PyObject *SVertex_normals_get(BPy_SVertex *self, void *UNUSED(closure)) { PyObject *py_normals; - set< Vec3r > normals; - - py_normals = PyList_New(0); - normals = self->sv->normals(); - for (set< Vec3r >::iterator set_iterator = normals.begin(); set_iterator != normals.end(); set_iterator++) { - Vec3r v(*set_iterator); - PyList_Append(py_normals, Vector_from_Vec3r(v)); + set< Vec3r > normals = self->sv->normals(); + set< Vec3r >::iterator it; + py_normals = PyList_New(normals.size()); + unsigned int i = 0; + + for (it = normals.begin(); it != normals.end(); it++) { + Vec3r v(*it); + PyList_SET_ITEM(py_normals, i++, Vector_from_Vec3r(v)); } return py_normals; } @@ -399,13 +400,14 @@ static PyObject *SVertex_curvatures_get(BPy_SVertex *self, void *UNUSED(closure) Vec3r e2(info->e2.x(), info->e2.y(), info->e2.z()); Vec3r er(info->er.x(), info->er.y(), info->er.z()); PyObject *retval = PyTuple_New(7); - PyTuple_SET_ITEM(retval, 0, PyFloat_FromDouble(info->K1)); - PyTuple_SET_ITEM(retval, 2, Vector_from_Vec3r(e1)); - PyTuple_SET_ITEM(retval, 1, PyFloat_FromDouble(info->K2)); - PyTuple_SET_ITEM(retval, 3, Vector_from_Vec3r(e2)); - PyTuple_SET_ITEM(retval, 4, PyFloat_FromDouble(info->Kr)); - PyTuple_SET_ITEM(retval, 5, Vector_from_Vec3r(er)); - PyTuple_SET_ITEM(retval, 6, PyFloat_FromDouble(info->dKr)); + PyTuple_SET_ITEMS(retval, + PyFloat_FromDouble(info->K1), + PyFloat_FromDouble(info->K2), + Vector_from_Vec3r(e1), + Vector_from_Vec3r(e2), + PyFloat_FromDouble(info->Kr), + Vector_from_Vec3r(er), + PyFloat_FromDouble(info->dKr)); return retval; } diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp index c72ab2aba71..2a61dfb075a 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp @@ -112,20 +112,14 @@ static PyObject *UnaryFunction0DVectorViewShape___call__(BPy_UnaryFunction0DVect } return NULL; } - PyObject *list = PyList_New(0); - PyObject *item; - for (unsigned int i = 0; i < self->uf0D_vectorviewshape->result.size(); i++) { + + const unsigned int list_len = self->uf0D_vectorviewshape->result.size(); + PyObject *list = PyList_New(list_len); + for (unsigned int i = 0; i < list_len; i++) { ViewShape *v = self->uf0D_vectorviewshape->result[i]; - if (v) { - item = BPy_ViewShape_from_ViewShape(*v); - } - else { - item = Py_None; - Py_INCREF(item); - } - PyList_Append(list, item); + PyList_SET_ITEM(list, i, v ? BPy_ViewShape_from_ViewShape(*v) : (Py_INCREF(Py_None), Py_None)); } - + return list; } diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp index a028952fa69..c15d974e771 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp @@ -142,18 +142,12 @@ static PyObject *UnaryFunction1DVectorViewShape___call__(BPy_UnaryFunction1DVect } return NULL; } - PyObject *list = PyList_New(0); - PyObject *item; - for (unsigned int i = 0; i < self->uf1D_vectorviewshape->result.size(); i++) { + + const unsigned int list_len = self->uf1D_vectorviewshape->result.size(); + PyObject *list = PyList_New(list_len); + for (unsigned int i = 0; i < list_len; i++) { ViewShape *v = self->uf1D_vectorviewshape->result[i]; - if (v) { - item = BPy_ViewShape_from_ViewShape(*v); - } - else { - item = Py_None; - Py_INCREF(item); - } - PyList_Append(list, item); + PyList_SET_ITEM(list, i, v ? BPy_ViewShape_from_ViewShape(*v) : (Py_INCREF(Py_None), Py_None)); } return list; diff --git a/source/blender/freestyle/intern/scene_graph/NodeCamera.h b/source/blender/freestyle/intern/scene_graph/NodeCamera.h index 5d84a624830..78c34fdef6d 100644 --- a/source/blender/freestyle/intern/scene_graph/NodeCamera.h +++ b/source/blender/freestyle/intern/scene_graph/NodeCamera.h @@ -53,7 +53,9 @@ public: /*! Default matrices: Identity for both projection and modelview. */ NodeCamera(CameraType camera_type = GENERIC); +#if 0 /* UNUSED, gives warning in gcc */ NodeCamera(const NodeCamera& iBrother); +#endif virtual ~NodeCamera() {} diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp new file mode 100644 index 00000000000..24c56ff4e28 --- /dev/null +++ b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp @@ -0,0 +1,35 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp + * \ingroup freestyle + * \brief Class to represent a scene render layer in Blender. + */ + +#include "NodeSceneRenderLayer.h" + +namespace Freestyle { + +void NodeSceneRenderLayer::accept(SceneVisitor& v) +{ + v.visitNodeSceneRenderLayer(*this); +} + +} /* namespace Freestyle */ diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h new file mode 100644 index 00000000000..2fc08bb1175 --- /dev/null +++ b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h @@ -0,0 +1,64 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __FREESTYLE_NODE_SCENE_RENDER_LAYER_H__ +#define __FREESTYLE_NODE_SCENE_RENDER_LAYER_H__ + +/** \file blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h + * \ingroup freestyle + * \brief Class to represent a scene render layer in Blender. + */ + +#include "Node.h" + +extern "C" { +#include "DNA_scene_types.h" /* for SceneRenderLayer */ +} + +using namespace std; + +namespace Freestyle { + +class NodeSceneRenderLayer : public Node +{ +public: + inline NodeSceneRenderLayer(SceneRenderLayer& srl) : Node(), _SceneRenderLayer(srl) {} + virtual ~NodeSceneRenderLayer() {} + + inline struct SceneRenderLayer& sceneRenderLayer() const + { + return _SceneRenderLayer; + } + + inline void setSceneRenderLayer(SceneRenderLayer& srl) + { + _SceneRenderLayer = srl; + } + + /*! Accept the corresponding visitor */ + virtual void accept(SceneVisitor& v); + +protected: + SceneRenderLayer& _SceneRenderLayer; +}; + +} /* namespace Freestyle */ + +#endif // __FREESTYLE_NODE_SCENE_RENDER_LAYER_H__ diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp index 6e8856f1b93..ee1d0c53b87 100644 --- a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp +++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp @@ -24,16 +24,56 @@ #include "SceneHash.h" +#include <sstream> + namespace Freestyle { +string SceneHash::toString() +{ + stringstream ss; + ss << hex << _sum; + return ss.str(); +} + +void SceneHash::visitNodeSceneRenderLayer(NodeSceneRenderLayer& srl) +{ + struct FreestyleConfig *config = &srl.sceneRenderLayer().freestyleConfig; + adler32((unsigned char *)&config->flags, sizeof(int)); + adler32((unsigned char *)&config->crease_angle, sizeof(float)); + adler32((unsigned char *)&config->sphere_radius, sizeof(float)); + adler32((unsigned char *)&config->dkr_epsilon, sizeof(float)); +} + +void SceneHash::visitNodeCamera(NodeCamera& cam) +{ + double *proj = cam.projectionMatrix(); + for (int i = 0; i < 16; i++) { + adler32((unsigned char *)&proj[i], sizeof(double)); + } +} + void SceneHash::visitIndexedFaceSet(IndexedFaceSet& ifs) { const real *v = ifs.vertices(); const unsigned n = ifs.vsize(); for (unsigned i = 0; i < n; i++) { - _hashcode += v[i]; + adler32((unsigned char *)&v[i], sizeof(v[i])); + } +} + +static const int MOD_ADLER = 65521; + +void SceneHash::adler32(unsigned char *data, int size) +{ + uint32_t sum1 = _sum & 0xffff; + uint32_t sum2 = (_sum >> 16) & 0xffff; + + for (int i = 0; i < size; i++) { + sum1 = (sum1 + data[i]) % MOD_ADLER; + sum2 = (sum1 + sum2) % MOD_ADLER; } + _sum = sum1 | (sum2 << 16); } } /* namespace Freestyle */ diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.h b/source/blender/freestyle/intern/scene_graph/SceneHash.h index 8f5f847eaab..9da711673f0 100644 --- a/source/blender/freestyle/intern/scene_graph/SceneHash.h +++ b/source/blender/freestyle/intern/scene_graph/SceneHash.h @@ -26,8 +26,12 @@ */ #include "IndexedFaceSet.h" +#include "NodeSceneRenderLayer.h" +#include "NodeCamera.h" #include "SceneVisitor.h" +#include "BLI_sys_types.h" + #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" #endif @@ -39,23 +43,34 @@ class SceneHash : public SceneVisitor public: inline SceneHash() : SceneVisitor() { - _hashcode = 0.0; + _sum = 1; } virtual ~SceneHash() {} + VISIT_DECL(NodeCamera) + VISIT_DECL(NodeSceneRenderLayer) VISIT_DECL(IndexedFaceSet) - inline real getValue() { - return _hashcode; + string toString(); + + inline bool match() { + return _sum == _prevSum; + } + + inline void store() { + _prevSum = _sum; } inline void reset() { - _hashcode = 0.0; + _sum = 1; } private: - real _hashcode; + void adler32(unsigned char *data, int size); + + uint32_t _sum; + uint32_t _prevSum; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SceneHash") diff --git a/source/blender/freestyle/intern/scene_graph/SceneVisitor.h b/source/blender/freestyle/intern/scene_graph/SceneVisitor.h index c00f5124a31..712585c4064 100644 --- a/source/blender/freestyle/intern/scene_graph/SceneVisitor.h +++ b/source/blender/freestyle/intern/scene_graph/SceneVisitor.h @@ -56,6 +56,7 @@ class NodeLight; class NodeCamera; class NodeDrawingStyle; class NodeTransform; +class NodeSceneRenderLayer; class Rep; class LineRep; @@ -87,6 +88,7 @@ public: VISIT_COMPLETE_DEF(NodeCamera) VISIT_COMPLETE_DEF(NodeDrawingStyle) VISIT_COMPLETE_DEF(NodeTransform) + VISIT_COMPLETE_DEF(NodeSceneRenderLayer) VISIT_COMPLETE_DEF(Rep) VISIT_COMPLETE_DEF(LineRep) diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp index 32cfac016d6..69c5dcdfe28 100644 --- a/source/blender/freestyle/intern/stroke/Curve.cpp +++ b/source/blender/freestyle/intern/stroke/Curve.cpp @@ -25,6 +25,8 @@ * \date 11/01/2003 */ +#include <stdio.h> /* printf */ + #include "Curve.h" #include "CurveIterators.h" #include "CurveAdvancedIterators.h" diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp index 863da069259..244b20f6b89 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.cpp +++ b/source/blender/freestyle/intern/stroke/Stroke.cpp @@ -400,6 +400,7 @@ Stroke::Stroke() } _nodeTree = NULL; _tips = false; + _rep = NULL; } Stroke::Stroke(const Stroke& iBrother) @@ -427,6 +428,10 @@ Stroke::Stroke(const Stroke& iBrother) } _nodeTree = iBrother._nodeTree; _tips = iBrother._tips; + if (iBrother._rep) + _rep = new StrokeRep(*(iBrother._rep)); + else + _rep = NULL; } Stroke::~Stroke() @@ -439,6 +444,10 @@ Stroke::~Stroke() } _ViewEdges.clear(); + if (_rep) { + delete _rep; + _rep = NULL; + } } Stroke& Stroke::operator=(const Stroke& iBrother) @@ -456,6 +465,12 @@ Stroke& Stroke::operator=(const Stroke& iBrother) _id = iBrother._id; _ViewEdges = iBrother._ViewEdges; _sampling = iBrother._sampling; + if (_rep) + delete _rep; + if (iBrother._rep) + _rep = new StrokeRep(*(iBrother._rep)); + else + _rep = NULL; return *this; } @@ -757,14 +772,16 @@ void Stroke::ScaleThickness(float iFactor) void Stroke::Render(const StrokeRenderer *iRenderer) { - StrokeRep rep(this); - iRenderer->RenderStrokeRep(&rep); + if (!_rep) + _rep = new StrokeRep(this); + iRenderer->RenderStrokeRep(_rep); } void Stroke::RenderBasic(const StrokeRenderer *iRenderer) { - StrokeRep rep(this); - iRenderer->RenderStrokeRepBasic(&rep); + if (!_rep) + _rep = new StrokeRep(this); + iRenderer->RenderStrokeRep(_rep); } Stroke::vertex_iterator Stroke::vertices_begin(float sampling) diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h index 8ff801ed144..5f0b4eab309 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.h +++ b/source/blender/freestyle/intern/stroke/Stroke.h @@ -549,6 +549,7 @@ private: MTex *_mtex[MAX_MTEX]; bNodeTree *_nodeTree; bool _tips; + StrokeRep *_rep; Vec2r _extremityOrientations[2]; // the orientations of the first and last extermity public: diff --git a/source/blender/freestyle/intern/system/StringUtils.h b/source/blender/freestyle/intern/system/StringUtils.h index 77b543c7886..e11798762e4 100644 --- a/source/blender/freestyle/intern/system/StringUtils.h +++ b/source/blender/freestyle/intern/system/StringUtils.h @@ -36,7 +36,8 @@ extern "C" { #include "BKE_utildefines.h" -#include "BLI_blenlib.h" +#include "BLI_string.h" +#include "BLI_path_util.h" } using namespace std; diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp index 38941b23357..31396688422 100644 --- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp +++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp @@ -535,6 +535,7 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V namespace OGF { +#if 0 inline static real angle(WOEdge *h) { const Vec3r& n1 = h->GetbFace()->GetNormal(); @@ -549,6 +550,7 @@ inline static real angle(WOEdge *h) } return ::asin(sine); } +#endif // precondition1: P is inside the sphere // precondition2: P,V points to the outside of the sphere (i.e. OP.V > 0) diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 63eea9486ed..361c247767f 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -73,6 +73,7 @@ data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_simple_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_simple_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC) +data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC) diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index ba461d5f8a2..e9b600a9267 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -54,6 +54,7 @@ typedef struct GPUBuffer { int size; /* in bytes */ void *pointer; /* used with vertex arrays */ unsigned int id; /* used with vertex buffer objects */ + bool use_vbo; /* true for VBOs, false for vertex arrays */ } GPUBuffer; typedef struct GPUBufferMaterial { @@ -85,6 +86,7 @@ typedef struct GPUDrawObject { GPUBuffer *points; GPUBuffer *normals; GPUBuffer *uv; + GPUBuffer *uv_tex; GPUBuffer *colors; GPUBuffer *edges; GPUBuffer *uvedges; @@ -113,10 +115,6 @@ typedef struct GPUDrawObject { /* caches of the original DerivedMesh values */ int totvert; int totedge; - - /* if there was a failure allocating some buffer, use old - * rendering code */ - bool legacy; } GPUDrawObject; /* used for GLSL materials */ @@ -129,7 +127,7 @@ typedef struct GPUAttrib { void GPU_global_buffer_pool_free(void); void GPU_global_buffer_pool_free_unused(void); -GPUBuffer *GPU_buffer_alloc(int size); +GPUBuffer *GPU_buffer_alloc(int size, bool force_vertex_arrays); void GPU_buffer_free(GPUBuffer *buffer); GPUDrawObject *GPU_drawobject_new(struct DerivedMesh *dm); @@ -161,9 +159,6 @@ void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, /* called after drawing */ void GPU_buffer_unbind(void); -/* used to check whether to use the old (without buffers) code */ -bool GPU_buffer_legacy(struct DerivedMesh *dm); - /* Buffers for non-DerivedMesh drawing */ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 3daf8585539..bb0cf2dd2b9 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -140,12 +140,15 @@ int GPU_texture_opengl_bindcode(GPUTexture *tex); * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must * be called before rendering to the window framebuffer again */ +void GPU_texture_bind_as_framebuffer(GPUTexture *tex); + GPUFrameBuffer *GPU_framebuffer_create(void); -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256]); -void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex); -void GPU_framebuffer_texture_bind(GPUFrameBuffer *fb, GPUTexture *tex, int w, int h); +int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]); +void GPU_framebuffer_texture_detach(GPUTexture *tex); +void GPU_framebuffer_slot_bind(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); +bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); void GPU_framebuffer_restore(void); void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index fab9c28cb61..09a5653b1ec 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -58,6 +58,7 @@ struct GPUMaterial; struct GPUTexture; struct GPULamp; struct PreviewImage; +struct World; typedef struct GPUNode GPUNode; typedef struct GPUNodeLink GPUNodeLink; @@ -95,6 +96,12 @@ typedef enum GPUOpenGLBuiltin { GPU_COLOR = 2, } GPUOpenGLBuiltin; +typedef enum GPUMatType { + GPU_MATERIAL_TYPE_MESH = 1, + GPU_MATERIAL_TYPE_WORLD = 2, +} GPUMatType; + + typedef enum GPUBlendMode { GPU_BLEND_SOLID = 0, GPU_BLEND_ADD = 1, @@ -131,10 +138,11 @@ void GPU_material_enable_alpha(GPUMaterial *material); GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]); /* High level functions to create and use GPU materials */ +GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo); GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma); GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma); -void GPU_material_free(struct Material *ma); +void GPU_material_free(struct ListBase *gpumaterial); void GPU_materials_free(void); @@ -144,6 +152,7 @@ void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float void GPU_material_unbind(GPUMaterial *material); int GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); +GPUMatType GPU_Material_get_type(GPUMaterial *material); void GPU_material_vertex_attributes(GPUMaterial *material, struct GPUVertexAttribs *attrib); diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript index f11ecafc986..e44a99286a8 100644 --- a/source/blender/gpu/SConscript +++ b/source/blender/gpu/SConscript @@ -69,6 +69,7 @@ sources.extend(( os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_vert.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex_world.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_vert.glsl.c"), )) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index b5a576b509c..f0ef55ae673 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -46,13 +46,11 @@ #include "BLI_ghash.h" #include "BLI_threads.h" -#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" #include "BKE_paint.h" -#include "BKE_material.h" #include "BKE_pbvh.h" #include "DNA_userdef_types.h" @@ -76,7 +74,6 @@ typedef enum { #define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */ -static int useVBOs = -1; static GPUBufferState GLStates = 0; static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } }; @@ -111,10 +108,6 @@ static GPUBufferPool *gpu_buffer_pool_new(void) { GPUBufferPool *pool; - /* enable VBOs if supported */ - if (useVBOs == -1) - useVBOs = (GLEW_ARB_vertex_buffer_object ? 1 : 0); - pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer_Pool"); pool->maxsize = MAX_FREE_GPU_BUFFERS; @@ -158,7 +151,7 @@ static void gpu_buffer_pool_delete_last(GPUBufferPool *pool) return; /* delete the buffer's data */ - if (useVBOs) + if (last->use_vbo) glDeleteBuffersARB(1, &last->id); else MEM_freeN(last->pointer); @@ -226,7 +219,7 @@ void GPU_global_buffer_pool_free_unused(void) * * Thread-unsafe version for internal usage only. */ -static GPUBuffer *gpu_buffer_alloc_intern(int size) +static GPUBuffer *gpu_buffer_alloc_intern(int size, bool use_VBO) { GPUBufferPool *pool; GPUBuffer *buf; @@ -251,6 +244,10 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size) for (i = 0; i < pool->totbuf; i++) { bufsize = pool->buffers[i]->size; + /* only return a buffer that matches the VBO preference */ + if (pool->buffers[i]->use_vbo != use_VBO) + continue; + /* check for an exact size match */ if (bufsize == size) { bestfit = i; @@ -279,8 +276,9 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size) /* no acceptable buffer found in the pool, create a new one */ buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer"); buf->size = size; + buf->use_vbo = use_VBO; - if (useVBOs == 1) { + if (use_VBO) { /* create a new VBO and initialize it to the requested * size */ glGenBuffersARB(1, &buf->id); @@ -307,9 +305,10 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size) } /* Same as above, but safe for threading. */ -GPUBuffer *GPU_buffer_alloc(int size) +GPUBuffer *GPU_buffer_alloc(int size, bool force_vertex_arrays) { GPUBuffer *buffer; + bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO) && !force_vertex_arrays; if (size == 0) { /* Early out, no lock needed in this case. */ @@ -317,7 +316,7 @@ GPUBuffer *GPU_buffer_alloc(int size) } BLI_mutex_lock(&buffer_mutex); - buffer = gpu_buffer_alloc_intern(size); + buffer = gpu_buffer_alloc_intern(size, use_VBOs); BLI_mutex_unlock(&buffer_mutex); return buffer; @@ -577,6 +576,7 @@ void GPU_drawobject_free(DerivedMesh *dm) GPU_buffer_free(gdo->points); GPU_buffer_free(gdo->normals); GPU_buffer_free(gdo->uv); + GPU_buffer_free(gdo->uv_tex); GPU_buffer_free(gdo->colors); GPU_buffer_free(gdo->edges); GPU_buffer_free(gdo->uvedges); @@ -585,6 +585,22 @@ void GPU_drawobject_free(DerivedMesh *dm) dm->drawObject = NULL; } +static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, int size, bool use_VBOs) +{ + gpu_buffer_free_intern(buffer); + gpu_buffer_pool_delete_last(pool); + buffer = NULL; + + /* try freeing an entry from the pool + * and reallocating the buffer */ + if (pool->totbuf > 0) { + gpu_buffer_pool_delete_last(pool); + buffer = gpu_buffer_alloc_intern(size, use_VBOs); + } + + return buffer; +} + typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *user_data); @@ -598,7 +614,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, int *mat_orig_to_new; int *cur_index_per_mat; int i; - bool success; + bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO); GLboolean uploaded; pool = gpu_get_global_buffer_pool(); @@ -606,11 +622,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, BLI_mutex_lock(&buffer_mutex); /* alloc a GPUBuffer; fall back to legacy mode on failure */ - if (!(buffer = gpu_buffer_alloc_intern(size))) - dm->drawObject->legacy = 1; - - /* nothing to do for legacy mode */ - if (dm->drawObject->legacy) { + if (!(buffer = gpu_buffer_alloc_intern(size, use_VBOs))) { BLI_mutex_unlock(&buffer_mutex); return NULL; } @@ -628,8 +640,8 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, mat_orig_to_new[object->materials[i].mat_nr] = i; } - if (useVBOs) { - success = 0; + if (use_VBOs) { + bool success = false; while (!success) { /* bind the buffer and discard previous data, @@ -639,32 +651,22 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, /* attempt to map the buffer */ if (!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) { - /* failed to map the buffer; delete it */ - gpu_buffer_free_intern(buffer); - gpu_buffer_pool_delete_last(pool); - buffer = NULL; - - /* try freeing an entry from the pool - * and reallocating the buffer */ - if (pool->totbuf > 0) { - gpu_buffer_pool_delete_last(pool); - buffer = gpu_buffer_alloc_intern(size); - } - + buffer = gpu_try_realloc(pool, buffer, size, true); + /* allocation still failed; fall back * to legacy mode */ if (!buffer) { - dm->drawObject->legacy = 1; - success = 1; + use_VBOs = false; + success = true; } } else { - success = 1; + success = true; } } /* check legacy fallback didn't happen */ - if (dm->drawObject->legacy == 0) { + if (use_VBOs) { uploaded = GL_FALSE; /* attempt to upload the data to the VBO */ while (uploaded == GL_FALSE) { @@ -677,15 +679,16 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, } glBindBufferARB(target, 0); } - else { + if (!use_VBOs) { /* VBO not supported, use vertex array fallback */ - if (buffer->pointer) { + if (!buffer || !buffer->pointer) { + buffer = gpu_try_realloc(pool, buffer, size, false); + } + + if (buffer) { varray = buffer->pointer; (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user); } - else { - dm->drawObject->legacy = 1; - } } MEM_freeN(cur_index_per_mat); @@ -1019,7 +1022,7 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer case GPU_BUFFER_UV: return &gdo->uv; case GPU_BUFFER_UV_TEXPAINT: - return &gdo->uv; + return &gdo->uv_tex; case GPU_BUFFER_EDGE: return &gdo->edges; case GPU_BUFFER_UVEDGE: @@ -1105,7 +1108,7 @@ void GPU_vertex_setup(DerivedMesh *dm) return; glEnableClientState(GL_VERTEX_ARRAY); - if (useVBOs) { + if (dm->drawObject->points->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id); glVertexPointer(3, GL_FLOAT, 0, 0); } @@ -1122,7 +1125,7 @@ void GPU_normal_setup(DerivedMesh *dm) return; glEnableClientState(GL_NORMAL_ARRAY); - if (useVBOs) { + if (dm->drawObject->normals->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id); glNormalPointer(GL_FLOAT, 0, 0); } @@ -1139,7 +1142,7 @@ void GPU_uv_setup(DerivedMesh *dm) return; glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (useVBOs) { + if (dm->drawObject->uv->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id); glTexCoordPointer(2, GL_FLOAT, 0, 0); } @@ -1156,8 +1159,8 @@ void GPU_texpaint_uv_setup(DerivedMesh *dm) return; glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (useVBOs) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id); + if (dm->drawObject->uv_tex->use_vbo) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv_tex->id); glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); glClientActiveTexture(GL_TEXTURE2); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -1165,10 +1168,10 @@ void GPU_texpaint_uv_setup(DerivedMesh *dm) glClientActiveTexture(GL_TEXTURE0); } else { - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv->pointer); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv_tex->pointer); glClientActiveTexture(GL_TEXTURE2); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv->pointer + 2 * sizeof(float)); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv_tex->pointer + 2 * sizeof(float)); glClientActiveTexture(GL_TEXTURE0); } @@ -1202,7 +1205,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType) return; glEnableClientState(GL_COLOR_ARRAY); - if (useVBOs) { + if (dm->drawObject->colors->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); } @@ -1222,7 +1225,7 @@ void GPU_edge_setup(DerivedMesh *dm) return; glEnableClientState(GL_VERTEX_ARRAY); - if (useVBOs) { + if (dm->drawObject->points->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id); glVertexPointer(3, GL_FLOAT, 0, 0); } @@ -1232,7 +1235,7 @@ void GPU_edge_setup(DerivedMesh *dm) GLStates |= GPU_BUFFER_VERTEX_STATE; - if (useVBOs) + if (dm->drawObject->edges->use_vbo) glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id); GLStates |= GPU_BUFFER_ELEMENT_STATE; @@ -1244,7 +1247,7 @@ void GPU_uvedge_setup(DerivedMesh *dm) return; glEnableClientState(GL_VERTEX_ARRAY); - if (useVBOs) { + if (dm->drawObject->uvedges->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id); glVertexPointer(2, GL_FLOAT, 0, 0); } @@ -1290,6 +1293,7 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda int i; int elementsize; intptr_t offset = 0; + char *basep; for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { if (attribData[i].index != -1) { @@ -1300,28 +1304,26 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda } elementsize = GPU_attrib_element_size(data, numdata); - if (useVBOs) { + if (buffer->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); - for (i = 0; i < numdata; i++) { - glEnableVertexAttribArrayARB(data[i].index); - glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type, - GL_FALSE, elementsize, (void *)offset); - offset += data[i].size * GPU_typesize(data[i].type); - - attribData[i].index = data[i].index; - attribData[i].size = data[i].size; - attribData[i].type = data[i].type; - } - attribData[numdata].index = -1; + basep = NULL; } else { - for (i = 0; i < numdata; i++) { - glEnableVertexAttribArrayARB(data[i].index); - glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type, - GL_FALSE, elementsize, (char *)buffer->pointer + offset); - offset += data[i].size * GPU_typesize(data[i].type); - } + basep = buffer->pointer; } + + for (i = 0; i < numdata; i++) { + glEnableVertexAttribArrayARB(data[i].index); + glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type, + GL_FALSE, elementsize, (void *)(basep + offset)); + offset += data[i].size * GPU_typesize(data[i].type); + + attribData[i].index = data[i].index; + attribData[i].size = data[i].size; + attribData[i].type = data[i].type; + } + + attribData[numdata].index = -1; } @@ -1343,7 +1345,8 @@ void GPU_buffer_unbind(void) if (GLStates & GPU_BUFFER_COLOR_STATE) glDisableClientState(GL_COLOR_ARRAY); if (GLStates & GPU_BUFFER_ELEMENT_STATE) { - if (useVBOs) { + /* not guaranteed we used VBOs but in that case it's just a no-op */ + if (GLEW_ARB_vertex_buffer_object) { glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } } @@ -1359,7 +1362,8 @@ void GPU_buffer_unbind(void) break; } - if (useVBOs) + /* not guaranteed we used VBOs but in that case it's just a no-op */ + if (GLEW_ARB_vertex_buffer_object) glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } @@ -1377,19 +1381,6 @@ void GPU_color_switch(int mode) } } -/* return 1 if drawing should be done using old immediate-mode - * code, 0 otherwise */ -bool GPU_buffer_legacy(DerivedMesh *dm) -{ - int test = (U.gameflags & USER_DISABLE_VBO); - if (test) - return 1; - - if (dm->drawObject == NULL) - dm->drawObject = GPU_drawobject_new(dm); - return dm->drawObject->legacy; -} - void *GPU_buffer_lock(GPUBuffer *buffer) { float *varray; @@ -1397,7 +1388,7 @@ void *GPU_buffer_lock(GPUBuffer *buffer) if (!buffer) return 0; - if (useVBOs) { + if (buffer->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); return varray; @@ -1414,7 +1405,7 @@ void *GPU_buffer_lock_stream(GPUBuffer *buffer) if (!buffer) return 0; - if (useVBOs) { + if (buffer->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); /* discard previous data, avoid stalling gpu */ glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB); @@ -1428,12 +1419,10 @@ void *GPU_buffer_lock_stream(GPUBuffer *buffer) void GPU_buffer_unlock(GPUBuffer *buffer) { - if (useVBOs) { - if (buffer) { - /* note: this operation can fail, could return - * an error code from this function? */ - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); - } + if (buffer->use_vbo) { + /* note: this operation can fail, could return + * an error code from this function? */ + glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } } @@ -1442,7 +1431,7 @@ void GPU_buffer_unlock(GPUBuffer *buffer) void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count) { glDrawElements(mode, count, GL_UNSIGNED_INT, - (useVBOs ? + (elements->use_vbo ? (void *)(start * sizeof(unsigned int)) : ((int *)elements->pointer) + start)); } @@ -2748,7 +2737,7 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers) /* debug function, draws the pbvh BB */ void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf) { - float quads[4][4][3] = { + const float quads[4][4][3] = { { {min[0], min[1], min[2]}, {max[0], min[1], min[2]}, diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 4182f51561b..1f9efdcbefd 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -51,13 +51,12 @@ #include "gpu_codegen.h" -#include "node_util.h" /* For muting node stuff... */ - #include <string.h> #include <stdarg.h> extern char datatoc_gpu_shader_material_glsl[]; extern char datatoc_gpu_shader_vertex_glsl[]; +extern char datatoc_gpu_shader_vertex_world_glsl[]; static char *glsl_material_library = NULL; @@ -239,7 +238,7 @@ GPUFunction *GPU_lookup_function(const char *name) gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library); } - return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, (void *)name); + return BLI_ghash_lookup(FUNCTION_HASH, (const void *)name); } void gpu_codegen_init(void) @@ -252,7 +251,7 @@ void gpu_codegen_exit(void) extern Material defmaterial; // render module abuse... if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); if (FUNCTION_HASH) { BLI_ghash_free(FUNCTION_HASH, NULL, MEM_freeN); @@ -624,8 +623,7 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const ch if (builtins & GPU_VIEW_NORMAL) BLI_dynstr_append(ds, "\tvec3 facingnormal = (gl_FrontFacing)? varnormal: -varnormal;\n"); - - + codegen_declare_tmps(ds, nodes); codegen_call_functions(ds, nodes, output); @@ -640,12 +638,13 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const ch return code; } -static char *code_generate_vertex(ListBase *nodes) +static char *code_generate_vertex(ListBase *nodes, int type) { DynStr *ds = BLI_dynstr_new(); GPUNode *node; GPUInput *input; char *code; + char *vertcode; for (node=nodes->first; node; node=node->next) { for (input=node->inputs.first; input; input=input->next) { @@ -659,8 +658,21 @@ static char *code_generate_vertex(ListBase *nodes) } BLI_dynstr_append(ds, "\n"); - BLI_dynstr_append(ds, datatoc_gpu_shader_vertex_glsl); + switch (type) { + case GPU_MATERIAL_TYPE_MESH: + vertcode = datatoc_gpu_shader_vertex_glsl; + break; + case GPU_MATERIAL_TYPE_WORLD: + vertcode = datatoc_gpu_shader_vertex_world_glsl; + break; + default: + fprintf(stderr, "invalid material type, set one after GPU_material_construct_begin\n"); + break; + } + + BLI_dynstr_append(ds, vertcode); + for (node=nodes->first; node; node=node->next) for (input=node->inputs.first; input; input=input->next) if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { @@ -1386,7 +1398,7 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } } -GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, const char *name) +GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, int type, const char *name) { GPUShader *shader; GPUPass *pass; @@ -1405,7 +1417,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri /* generate code and compile with opengl */ fragmentcode = code_generate_fragment(nodes, outlink->output, name); - vertexcode = code_generate_vertex(nodes); + vertexcode = code_generate_vertex(nodes, type); shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL); /* failed? */ diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 69213925931..a0698235db6 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -175,7 +175,7 @@ struct GPUPass { typedef struct GPUPass GPUPass; GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink, - struct GPUVertexAttribs *attribs, int *builtin, const char *name); + struct GPUVertexAttribs *attribs, int *builtin, int type, const char *name); struct GPUShader *GPU_pass_shader(GPUPass *pass); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 622e7b5ce9e..5f58e3fe65b 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -724,8 +724,12 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int glBindTexture(GL_TEXTURE_2D, *bind); if (!(GPU_get_mipmap() && mipmap)) { - if (use_high_bit_depth) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + if (use_high_bit_depth) { + if (GLEW_ARB_texture_float) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + } else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -733,8 +737,12 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int } else { if (GTS.gpu_mipmap) { - if (use_high_bit_depth) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + if (use_high_bit_depth) { + if (GLEW_ARB_texture_float) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + } else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix); @@ -1389,9 +1397,10 @@ static struct GPUMaterialState { } GMS = {NULL}; /* fixed function material, alpha handed by caller */ -static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob, const int new_shading_nodes) +static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob, const int new_shading_nodes, + const bool dimdown) { - if (new_shading_nodes || bmat->mode & MA_SHLESS) { + if (bmat->mode & MA_SHLESS) { copy_v3_v3(smat->diff, &bmat->r); smat->diff[3]= 1.0; @@ -1401,6 +1410,24 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, zero_v4(smat->spec); smat->hard= 0; } + else if (new_shading_nodes) { + copy_v3_v3(smat->diff, &bmat->r); + smat->diff[3]= 1.0; + + copy_v3_v3(smat->spec, &bmat->specr); + smat->spec[3] = 1.0; + smat->hard= CLAMPIS(bmat->har, 0, 128); + + if (dimdown) { + mul_v3_fl(smat->diff, 0.8f); + mul_v3_fl(smat->spec, 0.5f); + } + + if (gamma) { + linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); + linearrgb_to_srgb_v3_v3(smat->spec, smat->spec); + } + } else { mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit); smat->diff[3]= 1.0; /* caller may set this to bmat->alpha */ @@ -1501,7 +1528,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O /* no materials assigned? */ if (ob->totcol==0) { - gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes); + gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true); /* do material 1 too, for displists! */ memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); @@ -1531,7 +1558,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O } else { /* fixed function opengl materials */ - gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes); + gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false); if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) { GMS.matbuf[a].diff[3]= ma->alpha; diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 04f8e68431a..a6b711fd556 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -49,7 +49,6 @@ #include "GPU_extensions.h" #include "GPU_simple_shader.h" -#include "intern/gpu_codegen.h" #include "intern/gpu_extensions_private.h" #include <stdlib.h> @@ -103,6 +102,16 @@ static struct GPUGlobal { GPUTexture *invalid_tex_3D; } GG = {1, 0}; +/* Number of maximum output slots. We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */ +#define GPU_FB_MAX_SLOTS 4 + +struct GPUFrameBuffer { + GLuint object; + GPUTexture *colortex[GPU_FB_MAX_SLOTS]; + GPUTexture *depthtex; +}; + + /* GPU Types */ int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver) @@ -259,7 +268,7 @@ int GPU_print_error(const char *str) { GLenum errCode; - if (G.debug & G_DEBUG) { + if ((G.debug & G_DEBUG)) { if ((errCode = glGetError()) != GL_NO_ERROR) { fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode)); return 1; @@ -323,6 +332,7 @@ struct GPUTexture { int fromblender; /* we got the texture from Blender */ GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ + int fb_attachment; /* slot the texture is attached to */ int depth; /* is a depth texture? */ }; @@ -370,6 +380,7 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in tex->refcount = 1; tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D; tex->depth = depth; + tex->fb_attachment = -1; glGenTextures(1, &tex->bindcode); @@ -451,15 +462,8 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in } if (tex->target != GL_TEXTURE_1D) { - /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */ - GLenum wrapmode = (depth || tex->h == 1)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER; - glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode); - glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode); - -#if 0 - float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); -#endif + glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -737,7 +741,13 @@ void GPU_texture_bind(GPUTexture *tex, int number) return; } - if (number == -1) + if ((G.debug & G_DEBUG)) { + if (tex->fb && tex->fb->object == GG.currentfb) { + fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n"); + } + } + + if (number < 0) return; GPU_print_error("Pre Texture Bind"); @@ -791,7 +801,7 @@ void GPU_texture_free(GPUTexture *tex) if (tex->refcount == 0) { if (tex->fb) - GPU_framebuffer_texture_detach(tex->fb, tex); + GPU_framebuffer_texture_detach(tex); if (tex->bindcode && !tex->fromblender) glDeleteTextures(1, &tex->bindcode); @@ -831,12 +841,6 @@ GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) /* GPUFrameBuffer */ -struct GPUFrameBuffer { - GLuint object; - GPUTexture *colortex; - GPUTexture *depthtex; -}; - GPUFrameBuffer *GPU_framebuffer_create(void) { GPUFrameBuffer *fb; @@ -854,19 +858,35 @@ GPUFrameBuffer *GPU_framebuffer_create(void) return NULL; } + /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glReadBuffer(GL_NONE); + glDrawBuffer(GL_NONE); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + return fb; } -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256]) +int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) { - GLenum status; GLenum attachment; GLenum error; + if (slot >= GPU_FB_MAX_SLOTS) { + fprintf(stderr, "Attaching to index %d framebuffer slot unsupported in blender use at most %d\n", slot, GPU_FB_MAX_SLOTS); + return 0; + } + + if ((G.debug & G_DEBUG)) { + if (tex->number != -1) { + fprintf(stderr, "Feedback loop warning!: Attempting to attach texture to framebuffer while still bound to texture unit for drawing!"); + } + } + if (tex->depth) attachment = GL_DEPTH_ATTACHMENT_EXT; else - attachment = GL_COLOR_ATTACHMENT0_EXT; + attachment = GL_COLOR_ATTACHMENT0_EXT + slot; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); GG.currentfb = fb->object; @@ -885,42 +905,29 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err return 0; } - if (tex->depth) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } - else { - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - } - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - GPU_framebuffer_restore(); - GPU_print_framebuffer_error(status, err_out); - return 0; - } - if (tex->depth) fb->depthtex = tex; else - fb->colortex = tex; + fb->colortex[slot] = tex; tex->fb= fb; + tex->fb_attachment = slot; return 1; } -void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) +void GPU_framebuffer_texture_detach(GPUTexture *tex) { GLenum attachment; + GPUFrameBuffer *fb; if (!tex->fb) return; - if (GG.currentfb != tex->fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object); + fb = tex->fb; + + if (GG.currentfb != fb->object) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); GG.currentfb = tex->fb->object; } @@ -929,18 +936,25 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) attachment = GL_DEPTH_ATTACHMENT_EXT; } else { - fb->colortex = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT; + BLI_assert(fb->colortex[tex->fb_attachment] == tex); + fb->colortex[tex->fb_attachment] = NULL; + attachment = GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment; } glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, 0, 0); tex->fb = NULL; + tex->fb_attachment = -1; } -void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, int w, int h) +void GPU_texture_bind_as_framebuffer(GPUTexture *tex) { + if (!tex->fb) { + fprintf(stderr, "Error, texture not bound to framebuffer!"); + return; + } + /* push attributes */ glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); glDisable(GL_SCISSOR_TEST); @@ -948,8 +962,18 @@ void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, i /* bind framebuffer */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object); + if (tex->depth) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + else { + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); + } + /* push matrices and set default viewport and matrix */ - glViewport(0, 0, w, h); + glViewport(0, 0, tex->w, tex->h); GG.currentfb = tex->fb->object; glMatrixMode(GL_PROJECTION); @@ -958,6 +982,35 @@ void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, i glPushMatrix(); } +void GPU_framebuffer_slot_bind(GPUFrameBuffer *fb, int slot) +{ + if (!fb->colortex[slot]) { + fprintf(stderr, "Error, framebuffer slot empty!"); + return; + } + + /* push attributes */ + glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + glDisable(GL_SCISSOR_TEST); + + /* bind framebuffer */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + + /* push matrices and set default viewport and matrix */ + glViewport(0, 0, fb->colortex[slot]->w, fb->colortex[slot]->h); + GG.currentfb = fb->object; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + + void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) { /* restore matrix */ @@ -968,15 +1021,42 @@ void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUS /* restore attributes */ glPopAttrib(); - glEnable(GL_SCISSOR_TEST); } + +bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) +{ + GLenum status; + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + GG.currentfb = fb->object; + + /* Clean glError buffer. */ + while (glGetError() != GL_NO_ERROR) {} + + status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + GPU_framebuffer_restore(); + GPU_print_framebuffer_error(status, err_out); + return false; + } + + return true; +} + + void GPU_framebuffer_free(GPUFrameBuffer *fb) { + int i; if (fb->depthtex) - GPU_framebuffer_texture_detach(fb, fb->depthtex); - if (fb->colortex) - GPU_framebuffer_texture_detach(fb, fb->colortex); + GPU_framebuffer_texture_detach(fb->depthtex); + + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { + if (fb->colortex[i]) { + GPU_framebuffer_texture_detach(fb->colortex[i]); + } + } if (fb->object) { glDeleteFramebuffersEXT(1, &fb->object); @@ -1017,6 +1097,10 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid * pushing unnecessary matrices onto the OpenGL stack. */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + + /* avoid warnings from texture binding */ + GG.currentfb = blurfb->object; GPU_shader_bind(blur_shader); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scaleh); @@ -1046,6 +1130,10 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b /* Blurring vertically */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + + GG.currentfb = fb->object; + glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex)); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scalev); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); @@ -1067,10 +1155,6 @@ struct GPUOffScreen { GPUFrameBuffer *fb; GPUTexture *color; GPUTexture *depth; - - /* requested width/height, may be smaller than actual texture size due - * to missing non-power of two support, so we compensate for that */ - int w, h; }; GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) @@ -1078,8 +1162,6 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) GPUOffScreen *ofs; ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); - ofs->w= width; - ofs->h= height; ofs->fb = GPU_framebuffer_create(); if (!ofs->fb) { @@ -1093,7 +1175,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { GPU_offscreen_free(ofs); return NULL; } @@ -1104,10 +1186,16 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { GPU_offscreen_free(ofs); return NULL; } + + /* check validity at the very end! */ + if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } GPU_framebuffer_restore(); @@ -1129,7 +1217,7 @@ void GPU_offscreen_free(GPUOffScreen *ofs) void GPU_offscreen_bind(GPUOffScreen *ofs) { glDisable(GL_SCISSOR_TEST); - GPU_framebuffer_texture_bind(ofs->fb, ofs->color, ofs->w, ofs->h); + GPU_texture_bind_as_framebuffer(ofs->color); } void GPU_offscreen_unbind(GPUOffScreen *ofs) @@ -1141,17 +1229,17 @@ void GPU_offscreen_unbind(GPUOffScreen *ofs) void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) { - glReadPixels(0, 0, ofs->w, ofs->h, GL_RGBA, type, pixels); + glReadPixels(0, 0, ofs->color->w, ofs->color->h, GL_RGBA, type, pixels); } int GPU_offscreen_width(GPUOffScreen *ofs) { - return ofs->w; + return ofs->color->w; } int GPU_offscreen_height(GPUOffScreen *ofs) { - return ofs->h; + return ofs->color->h; } /* GPUShader */ @@ -1173,8 +1261,8 @@ static void shader_print_errors(const char *task, char *log, const char **code, for (i = 0; i < totcode; i++) { const char *c, *pos, *end = code[i] + strlen(code[i]); int line = 1; - - if (G.debug & G_DEBUG) { + + if ((G.debug & G_DEBUG)) { fprintf(stderr, "===== shader string %d ====\n", i + 1); c = code[i]; diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 912774cd345..fd99595b6a4 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -31,7 +31,6 @@ #include "BLI_sys_types.h" #include "GPU_init_exit.h" /* interface */ -#include "GPU_extensions.h" /* library */ #include "intern/gpu_codegen.h" #include "intern/gpu_extensions_private.h" diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index fa22783ba2a..75a9572f54f 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -76,10 +76,15 @@ typedef enum DynMatProperty { DYN_LAMP_PERSMAT = 8, } DynMatProperty; + struct GPUMaterial { Scene *scene; Material *ma; + /* material for mesh surface, worlds or something else. + * some code generation is done differently depending on the use case */ + int type; + /* for creating the material */ ListBase nodes; GPUNodeLink *outlink; @@ -194,7 +199,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material) attribs->totlayer = b; } -static int GPU_material_construct_end(GPUMaterial *material) +static int GPU_material_construct_end(GPUMaterial *material, const char *passname) { if (material->outlink) { GPUNodeLink *outlink; @@ -202,7 +207,7 @@ static int GPU_material_construct_end(GPUMaterial *material) outlink = material->outlink; material->pass = GPU_generate_pass(&material->nodes, outlink, - &material->attribs, &material->builtins, material->ma->id.name); + &material->attribs, &material->builtins, material->type, passname); if (!material->pass) return 0; @@ -229,12 +234,12 @@ static int GPU_material_construct_end(GPUMaterial *material) return 0; } -void GPU_material_free(Material *ma) +void GPU_material_free(ListBase *gpumaterial) { LinkData *link; LinkData *nlink, *mlink, *next; - for (link=ma->gpumaterial.first; link; link=link->next) { + for (link=gpumaterial->first; link; link=link->next) { GPUMaterial *material = link->data; if (material->pass) @@ -243,19 +248,23 @@ void GPU_material_free(Material *ma) for (nlink=material->lamps.first; nlink; nlink=nlink->next) { GPULamp *lamp = nlink->data; - for (mlink=lamp->materials.first; mlink; mlink=next) { - next = mlink->next; - if (mlink->data == ma) - BLI_freelinkN(&lamp->materials, mlink); + if (material->ma) { + Material *ma = material->ma; + + for (mlink=lamp->materials.first; mlink; mlink=next) { + next = mlink->next; + if (mlink->data == ma) + BLI_freelinkN(&lamp->materials, mlink); + } } } - + BLI_freelistN(&material->lamps); MEM_freeN(material); } - BLI_freelistN(&ma->gpumaterial); + BLI_freelistN(gpumaterial); } bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) @@ -280,42 +289,44 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim viewlay &= srl->lay; /* handle layer lamps */ - for (nlink=material->lamps.first; nlink; nlink=nlink->next) { - lamp= nlink->data; - - if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) - && GPU_lamp_override_visible(lamp, srl, material->ma)) { - lamp->dynenergy = lamp->energy; - copy_v3_v3(lamp->dyncol, lamp->col); - } - else { - lamp->dynenergy = 0.0f; - lamp->dyncol[0]= lamp->dyncol[1]= lamp->dyncol[2] = 0.0f; - } - - if (material->dynproperty & DYN_LAMP_VEC) { - copy_v3_v3(lamp->dynvec, lamp->vec); - normalize_v3(lamp->dynvec); - negate_v3(lamp->dynvec); - mul_mat3_m4_v3(viewmat, lamp->dynvec); - } - - if (material->dynproperty & DYN_LAMP_CO) { - copy_v3_v3(lamp->dynco, lamp->co); - mul_m4_v3(viewmat, lamp->dynco); - } - - if (material->dynproperty & DYN_LAMP_IMAT) { - mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv); - } - - if (material->dynproperty & DYN_LAMP_PERSMAT) { - if (!GPU_lamp_has_shadow_buffer(lamp)) /* The lamp matrices are already updated if we're using shadow buffers */ - GPU_lamp_update_buffer_mats(lamp); - mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv); + if (material->type == GPU_MATERIAL_TYPE_MESH) { + for (nlink=material->lamps.first; nlink; nlink=nlink->next) { + lamp= nlink->data; + + if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) + && GPU_lamp_override_visible(lamp, srl, material->ma)) { + lamp->dynenergy = lamp->energy; + copy_v3_v3(lamp->dyncol, lamp->col); + } + else { + lamp->dynenergy = 0.0f; + lamp->dyncol[0]= lamp->dyncol[1]= lamp->dyncol[2] = 0.0f; + } + + if (material->dynproperty & DYN_LAMP_VEC) { + copy_v3_v3(lamp->dynvec, lamp->vec); + normalize_v3(lamp->dynvec); + negate_v3(lamp->dynvec); + mul_mat3_m4_v3(viewmat, lamp->dynvec); + } + + if (material->dynproperty & DYN_LAMP_CO) { + copy_v3_v3(lamp->dynco, lamp->co); + mul_m4_v3(viewmat, lamp->dynco); + } + + if (material->dynproperty & DYN_LAMP_IMAT) { + mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv); + } + + if (material->dynproperty & DYN_LAMP_PERSMAT) { + if (!GPU_lamp_has_shadow_buffer(lamp)) /* The lamp matrices are already updated if we're using shadow buffers */ + GPU_lamp_update_buffer_mats(lamp); + mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv); + } } } - + /* note material must be bound before setting uniforms */ GPU_pass_bind(material->pass, time, mipmap); @@ -376,6 +387,12 @@ Scene *GPU_material_scene(GPUMaterial *material) return material->scene; } +GPUMatType GPU_Material_get_type(GPUMaterial *material) +{ + return material->type; +} + + void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) { *attribs = material->attribs; @@ -1589,6 +1606,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma) /* allocate material */ mat = GPU_material_construct_begin(ma); mat->scene = scene; + mat->type = GPU_MATERIAL_TYPE_MESH; if (ma->preview && ma->preview->rect[0]) { outlink = gpu_material_preview_matcap(mat, ma); @@ -1599,7 +1617,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma) GPU_material_output_link(mat, outlink); - GPU_material_construct_end(mat); + GPU_material_construct_end(mat, "matcap_pass"); /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use @@ -1612,6 +1630,45 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma) return mat; } +GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) +{ + LinkData *link; + GPUMaterial *mat; + + for (link=wo->gpumaterial.first; link; link=link->next) + if (((GPUMaterial*)link->data)->scene == scene) + return link->data; + + /* allocate material */ + mat = GPU_material_construct_begin(NULL); + mat->scene = scene; + mat->type = GPU_MATERIAL_TYPE_WORLD; + + /* create nodes */ + if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) + ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING); + else { + /* old fixed function world */ + } + + if (GPU_material_do_color_management(mat)) + if (mat->outlink) + GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); + + GPU_material_construct_end(mat, wo->id.name); + + /* note that even if building the shader fails in some way, we still keep + * it to avoid trying to compile again and again, and simple do not use + * the actual shader on drawing */ + + link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); + link->data = mat; + BLI_addtail(&wo->gpumaterial, link); + + return mat; +} + + GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma) { GPUMaterial *mat; @@ -1625,6 +1682,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma) /* allocate material */ mat = GPU_material_construct_begin(ma); mat->scene = scene; + mat->type = GPU_MATERIAL_TYPE_MESH; /* render pipeline option */ if (ma->mode & MA_TRANSP) @@ -1654,7 +1712,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma) if (mat->outlink) GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); - GPU_material_construct_end(mat); + GPU_material_construct_end(mat, ma->id.name); /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use @@ -1671,12 +1729,16 @@ void GPU_materials_free(void) { Object *ob; Material *ma; + World *wo; extern Material defmaterial; for (ma=G.main->mat.first; ma; ma=ma->id.next) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); - GPU_material_free(&defmaterial); + for (wo=G.main->world.first; wo; wo=wo->id.next) + GPU_material_free(&wo->gpumaterial); + + GPU_material_free(&defmaterial.gpumaterial); for (ob=G.main->object.first; ob; ob=ob->id.next) GPU_lamp_free(ob); @@ -1851,7 +1913,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -1863,11 +1925,16 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { gpu_lamp_shadow_free(lamp); return lamp; } + if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + /* FBO and texture for blurring */ lamp->blurfb = GPU_framebuffer_create(); if (!lamp->blurfb) { @@ -1881,10 +1948,20 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, NULL)) { gpu_lamp_shadow_free(lamp); return lamp; } + + /* we need to properly bind to test for completeness */ + GPU_texture_bind_as_framebuffer(lamp->blurtex); + + if (!GPU_framebuffer_check_valid(lamp->blurfb, NULL)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + GPU_framebuffer_texture_unbind(lamp->blurfb, lamp->blurtex); } else { lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); @@ -1893,10 +1970,15 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { gpu_lamp_shadow_free(lamp); return lamp; } + + if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } } GPU_framebuffer_restore(); @@ -1930,7 +2012,7 @@ void GPU_lamp_free(Object *ob) BLI_freelinkN(&lamp->materials, nlink); if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); } gpu_lamp_shadow_free(lamp); @@ -1979,8 +2061,7 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz /* opengl */ glDisable(GL_SCISSOR_TEST); - GPU_framebuffer_texture_bind(lamp->fb, lamp->tex, - GPU_texture_opengl_width(lamp->tex), GPU_texture_opengl_height(lamp->tex)); + GPU_texture_bind_as_framebuffer(lamp->tex); if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index afd6af9efae..d8e1fab9f80 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -33,12 +33,12 @@ #include "GPU_extensions.h" #include "GPU_glew.h" -#include "BLI_utildefines.h" - #include "MEM_guardedalloc.h" #include "DNA_userdef_types.h" +#include "BLI_utildefines.h" + /* Ad hoc number of queries to allocate to skip doing many glGenQueries */ #define ALLOC_QUERIES 200 diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_simple_shader.c index c0d7ebd4abb..3fa5975ef15 100644 --- a/source/blender/gpu/intern/gpu_simple_shader.c +++ b/source/blender/gpu/intern/gpu_simple_shader.c @@ -47,9 +47,6 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "DNA_mesh_types.h" -#include "DNA_object_types.h" - #include "GPU_extensions.h" #include "GPU_simple_shader.h" diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index a737741975e..1e0927d90b3 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -357,6 +357,12 @@ void normal(vec3 dir, vec3 nor, out vec3 outnor, out float outdot) outdot = -dot(dir, nor); } +void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot) +{ + outnor = normalize(nor); + outdot = dot(normalize(dir), nor); +} + void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec) { outvec.x = texture2D(curvemap, vec2((vec.x + 1.0)*0.5, 0.0)).x; @@ -2256,6 +2262,22 @@ void node_emission(vec4 color, float strength, vec3 N, out vec4 result) result = color*strength; } +/* background */ + +void background_transform_to_world(vec3 viewvec, out vec3 worldvec) +{ + vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); + vec4 co_homogenous = (gl_ProjectionMatrixInverse * v); + + vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); + worldvec = (gl_ModelViewMatrixInverse * co).xyz; +} + +void node_background(vec4 color, float strength, vec3 N, out vec4 result) +{ + result = color*strength; +} + /* closures */ void node_mix_shader(float fac, vec4 shader1, vec4 shader2, out vec4 shader) @@ -2350,13 +2372,13 @@ void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, out vec3 camera, out vec3 window, out vec3 reflection) { - generated = mtex_2d_mapping(attr_orco); + generated = attr_orco * 0.5 + vec3(0.5); normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz); uv = attr_uv; object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz; - camera = I; + camera = vec3(I.xy, -I.z); vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0); - window = mtex_2d_mapping(projvec.xyz/projvec.w); + window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy, 0.0); vec3 shade_I; shade_view(I, shade_I); @@ -2364,6 +2386,30 @@ void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz; } +void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, + vec3 attr_orco, vec3 attr_uv, + out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, + out vec3 camera, out vec3 window, out vec3 reflection) +{ + vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); + vec4 co_homogenous = (gl_ProjectionMatrixInverse * v); + + vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); + + co = normalize(co); + vec3 coords = (gl_ModelViewMatrixInverse * co).xyz; + + generated = coords; + normal = -coords; + uv = vec3(attr_uv.xy, 0.0); + object = coords; + + camera = vec3(co.xy, -co.z); + window = (gl_ProjectionMatrix[3][3] == 0.0) ? vec3(mtex_2d_mapping(I).xy, 0.0) : vec3(0.5, 0.5, 0.0); + + reflection = -coords; +} + /* textures */ void node_tex_gradient(vec3 co, out vec4 color, out float fac) @@ -2390,17 +2436,34 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac) fac = 1.0; } -void node_tex_environment(vec3 co, sampler2D ima, out vec4 color) +void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color) +{ + vec3 nco = normalize(co); + float u = -atan(nco.y, nco.x)/(2.0*M_PI) + 0.5; + float v = atan(nco.z, hypot(nco.x, nco.y))/M_PI + 0.5; + + color = texture2D(ima, vec2(u, v)); +} + +void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color) { - float u = (atan(co.y, co.x) + M_PI)/(2.0*M_PI); - float v = atan(co.z, hypot(co.x, co.y))/M_PI + 0.5; + vec3 nco = normalize(co); + + nco.y -= 1.0; + + float div = 2.0*sqrt(max(-0.5*nco.y, 0.0)); + if(div > 0.0) + nco /= div; + + float u = 0.5*(nco.x + 1.0); + float v = 0.5*(nco.z + 1.0); color = texture2D(ima, vec2(u, v)); } void node_tex_environment_empty(vec3 co, out vec4 color) { - color = vec4(0.0); + color = vec4(1.0, 0.0, 1.0, 1.0); } void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha) @@ -2508,6 +2571,11 @@ void node_output_material(vec4 surface, vec4 volume, float displacement, out vec result = surface; } +void node_output_world(vec4 surface, vec4 volume, out vec4 result) +{ + result = surface; +} + /* ********************** matcap style render ******************** */ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result) diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl index 978b6db1b9a..5f406c959f1 100644 --- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl @@ -10,7 +10,7 @@ void main() color += texture2D( textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125; color += texture2D( textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y ) ) * 0.234375; color += texture2D( textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y ) ) * 0.09375; - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, -3.0 * ScaleU.y ) ) * 0.015625; + color += texture2D( textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y ) ) * 0.015625; gl_FragColor = color; } diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl new file mode 100644 index 00000000000..9dbcaeb7a32 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -0,0 +1,13 @@ + +varying vec3 varposition; +varying vec3 varnormal; + +void main() +{ + /* position does not need to be transformed, we already have it */ + gl_Position = gl_Vertex; + + varposition = gl_Vertex.xyz; + + varnormal = normalize(-varposition); + diff --git a/source/blender/ikplugin/intern/ikplugin_api.c b/source/blender/ikplugin/intern/ikplugin_api.c index 2ca50afb0f2..0f81fb34a63 100644 --- a/source/blender/ikplugin/intern/ikplugin_api.c +++ b/source/blender/ikplugin/intern/ikplugin_api.c @@ -30,19 +30,12 @@ * \ingroup ikplugin */ - - #include "BIK_api.h" #include "BLI_blenlib.h" -#include "BLI_math.h" - -#include "BKE_armature.h" #include "DNA_object_types.h" #include "DNA_action_types.h" #include "DNA_scene_types.h" -#include "DNA_constraint_types.h" -#include "DNA_armature_types.h" #include "ikplugin_api.h" diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 612517775f4..556c4beeae7 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -47,8 +47,8 @@ #include "MEM_guardedalloc.h" -#include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_threads.h" static SpinLock refcounter_spin; diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index eef7964ef3f..b8f6e66adfe 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -70,12 +70,8 @@ #include "MEM_guardedalloc.h" -#include "DNA_userdef_types.h" - #include "BKE_global.h" -#include "imbuf.h" - #ifdef WITH_AVI # include "AVI_avi.h" #endif @@ -89,7 +85,6 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_anim.h" #include "IMB_indexer.h" diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c index dabeec74a62..8853fe449ba 100644 --- a/source/blender/imbuf/intern/bmp.c +++ b/source/blender/imbuf/intern/bmp.c @@ -36,7 +36,6 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_filetype.h" #include "IMB_colormanagement.h" diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c index 677c3dbe700..759f8cc82c2 100644 --- a/source/blender/imbuf/intern/cache.c +++ b/source/blender/imbuf/intern/cache.c @@ -22,7 +22,6 @@ * \ingroup imbuf */ - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -31,8 +30,6 @@ #include "BLI_memarena.h" #include "BLI_threads.h" - - #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_filetype.h" diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index 880df0ce5c3..0e71206517e 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -135,7 +135,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t { CineonMainHeader header; LogImageFile *cineon = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__); - char *filename = (char *)byteStuff; + const char *filename = (const char *)byteStuff; int i; unsigned int dataOffset; diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index 626d05b05c5..f7362d76913 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -67,7 +67,7 @@ static void fillDpxMainHeader(LogImageFile *dpx, DpxMainHeader *header, const ch /* --- File header --- */ header->fileHeader.magic_num = swap_uint(DPX_FILE_MAGIC, dpx->isMSB); header->fileHeader.offset = swap_uint(dpx->element[0].dataOffset, dpx->isMSB); - strcpy(header->fileHeader.version, "v2.0"); + strcpy(header->fileHeader.version, "V2.0"); header->fileHeader.file_size = swap_uint(dpx->element[0].dataOffset + dpx->height * getRowLength(dpx->width, dpx->element[0]), dpx->isMSB); header->fileHeader.ditto_key = 0; header->fileHeader.gen_hdr_size = swap_uint(sizeof(DpxFileHeader) + sizeof(DpxImageHeader) + sizeof(DpxOrientationHeader), dpx->isMSB); @@ -134,7 +134,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf { DpxMainHeader header; LogImageFile *dpx = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__); - char *filename = (char *)byteStuff; + const char *filename = (const char *)byteStuff; int i; if (dpx == NULL) { diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 5dd6b366a93..049d8bdcff1 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -44,7 +44,6 @@ #include "DNA_scene_types.h" #include "DNA_space_types.h" -#include "IMB_filter.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_filetype.h" @@ -53,14 +52,13 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "BLI_fileops.h" #include "BLI_math.h" #include "BLI_math_color.h" -#include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_threads.h" #include "BLI_rect.h" +#include "BKE_appdir.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_image.h" @@ -245,7 +243,7 @@ static ColormnaageCacheData *colormanage_cachedata_get(const ImBuf *ibuf) static unsigned int colormanage_hashhash(const void *key_v) { - ColormanageCacheKey *key = (ColormanageCacheKey *)key_v; + const ColormanageCacheKey *key = key_v; unsigned int rval = (key->display << 16) | (key->view % 0xffff); @@ -254,8 +252,8 @@ static unsigned int colormanage_hashhash(const void *key_v) static bool colormanage_hashcmp(const void *av, const void *bv) { - const ColormanageCacheKey *a = (ColormanageCacheKey *) av; - const ColormanageCacheKey *b = (ColormanageCacheKey *) bv; + const ColormanageCacheKey *a = av; + const ColormanageCacheKey *b = bv; return ((a->view != b->view) || (a->display != b->display)); @@ -625,7 +623,7 @@ void colormanagement_init(void) } if (config == NULL) { - configdir = BLI_get_folder(BLENDER_DATAFILES, "colormanagement"); + configdir = BKE_appdir_folder_id(BLENDER_DATAFILES, "colormanagement"); if (configdir) { BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE); diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp index 57a251261a1..d8387b92530 100644 --- a/source/blender/imbuf/intern/dds/Stream.cpp +++ b/source/blender/imbuf/intern/dds/Stream.cpp @@ -30,10 +30,13 @@ #include <stdio.h> // printf #include <string.h> // memcpy +static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)"; +static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)"; + unsigned int Stream::seek(unsigned int p) { if (p > size) { - printf("DDS: trying to seek beyond end of stream (corrupt file?)"); + puts(msg_error_seek); } else { pos = p; @@ -45,7 +48,7 @@ unsigned int Stream::seek(unsigned int p) unsigned int mem_read(Stream & mem, unsigned long long & i) { if (mem.pos + 8 > mem.size) { - printf("DDS: trying to read beyond end of stream (corrupt file?)"); + puts(msg_error_seek); return(0); } memcpy(&i, mem.mem + mem.pos, 8); // @@ todo: make sure little endian @@ -56,7 +59,7 @@ unsigned int mem_read(Stream & mem, unsigned long long & i) unsigned int mem_read(Stream & mem, unsigned int & i) { if (mem.pos + 4 > mem.size) { - printf("DDS: trying to read beyond end of stream (corrupt file?)"); + puts(msg_error_read); return(0); } memcpy(&i, mem.mem + mem.pos, 4); // @@ todo: make sure little endian @@ -67,7 +70,7 @@ unsigned int mem_read(Stream & mem, unsigned int & i) unsigned int mem_read(Stream & mem, unsigned short & i) { if (mem.pos + 2 > mem.size) { - printf("DDS: trying to read beyond end of stream (corrupt file?)"); + puts(msg_error_read); return(0); } memcpy(&i, mem.mem + mem.pos, 2); // @@ todo: make sure little endian @@ -78,7 +81,7 @@ unsigned int mem_read(Stream & mem, unsigned short & i) unsigned int mem_read(Stream & mem, unsigned char & i) { if (mem.pos + 1 > mem.size) { - printf("DDS: trying to read beyond end of stream (corrupt file?)"); + puts(msg_error_read); return(0); } i = (mem.mem + mem.pos)[0]; @@ -89,7 +92,7 @@ unsigned int mem_read(Stream & mem, unsigned char & i) unsigned int mem_read(Stream & mem, unsigned char *i, unsigned int cnt) { if (mem.pos + cnt > mem.size) { - printf("DDS: trying to read beyond end of stream (corrupt file?)"); + puts(msg_error_read); return(0); } memcpy(i, mem.mem + mem.pos, cnt); diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 03cd5ecd646..81aef4ac6e4 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -37,7 +37,6 @@ #include "imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_filter.h" #include "IMB_colormanagement.h" diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index b6b46c72384..c6e358dd3d2 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -51,8 +51,6 @@ #include "quicktime_import.h" #endif -#include "imbuf.h" - static int imb_ftype_default(ImFileType *type, ImBuf *ibuf) { return (ibuf->ftype & type->filetype); diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 547a8df4438..e66be77ecaf 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -1170,7 +1170,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecod return context; - (void)tcs_in_use, (void)proxy_sizes_in_use, (void)quality; + UNUSED_VARS(tcs_in_use, proxy_sizes_in_use, quality); } void IMB_anim_index_rebuild(struct IndexBuildContext *context, @@ -1189,7 +1189,7 @@ void IMB_anim_index_rebuild(struct IndexBuildContext *context, #endif } - (void)stop, (void)do_update, (void)progress; + UNUSED_VARS(stop, do_update, progress); } void IMB_anim_index_rebuild_finish(IndexBuildContext *context, short stop) @@ -1207,8 +1207,8 @@ void IMB_anim_index_rebuild_finish(IndexBuildContext *context, short stop) #endif } - (void)stop; - (void)proxy_sizes; /* static defined at top of the file */ + /* static defined at top of the file */ + UNUSED_VARS(stop, proxy_sizes); } diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index 8f98f240053..ea5acf27e99 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -40,7 +40,6 @@ #include "imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_filetype.h" #include "IMB_colormanagement.h" diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c index 18c096450af..8750b825fb6 100644 --- a/source/blender/imbuf/intern/jp2.c +++ b/source/blender/imbuf/intern/jp2.c @@ -29,11 +29,8 @@ #include "BLI_math.h" #include "BLI_fileops.h" -#include "imbuf.h" - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_filetype.h" #include "IMB_colormanagement.h" diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 1641bd3089b..cb789cc8491 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -99,22 +99,22 @@ typedef struct MovieCacheItem { static unsigned int moviecache_hashhash(const void *keyv) { - MovieCacheKey *key = (MovieCacheKey *)keyv; + const MovieCacheKey *key = keyv; return key->cache_owner->hashfp(key->userkey); } static bool moviecache_hashcmp(const void *av, const void *bv) { - const MovieCacheKey *a = (MovieCacheKey *)av; - const MovieCacheKey *b = (MovieCacheKey *)bv; + const MovieCacheKey *a = av; + const MovieCacheKey *b = bv; return a->cache_owner->cmpfp(a->userkey, b->userkey); } static void moviecache_keyfree(void *val) { - MovieCacheKey *key = (MovieCacheKey *)val; + MovieCacheKey *key = val; BLI_mempool_free(key->cache_owner->userkeys_pool, key->userkey); @@ -167,8 +167,8 @@ static void check_unused_keys(MovieCache *cache) static int compare_int(const void *av, const void *bv) { - const int *a = (int *)av; - const int *b = (int *)bv; + const int *a = av; + const int *b = bv; return *a - *b; } @@ -363,8 +363,7 @@ static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, boo item->priority_data = cache->getprioritydatafp(userkey); } - BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree); - BLI_ghash_insert(cache->hash, key, item); + BLI_ghash_reinsert(cache->hash, key, item, moviecache_keyfree, moviecache_valfree); if (cache->last_userkey) { memcpy(cache->last_userkey, userkey, cache->keysize); diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index d00a836667e..3266dc97c78 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -41,8 +41,6 @@ #include "MEM_guardedalloc.h" -#include "imbuf.h" - #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index db268546480..318bb7e96e3 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -38,7 +38,7 @@ */ #ifdef WIN32 -# include <io.h> +# include "BLI_utildefines.h" #endif #include "MEM_guardedalloc.h" @@ -72,10 +72,13 @@ typedef float fCOLOR[3]; #define COPY_RGBE(c1, c2) (c2[RED] = c1[RED], c2[GRN] = c1[GRN], c2[BLU] = c1[BLU], c2[EXP] = c1[EXP]) /* read routines */ -static unsigned char *oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax) +static unsigned char *oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax, unsigned char *mem_eof) { int i, rshift = 0, len = xmax; while (len > 0) { + if (mem_eof - mem < 4) { + return NULL; + } scan[0][RED] = *mem++; scan[0][GRN] = *mem++; scan[0][BLU] = *mem++; @@ -97,34 +100,62 @@ static unsigned char *oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax) return mem; } -static unsigned char *freadcolrs(RGBE *scan, unsigned char *mem, int xmax) +static unsigned char *freadcolrs(RGBE *scan, unsigned char *mem, int xmax, unsigned char *mem_eof) { int i, j, code, val; - if ((xmax < MINELEN) | (xmax > MAXELEN)) return oldreadcolrs(scan, mem, xmax); + if (mem_eof - mem < 4) { + return NULL; + } + + if ((xmax < MINELEN) | (xmax > MAXELEN)) { + return oldreadcolrs(scan, mem, xmax, mem_eof); + } i = *mem++; - if (i != 2) return oldreadcolrs(scan, mem - 1, xmax); + if (i != 2) { + return oldreadcolrs(scan, mem - 1, xmax, mem_eof); + } scan[0][GRN] = *mem++; scan[0][BLU] = *mem++; i = *mem++; - if (((scan[0][BLU] << 8) | i) != xmax) return NULL; - for (i = 0; i < 4; i++) + if (scan[0][GRN] != 2 || scan[0][BLU] & 128) { + scan[0][RED] = 2; + scan[0][EXP] = i; + return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof); + } + + if (((scan[0][BLU] << 8) | i) != xmax) { + return NULL; + } + + for (i = 0; i < 4; i++) { + if (mem_eof - mem < 2) { + return NULL; + } for (j = 0; j < xmax; ) { code = *mem++; if (code > 128) { code &= 127; val = *mem++; - while (code--) + while (code--) { scan[j++][i] = (unsigned char)val; + } } - else - while (code--) + else { + if (mem_eof - mem < code) { + return NULL; + } + while (code--) { scan[j++][i] = *mem++; + } + } } + } + return mem; } @@ -182,7 +213,7 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char color int found = 0; int width = 0, height = 0; int x, y; - unsigned char *ptr; + unsigned char *ptr, *mem_eof = mem + size; char oriY[80], oriX[80]; if (imb_is_a_hdr((void *)mem)) { @@ -218,15 +249,14 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char color if (flags & IB_test) return ibuf; /* read in and decode the actual data */ - sline = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_read_tmpscan"); + sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); rect_float = ibuf->rect_float; for (y = 0; y < height; y++) { - ptr = freadcolrs(sline, ptr, width); + ptr = freadcolrs(sline, ptr, width, mem_eof); if (ptr == NULL) { - printf("HDR decode error\n"); - MEM_freeN(sline); - return ibuf; + printf("WARNING! HDR decode error, image may be just truncated, or completely wrong...\n"); + break; } for (x = 0; x < width; x++) { /* convert to ldr */ diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index dd2406e234e..4001b681ad9 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -39,11 +39,9 @@ #include "BLI_math_color_blend.h" #include "BLI_math_vector.h" -#include "imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_colormanagement.h" void IMB_blend_color_byte(unsigned char dst[4], unsigned char src1[4], unsigned char src2[4], IMB_BlendMode mode) diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c index e98757883be..886944f6190 100644 --- a/source/blender/imbuf/intern/rotate.c +++ b/source/blender/imbuf/intern/rotate.c @@ -39,8 +39,6 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" - void IMB_flipy(struct ImBuf *ibuf) { int x, y; diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index e480f06da2b..2601fe62c2f 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -33,7 +33,6 @@ #include "BLI_utildefines.h" -#include "BLI_math_base.h" #include "BLI_math_color.h" #include "BLI_math_interp.h" #include "MEM_guardedalloc.h" @@ -42,7 +41,6 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_filter.h" #include "BLI_sys_types.h" // for intptr_t support diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c index 2dcb27a05d4..70b71ec4182 100644 --- a/source/blender/imbuf/intern/targa.c +++ b/source/blender/imbuf/intern/targa.c @@ -44,7 +44,6 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_filetype.h" #include "IMB_colormanagement.h" diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c index 73ced4095f9..af353461f1f 100644 --- a/source/blender/imbuf/intern/thumbs_blend.c +++ b/source/blender/imbuf/intern/thumbs_blend.c @@ -29,8 +29,6 @@ #include "zlib.h" -#include "MEM_guardedalloc.h" - #include "BLI_utildefines.h" #include "BLI_endian_switch.h" #include "BLI_fileops.h" diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index eb8f94cbc6e..e3b8e271387 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -53,9 +53,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "IMB_allocimbuf.h" #include "IMB_filetype.h" -#include "IMB_filter.h" #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c index d4a9bf7dc09..087330d10d2 100644 --- a/source/blender/imbuf/intern/writeimage.c +++ b/source/blender/imbuf/intern/writeimage.c @@ -41,8 +41,6 @@ #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" -#include "imbuf.h" - static ImBuf *prepare_write_imbuf(ImFileType *type, ImBuf *ibuf) { ImBuf *write_ibuf = ibuf; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 33d1445fb93..c00435faa9d 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -44,54 +44,65 @@ struct FileData; struct ID; struct PackedFile; struct GPUTexture; - + typedef struct IDPropertyData { void *pointer; ListBase group; - int val, val2; /*note, we actually fit a double into these two ints*/ + int val, val2; /* note, we actually fit a double into these two ints */ } IDPropertyData; typedef struct IDProperty { struct IDProperty *next, *prev; char type, subtype; short flag; - char name[64]; /* MAX_IDPROP_NAME */ - int saved; /* saved is used to indicate if this struct has been saved yet. - * seemed like a good idea as a pad var was needed anyway :)*/ - IDPropertyData data; /* note, alignment for 64 bits */ - int len; /* array length, also (this is important!) string length + 1. - * the idea is to be able to reuse array realloc functions on strings.*/ + char name[64]; /* MAX_IDPROP_NAME */ + + /* saved is used to indicate if this struct has been saved yet. + * seemed like a good idea as a pad var was needed anyway :) */ + int saved; + IDPropertyData data; /* note, alignment for 64 bits */ + + /* array length, also (this is important!) string length + 1. + * the idea is to be able to reuse array realloc functions on strings.*/ + int len; + + /* Strings and arrays are both buffered, though the buffer isn't saved. */ /* totallen is total length of allocated array/string, including a buffer. - * Note that the buffering is mild; the code comes from python's list implementation.*/ - int totallen; /*strings and arrays are both buffered, though the buffer isn't saved.*/ + * Note that the buffering is mild; the code comes from python's list implementation. */ + int totallen; } IDProperty; -#define MAX_IDPROP_NAME 64 -#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64 +#define MAX_IDPROP_NAME 64 +#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64 /*->type*/ -#define IDP_STRING 0 -#define IDP_INT 1 -#define IDP_FLOAT 2 -#define IDP_ARRAY 5 -#define IDP_GROUP 6 -/* the ID link property type hasn't been implemented yet, this will require - * some cleanup of blenkernel, most likely.*/ -#define IDP_ID 7 -#define IDP_DOUBLE 8 -#define IDP_IDPARRAY 9 -#define IDP_NUMTYPES 10 +enum { + IDP_STRING = 0, + IDP_INT = 1, + IDP_FLOAT = 2, + IDP_ARRAY = 5, + IDP_GROUP = 6, + /* the ID link property type hasn't been implemented yet, this will require + * some cleanup of blenkernel, most likely. */ + IDP_ID = 7, + IDP_DOUBLE = 8, + IDP_IDPARRAY = 9, + IDP_NUMTYPES = 10, +}; /*->subtype */ /* IDP_STRING */ -#define IDP_STRING_SUB_UTF8 0 /* default */ -#define IDP_STRING_SUB_BYTE 1 /* arbitrary byte array, _not_ null terminated */ -/*->flag*/ -#define IDP_FLAG_GHOST (1<<7) /* this means the property is set but RNA will return - * false when checking 'RNA_property_is_set', - * currently this is a runtime flag */ +enum { + IDP_STRING_SUB_UTF8 = 0, /* default */ + IDP_STRING_SUB_BYTE = 1, /* arbitrary byte array, _not_ null terminated */ +}; +/*->flag*/ +enum { + IDP_FLAG_GHOST = 1 << 7, /* this means the property is set but RNA will return false when checking + * 'RNA_property_is_set', currently this is a runtime flag */ +}; /* add any future new id property types here.*/ @@ -102,7 +113,7 @@ typedef struct IDProperty { * */ /* 2 characters for ID code and 64 for actual name */ -#define MAX_ID_NAME 66 +#define MAX_ID_NAME 66 /* There's a nasty circular dependency here.... 'void *' to the rescue! I * really wonder why this is needed. */ @@ -129,14 +140,14 @@ typedef struct Library { ID id; ID *idblock; struct FileData *filedata; - char name[1024]; /* path name used for reading, can be relative and edited in the outliner */ - char filepath[1024]; /* absolute filepath, this is only for convenience, - * 'name' is the real path used on file read but in - * some cases its useful to access the absolute one, - * This is set on file read. - * Use BKE_library_filepath_set() rather than - * setting 'name' directly and it will be kept in - * sync - campbell */ + char name[1024]; /* path name used for reading, can be relative and edited in the outliner */ + + /* absolute filepath, this is only for convenience, 'name' is the real path used on file read but in + * some cases its useful to access the absolute one. + * This is set on file read. + * Use BKE_library_filepath_set() rather than setting 'name' directly and it will be kept in sync - campbell */ + char filepath[1024]; + struct Library *parent; /* set for indirectly linked libs, used in the outliner and while reading */ struct PackedFile *packedfile; @@ -232,33 +243,34 @@ typedef struct PreviewImage { #ifdef GS # undef GS #endif -// #define GS(a) (*((short *)(a))) -#define GS(a) (CHECK_TYPE_INLINE(a, char *), (*((short *)(a)))) +#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (*((const short *)(a)))) #define ID_NEW(a) if ( (a) && (a)->id.newid ) (a) = (void *)(a)->id.newid #define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } #define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } -/* id->flag: set frist 8 bits always at zero while reading */ -#define LIB_LOCAL 0 -#define LIB_EXTERN 1 -#define LIB_INDIRECT 2 -#define LIB_NEED_EXPAND 8 -#define LIB_TESTEXT (LIB_NEED_EXPAND | LIB_EXTERN) -#define LIB_TESTIND (LIB_NEED_EXPAND | LIB_INDIRECT) -#define LIB_READ 16 -#define LIB_NEED_LINK 32 - -#define LIB_NEW 256 -#define LIB_FAKEUSER 512 -/* free test flag */ -#define LIB_DOIT 1024 -/* tag existing data before linking so we know what is new */ -#define LIB_PRE_EXISTING 2048 -/* runtime */ -#define LIB_ID_RECALC 4096 -#define LIB_ID_RECALC_DATA 8192 -#define LIB_ANIM_NO_RECALC 16384 +/* id->flag: set first 8 bits always at zero while reading */ +enum { + LIB_LOCAL = 0, + LIB_EXTERN = 1 << 0, + LIB_INDIRECT = 1 << 1, + LIB_NEED_EXPAND = 1 << 3, + LIB_TESTEXT = (LIB_NEED_EXPAND | LIB_EXTERN), + LIB_TESTIND = (LIB_NEED_EXPAND | LIB_INDIRECT), + LIB_READ = 1 << 4, + LIB_NEED_LINK = 1 << 5, + + LIB_NEW = 1 << 8, + LIB_FAKEUSER = 1 << 9, + /* free test flag */ + LIB_DOIT = 1 << 10, + /* tag existing data before linking so we know what is new */ + LIB_PRE_EXISTING = 1 << 11, + /* runtime */ + LIB_ID_RECALC = 1 << 12, + LIB_ID_RECALC_DATA = 1 << 13, + LIB_ANIM_NO_RECALC = 1 << 14, +}; #ifdef __cplusplus } diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index dab825c856e..243e747c006 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -250,6 +250,7 @@ typedef enum ePchan_Flag { POSE_ROT = (1 << 1), POSE_SIZE = (1 << 2), /* old IK/cache stuff... */ +#if 0 POSE_IK_MAT = (1 << 3), POSE_UNUSED2 = (1 << 4), POSE_UNUSED3 = (1 << 5), @@ -257,6 +258,7 @@ typedef enum ePchan_Flag { POSE_UNUSED5 = (1 << 7), /* has Standard IK */ POSE_HAS_IK = (1 << 8), +#endif /* IK/Pose solving*/ POSE_CHAIN = (1 << 9), POSE_DONE = (1 << 10), @@ -265,8 +267,10 @@ typedef enum ePchan_Flag { POSE_STRIDE = (1 << 12), /* standard IK solving */ POSE_IKTREE = (1 << 13), +#if 0 /* has Spline IK */ POSE_HAS_IKS = (1 << 14), +#endif /* spline IK solving */ POSE_IKSPLINE = (1 << 15) } ePchan_Flag; @@ -541,7 +545,7 @@ typedef enum eDopeSheet_FilterFlag { ADS_FILTER_ONLYNLA = (1 << 2), /* for 'NLA' editor - only include NLA data from AnimData */ ADS_FILTER_SELEDIT = (1 << 3), /* for Graph Editor - used to indicate whether to include a filtering flag or not */ - /* general filtering 2 */ + /* general filtering */ ADS_FILTER_SUMMARY = (1 << 4), /* for 'DopeSheet' Editors - include 'summary' line */ ADS_FILTER_ONLYOBGROUP = (1 << 5), /* only the objects in the specified object group get used */ @@ -564,6 +568,8 @@ typedef enum eDopeSheet_FilterFlag { ADS_FILTER_NOSPK = (1 << 21), ADS_FILTER_NOLINESTYLE = (1 << 22), ADS_FILTER_NOMODIFIERS = (1 << 23), + ADS_FILTER_NOGPENCIL = (1 << 24), + /* NOTE: all new datablock filters will have to go in filterflag2 (see below) */ /* NLA-specific filters */ ADS_FILTER_NLA_NOACT = (1 << 25), /* if the AnimData block has no NLA data, don't include to just show Action-line */ @@ -581,6 +587,8 @@ typedef enum eDopeSheet_FilterFlag { typedef enum eDopeSheet_Flag { ADS_FLAG_SUMMARY_COLLAPSED = (1 << 0), /* when summary is shown, it is collapsed, so all other channels get hidden */ ADS_FLAG_SHOW_DBFILTERS = (1 << 1) /* show filters for datablocks */ + + /* NOTE: datablock filter flags continued (1 << 10) onwards... */ } eDopeSheet_Flag; diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index b14861fcf47..89c8316002b 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -93,7 +93,7 @@ typedef struct Brush { float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */ - float pad; + int flag2; int gradient_spacing; int gradient_stroke_mode; /* source for stroke color gradient application */ int gradient_fill_mode; /* source for fill tool color gradient application */ @@ -102,7 +102,7 @@ typedef struct Brush { char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */ char imagepaint_tool; /* active image paint tool */ char mask_tool; /* enum BrushMaskTool, only used if sculpt_tool is SCULPT_TOOL_MASK */ - + float autosmooth_factor; float crease_pinch_factor; @@ -192,7 +192,7 @@ typedef enum BrushFlags { BRUSH_JITTER_PRESSURE = (1 << 4), BRUSH_SPACING_PRESSURE = (1 << 5), BRUSH_UNUSED = (1 << 6), - BRUSH_RAKE = (1 << 7), +// BRUSH_RAKE = (1 << 7), deprecated, use brush_angle_mode BRUSH_ANCHORED = (1 << 8), BRUSH_DIR_IN = (1 << 9), BRUSH_SPACE = (1 << 10), @@ -209,7 +209,7 @@ typedef enum BrushFlags { BRUSH_EDGE_TO_EDGE = (1 << 22), BRUSH_DRAG_DOT = (1 << 23), BRUSH_INVERSE_SMOOTH_PRESSURE = (1 << 24), - BRUSH_RANDOM_ROTATION = (1 << 25), +// BRUSH_RANDOM_ROTATION = (1 << 25), deprecated, use brush_angle_mode BRUSH_PLANE_TRIM = (1 << 26), BRUSH_FRONTFACE = (1 << 27), BRUSH_CUSTOM_ICON = (1 << 28), diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index fb33879e2c1..86991245068 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -173,6 +173,12 @@ typedef struct bSplineIKConstraint { /* settings */ short flag; /* general settings for constraint */ short xzScaleMode; /* method used for determining the x & z scaling of the bones */ + + /* volume preservation settings */ + float bulge; + float bulge_min; + float bulge_max; + float bulge_smooth; } bSplineIKConstraint; @@ -680,15 +686,19 @@ typedef enum eKinematic_Flags { /* bSplineIKConstraint->flag */ typedef enum eSplineIK_Flags { /* chain has been attached to spline */ - CONSTRAINT_SPLINEIK_BOUND = (1<<0), + CONSTRAINT_SPLINEIK_BOUND = (1 << 0), /* root of chain is not influenced by the constraint */ - CONSTRAINT_SPLINEIK_NO_ROOT = (1<<1), + CONSTRAINT_SPLINEIK_NO_ROOT = (1 << 1), /* bones in the chain should not scale to fit the curve */ - CONSTRAINT_SPLINEIK_SCALE_LIMITED = (1<<2), + CONSTRAINT_SPLINEIK_SCALE_LIMITED = (1 << 2), /* evenly distribute the bones along the path regardless of length */ - CONSTRAINT_SPLINEIK_EVENSPLITS = (1<<3), + CONSTRAINT_SPLINEIK_EVENSPLITS = (1 << 3), /* don't adjust the x and z scaling of the bones by the curve radius */ - CONSTRAINT_SPLINEIK_NO_CURVERAD = (1<<4) + CONSTRAINT_SPLINEIK_NO_CURVERAD = (1 << 4), + + /* for "volumetric" xz scale mode, limit the minimum or maximum scale values */ + CONSTRAINT_SPLINEIK_USE_BULGE_MIN = (1 << 5), + CONSTRAINT_SPLINEIK_USE_BULGE_MAX = (1 << 6), } eSplineIK_Flags; /* bSplineIKConstraint->xzScaleMode */ @@ -698,7 +708,9 @@ typedef enum eSplineIK_XZScaleModes { /* bones in the chain should take their x/z scales from the original scaling */ CONSTRAINT_SPLINEIK_XZS_ORIGINAL = 1, /* x/z scales are the inverse of the y-scale */ - CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC = 2 + CONSTRAINT_SPLINEIK_XZS_INVERSE = 2, + /* x/z scales are computed using a volume preserving technique (from Stretch To constraint) */ + CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC = 3 } eSplineIK_XZScaleModes; /* MinMax (floor) flags */ diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 87496fb491f..288743d5e2f 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -270,86 +270,101 @@ typedef struct Curve { /* **************** CURVE ********************* */ -/* texflag */ -#define CU_AUTOSPACE 1 - -/* drawflag */ -#define CU_HIDE_HANDLES (1 << 0) -#define CU_HIDE_NORMALS (1 << 1) - -/* flag */ -#define CU_3D 1 -#define CU_FRONT 2 -#define CU_BACK 4 -#define CU_PATH 8 -#define CU_FOLLOW 16 -#define CU_UV_ORCO 32 -#define CU_DEFORM_BOUNDS_OFF 64 -#define CU_STRETCH 128 -/* #define CU_OFFS_PATHDIST 256 */ /* DEPRECATED */ -#define CU_FAST 512 /* Font: no filling inside editmode */ -/* #define CU_RETOPO 1024 */ /* DEPRECATED */ -#define CU_DS_EXPAND 2048 -#define CU_PATH_RADIUS 4096 /* make use of the path radius if this is enabled (default for new curves) */ -#define CU_DEFORM_FILL 8192 /* fill 2d curve after deformation */ -#define CU_FILL_CAPS 16384 /* fill bevel caps */ -#define CU_MAP_TAPER 32768 /* map taper object to beveled area */ - -/* twist mode */ -#define CU_TWIST_Z_UP 0 -// #define CU_TWIST_Y_UP 1 // not used yet -// #define CU_TWIST_X_UP 2 -#define CU_TWIST_MINIMUM 3 -#define CU_TWIST_TANGENT 4 - -/* bevel factor mapping */ +/* Curve.texflag */ enum { - CU_BEVFAC_MAP_RESOLU = 0, + CU_AUTOSPACE = 1, +}; + +/* Curve.drawflag */ +enum { + CU_HIDE_HANDLES = 1 << 0, + CU_HIDE_NORMALS = 1 << 1, +}; + +/* Curve.flag */ +enum { + CU_3D = 1 << 0, + CU_FRONT = 1 << 1, + CU_BACK = 1 << 2, + CU_PATH = 1 << 3, + CU_FOLLOW = 1 << 4, + CU_UV_ORCO = 1 << 5, + CU_DEFORM_BOUNDS_OFF = 1 << 6, + CU_STRETCH = 1 << 7, + /* CU_OFFS_PATHDIST = 1 << 8, */ /* DEPRECATED */ + CU_FAST = 1 << 9, /* Font: no filling inside editmode */ + /* CU_RETOPO = 1 << 10, */ /* DEPRECATED */ + CU_DS_EXPAND = 1 << 11, + CU_PATH_RADIUS = 1 << 12, /* make use of the path radius if this is enabled (default for new curves) */ + CU_DEFORM_FILL = 1 << 13, /* fill 2d curve after deformation */ + CU_FILL_CAPS = 1 << 14, /* fill bevel caps */ + CU_MAP_TAPER = 1 << 15, /* map taper object to beveled area */ +}; + +/* Curve.twist_mode */ +enum { + CU_TWIST_Z_UP = 0, + /* CU_TWIST_Y_UP = 1, */ /* not used yet */ + /* CU_TWIST_X_UP = 2, */ + CU_TWIST_MINIMUM = 3, + CU_TWIST_TANGENT = 4, +}; + +/* Curve.bevfac1_mapping, Curve.bevfac2_mapping, bevel factor mapping */ +enum { + CU_BEVFAC_MAP_RESOLU = 0, CU_BEVFAC_MAP_SEGMENT = 1, - CU_BEVFAC_MAP_SPLINE = 2 + CU_BEVFAC_MAP_SPLINE = 2, +}; + +/* Curve.spacemode */ +enum { + CU_LEFT = 0, + CU_MIDDLE = 1, + CU_RIGHT = 2, + CU_JUSTIFY = 3, + CU_FLUSH = 4, }; -/* spacemode */ -#define CU_LEFT 0 -#define CU_MIDDLE 1 -#define CU_RIGHT 2 -#define CU_JUSTIFY 3 -#define CU_FLUSH 4 - -/* flag (nurb) */ -#define CU_SMOOTH 1 -#define CU_2D 8 /* moved from type since 2.4x */ - -/* type (nurb) */ -#define CU_POLY 0 -#define CU_BEZIER 1 -#define CU_BSPLINE 2 -#define CU_CARDINAL 3 -#define CU_NURBS 4 -#define CU_TYPE (CU_POLY|CU_BEZIER|CU_BSPLINE|CU_CARDINAL|CU_NURBS) - - /* only for adding */ -#define CU_PRIMITIVE 0xF00 - - /* 2 or 4 points */ -#define CU_PRIM_CURVE 0x100 - /* 8 points circle */ -#define CU_PRIM_CIRCLE 0x200 - /* 4x4 patch Nurb */ -#define CU_PRIM_PATCH 0x300 -#define CU_PRIM_TUBE 0x400 -#define CU_PRIM_SPHERE 0x500 -#define CU_PRIM_DONUT 0x600 - /* 5 points, 5th order straight line (for anim path) */ -#define CU_PRIM_PATH 0x700 - - -/* flagu flagv (nurb) */ -#define CU_NURB_CYCLIC 1 -#define CU_NURB_ENDPOINT 2 -#define CU_NURB_BEZIER 4 - -#define CU_ACT_NONE -1 +/* Nurb.flag */ +enum { + CU_SMOOTH = 1 << 0, + CU_2D = 1 << 3, /* moved from type since 2.4x */ +}; + +/* Nurb.type */ +enum { + CU_POLY = 0, + CU_BEZIER = 1, + CU_BSPLINE = 2, + CU_CARDINAL = 3, + CU_NURBS = 4, + CU_TYPE = (CU_POLY | CU_BEZIER | CU_BSPLINE | CU_CARDINAL | CU_NURBS), + + /* only for adding */ + CU_PRIMITIVE = 0xF00, + + /* 2 or 4 points */ + CU_PRIM_CURVE = 0x100, + /* 8 points circle */ + CU_PRIM_CIRCLE = 0x200, + /* 4x4 patch Nurb */ + CU_PRIM_PATCH = 0x300, + CU_PRIM_TUBE = 0x400, + CU_PRIM_SPHERE = 0x500, + CU_PRIM_DONUT = 0x600, + /* 5 points, 5th order straight line (for anim path) */ + CU_PRIM_PATH = 0x700, +}; + +/* Nurb.flagu, Nurb.flagv */ +enum { + CU_NURB_CYCLIC = 1 << 0, + CU_NURB_ENDPOINT = 1 << 1, + CU_NURB_BEZIER = 1 << 2, +}; + +#define CU_ACT_NONE -1 /* *************** BEZTRIPLE **************** */ @@ -366,9 +381,9 @@ typedef enum eBezTriple_Handle { /* interpolation modes (used only for BezTriple->ipo) */ typedef enum eBezTriple_Interpolation { /* traditional interpolation */ - BEZT_IPO_CONST = 0, /* constant interpolation */ - BEZT_IPO_LIN = 1, /* linear interpolation */ - BEZT_IPO_BEZ = 2, /* bezier interpolation */ + BEZT_IPO_CONST = 0, /* constant interpolation */ + BEZT_IPO_LIN = 1, /* linear interpolation */ + BEZT_IPO_BEZ = 2, /* bezier interpolation */ /* easing equations */ BEZT_IPO_BACK = 3, @@ -380,7 +395,7 @@ typedef enum eBezTriple_Interpolation { BEZT_IPO_QUAD = 9, BEZT_IPO_QUART = 10, BEZT_IPO_QUINT = 11, - BEZT_IPO_SINE = 12 + BEZT_IPO_SINE = 12, } eBezTriple_Interpolation; /* easing modes (used only for Keyframes - BezTriple->easing) */ @@ -389,15 +404,15 @@ typedef enum eBezTriple_Easing { BEZT_IPO_EASE_IN = 1, BEZT_IPO_EASE_OUT = 2, - BEZT_IPO_EASE_IN_OUT = 3 + BEZT_IPO_EASE_IN_OUT = 3, } eBezTriple_Easing; /* types of keyframe (used only for BezTriple->hide when BezTriple is used in F-Curves) */ typedef enum eBezTriple_KeyframeType { - BEZT_KEYTYPE_KEYFRAME = 0, /* default - 'proper' Keyframe */ - BEZT_KEYTYPE_EXTREME = 1, /* 'extreme' keyframe */ - BEZT_KEYTYPE_BREAKDOWN = 2, /* 'breakdown' keyframe */ - BEZT_KEYTYPE_JITTER = 3, /* 'jitter' keyframe (for adding 'filler' secondary motion) */ + BEZT_KEYTYPE_KEYFRAME = 0, /* default - 'proper' Keyframe */ + BEZT_KEYTYPE_EXTREME = 1, /* 'extreme' keyframe */ + BEZT_KEYTYPE_BREAKDOWN = 2, /* 'breakdown' keyframe */ + BEZT_KEYTYPE_JITTER = 3, /* 'jitter' keyframe (for adding 'filler' secondary motion) */ } eBezTriple_KeyframeType; /* checks if the given BezTriple is selected */ @@ -406,14 +421,16 @@ typedef enum eBezTriple_KeyframeType { /* *************** CHARINFO **************** */ -/* flag */ -/* note: CU_CHINFO_WRAP and CU_CHINFO_SMALLCAPS_TEST are set dynamically */ -#define CU_CHINFO_BOLD (1<<0) -#define CU_CHINFO_ITALIC (1<<1) -#define CU_CHINFO_UNDERLINE (1<<2) -#define CU_CHINFO_WRAP (1<<3) /* wordwrap occurred here */ -#define CU_CHINFO_SMALLCAPS (1<<4) -#define CU_CHINFO_SMALLCAPS_CHECK (1<<5) /* set at runtime, checks if case switching is needed */ +/* CharInfo.flag */ +enum { + /* note: CU_CHINFO_WRAP and CU_CHINFO_SMALLCAPS_TEST are set dynamically */ + CU_CHINFO_BOLD = 1 << 0, + CU_CHINFO_ITALIC = 1 << 1, + CU_CHINFO_UNDERLINE = 1 << 2, + CU_CHINFO_WRAP = 1 << 3, /* wordwrap occurred here */ + CU_CHINFO_SMALLCAPS = 1 << 4, + CU_CHINFO_SMALLCAPS_CHECK = 1 << 5, /* set at runtime, checks if case switching is needed */ +}; /* mixed with KEY_LINEAR but define here since only curve supports */ #define KEY_CU_EASE 3 diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h index fd435317426..939b14a5d32 100644 --- a/source/blender/makesdna/DNA_dynamicpaint_types.h +++ b/source/blender/makesdna/DNA_dynamicpaint_types.h @@ -34,55 +34,71 @@ struct CurveMapping; struct PaintSurfaceData; /* surface format */ -#define MOD_DPAINT_SURFACE_F_PTEX 0 -#define MOD_DPAINT_SURFACE_F_VERTEX 1 -#define MOD_DPAINT_SURFACE_F_IMAGESEQ 2 +enum { + MOD_DPAINT_SURFACE_F_PTEX = 0, + MOD_DPAINT_SURFACE_F_VERTEX = 1, + MOD_DPAINT_SURFACE_F_IMAGESEQ = 2, +}; /* surface type */ -#define MOD_DPAINT_SURFACE_T_PAINT 0 -#define MOD_DPAINT_SURFACE_T_DISPLACE 1 -#define MOD_DPAINT_SURFACE_T_WEIGHT 2 -#define MOD_DPAINT_SURFACE_T_WAVE 3 +enum { + MOD_DPAINT_SURFACE_T_PAINT = 0, + MOD_DPAINT_SURFACE_T_DISPLACE = 1, + MOD_DPAINT_SURFACE_T_WEIGHT = 2, + MOD_DPAINT_SURFACE_T_WAVE = 3, +}; /* surface flags */ -#define MOD_DPAINT_ACTIVE (1<<0) /* Is surface enabled */ +enum { + MOD_DPAINT_ACTIVE = 1 << 0, /* Is surface enabled */ -#define MOD_DPAINT_ANTIALIAS (1<<1) /* do antialiasing */ -#define MOD_DPAINT_DISSOLVE (1<<2) /* do dissolve */ -#define MOD_DPAINT_MULALPHA (1<<3) /* Multiply color by alpha when saving image */ -#define MOD_DPAINT_DISSOLVE_LOG (1<<4) /* Use 1/x for surface dissolve */ -#define MOD_DPAINT_DRY_LOG (1<<5) /* Use 1/x for drying paint */ -#define MOD_DPAINT_PREVIEW (1<<6) /* preview this surface on viewport*/ + MOD_DPAINT_ANTIALIAS = 1 << 1, /* do antialiasing */ + MOD_DPAINT_DISSOLVE = 1 << 2, /* do dissolve */ + MOD_DPAINT_MULALPHA = 1 << 3, /* Multiply color by alpha when saving image */ + MOD_DPAINT_DISSOLVE_LOG = 1 << 4, /* Use 1/x for surface dissolve */ + MOD_DPAINT_DRY_LOG = 1 << 5, /* Use 1/x for drying paint */ + MOD_DPAINT_PREVIEW = 1 << 6, /* preview this surface on viewport*/ -#define MOD_DPAINT_WAVE_OPEN_BORDERS (1<<7) /* passes waves through mesh edges */ -#define MOD_DPAINT_DISP_INCREMENTAL (1<<8) /* builds displace on top of earlier values */ -#define MOD_DPAINT_USE_DRYING (1<<9) /* use drying */ + MOD_DPAINT_WAVE_OPEN_BORDERS = 1 << 7, /* passes waves through mesh edges */ + MOD_DPAINT_DISP_INCREMENTAL = 1 << 8, /* builds displace on top of earlier values */ + MOD_DPAINT_USE_DRYING = 1 << 9, /* use drying */ -#define MOD_DPAINT_OUT1 (1<<10) /* output primary surface */ -#define MOD_DPAINT_OUT2 (1<<11) /* output secondary surface */ + MOD_DPAINT_OUT1 = 1 << 10, /* output primary surface */ + MOD_DPAINT_OUT2 = 1 << 11, /* output secondary surface */ +}; /* image_fileformat */ -#define MOD_DPAINT_IMGFORMAT_PNG 0 -#define MOD_DPAINT_IMGFORMAT_OPENEXR 1 +enum { + MOD_DPAINT_IMGFORMAT_PNG = 0, + MOD_DPAINT_IMGFORMAT_OPENEXR = 1, +}; /* disp_format */ -#define MOD_DPAINT_DISP_DISPLACE 0 /* displacement output displace map */ -#define MOD_DPAINT_DISP_DEPTH 1 /* displacement output depth data */ +enum { + MOD_DPAINT_DISP_DISPLACE = 0, /* displacement output displace map */ + MOD_DPAINT_DISP_DEPTH = 1, /* displacement output depth data */ +}; /* effect */ -#define MOD_DPAINT_EFFECT_DO_SPREAD (1<<0) /* do spread effect */ -#define MOD_DPAINT_EFFECT_DO_DRIP (1<<1) /* do drip effect */ -#define MOD_DPAINT_EFFECT_DO_SHRINK (1<<2) /* do shrink effect */ +enum { + MOD_DPAINT_EFFECT_DO_SPREAD = 1 << 0, /* do spread effect */ + MOD_DPAINT_EFFECT_DO_DRIP = 1 << 1, /* do drip effect */ + MOD_DPAINT_EFFECT_DO_SHRINK = 1 << 2, /* do shrink effect */ +}; /* preview_id */ -#define MOD_DPAINT_SURFACE_PREV_PAINT 0 -#define MOD_DPAINT_SURFACE_PREV_WETMAP 1 +enum { + MOD_DPAINT_SURFACE_PREV_PAINT = 0, + MOD_DPAINT_SURFACE_PREV_WETMAP = 1, +}; /* init_color_type */ -#define MOD_DPAINT_INITIAL_NONE 0 -#define MOD_DPAINT_INITIAL_COLOR 1 -#define MOD_DPAINT_INITIAL_TEXTURE 2 -#define MOD_DPAINT_INITIAL_VERTEXCOLOR 3 +enum { + MOD_DPAINT_INITIAL_NONE = 0, + MOD_DPAINT_INITIAL_COLOR = 1, + MOD_DPAINT_INITIAL_TEXTURE = 2, + MOD_DPAINT_INITIAL_VERTEXCOLOR = 3, +}; typedef struct DynamicPaintSurface { @@ -137,11 +153,14 @@ typedef struct DynamicPaintSurface { } DynamicPaintSurface; /* canvas flags */ -#if 0 /* This should not be needed, having a valid WEIGHT_MCOL layer should be enough. - * And if not, should be a general flag. But seems unnecessary for now... */ -#define MOD_DPAINT_PREVIEW_READY (1<<0) /* if viewport preview is ready */ +enum { + /* This should not be needed, having a valid WEIGHT_MCOL layer should be enough. + * And if not, should be a general flag. But seems unnecessary for now... */ +#if 0 + MOD_DPAINT_PREVIEW_READY = 1 << 0, /* if viewport preview is ready */ #endif -#define MOD_DPAINT_BAKING (1<<1) /* surface is already baking, so it wont get updated (loop) */ + MOD_DPAINT_BAKING = 1 << 1, /* surface is already baking, so it wont get updated (loop) */ +}; /* Canvas settings */ typedef struct DynamicPaintCanvasSettings { @@ -158,47 +177,56 @@ typedef struct DynamicPaintCanvasSettings { /* flags */ -#define MOD_DPAINT_PART_RAD (1<<0) /* use particle radius */ -#define MOD_DPAINT_USE_MATERIAL (1<<1) /* use object material */ -#define MOD_DPAINT_ABS_ALPHA (1<<2) /* don't increase alpha unless - * paint alpha is higher than existing */ -#define MOD_DPAINT_ERASE (1<<3) /* removes paint */ - -#define MOD_DPAINT_RAMP_ALPHA (1<<4) /* only read falloff ramp alpha */ -#define MOD_DPAINT_PROX_PROJECT (1<<5) /* do proximity check only in defined dir */ -#define MOD_DPAINT_INVERSE_PROX (1<<6) /* inverse proximity painting */ -#define MOD_DPAINT_NEGATE_VOLUME (1<<7) /* negates volume influence on "volume + prox" mode */ - -#define MOD_DPAINT_DO_SMUDGE (1<<8) /* brush smudges existing paint */ -#define MOD_DPAINT_VELOCITY_ALPHA (1<<9) /* multiply brush influence by velocity */ -#define MOD_DPAINT_VELOCITY_COLOR (1<<10) /* replace brush color by velocity color ramp */ -#define MOD_DPAINT_VELOCITY_DEPTH (1<<11) /* multiply brush intersection depth by velocity */ - -#define MOD_DPAINT_USES_VELOCITY ((1<<8)|(1<<9)|(1<<10)|(1<<11)) +enum { + MOD_DPAINT_PART_RAD = 1 << 0, /* use particle radius */ + MOD_DPAINT_USE_MATERIAL = 1 << 1, /* use object material */ + MOD_DPAINT_ABS_ALPHA = 1 << 2, /* don't increase alpha unless paint alpha is higher than existing */ + MOD_DPAINT_ERASE = 1 << 3, /* removes paint */ + + MOD_DPAINT_RAMP_ALPHA = 1 << 4, /* only read falloff ramp alpha */ + MOD_DPAINT_PROX_PROJECT = 1 << 5, /* do proximity check only in defined dir */ + MOD_DPAINT_INVERSE_PROX = 1 << 6, /* inverse proximity painting */ + MOD_DPAINT_NEGATE_VOLUME = 1 << 7, /* negates volume influence on "volume + prox" mode */ + + MOD_DPAINT_DO_SMUDGE = 1 << 8, /* brush smudges existing paint */ + MOD_DPAINT_VELOCITY_ALPHA = 1 << 9, /* multiply brush influence by velocity */ + MOD_DPAINT_VELOCITY_COLOR = 1 << 10, /* replace brush color by velocity color ramp */ + MOD_DPAINT_VELOCITY_DEPTH = 1 << 11, /* multiply brush intersection depth by velocity */ + + MOD_DPAINT_USES_VELOCITY = (MOD_DPAINT_DO_SMUDGE | MOD_DPAINT_VELOCITY_ALPHA | + MOD_DPAINT_VELOCITY_COLOR | MOD_DPAINT_VELOCITY_DEPTH), +}; /* collision type */ -#define MOD_DPAINT_COL_VOLUME 0 /* paint with mesh volume */ -#define MOD_DPAINT_COL_DIST 1 /* paint using distance to mesh surface */ -#define MOD_DPAINT_COL_VOLDIST 2 /* use both volume and distance */ -#define MOD_DPAINT_COL_PSYS 3 /* use particle system */ -#define MOD_DPAINT_COL_POINT 4 /* use distance to object center point */ +enum { + MOD_DPAINT_COL_VOLUME = 0, /* paint with mesh volume */ + MOD_DPAINT_COL_DIST = 1, /* paint using distance to mesh surface */ + MOD_DPAINT_COL_VOLDIST = 2, /* use both volume and distance */ + MOD_DPAINT_COL_PSYS = 3, /* use particle system */ + MOD_DPAINT_COL_POINT = 4, /* use distance to object center point */ +}; /* proximity_falloff */ -#define MOD_DPAINT_PRFALL_CONSTANT 0 /* no-falloff */ -#define MOD_DPAINT_PRFALL_SMOOTH 1 /* smooth, linear falloff */ -#define MOD_DPAINT_PRFALL_RAMP 2 /* use color ramp */ +enum { + MOD_DPAINT_PRFALL_CONSTANT = 0, /* no-falloff */ + MOD_DPAINT_PRFALL_SMOOTH = 1, /* smooth, linear falloff */ + MOD_DPAINT_PRFALL_RAMP = 2, /* use color ramp */ +}; /* wave_brush_type */ -#define MOD_DPAINT_WAVEB_DEPTH 0 /* use intersection depth */ -#define MOD_DPAINT_WAVEB_FORCE 1 /* act as a force on intersection area */ -#define MOD_DPAINT_WAVEB_REFLECT 2 /* obstacle that reflects waves */ -#define MOD_DPAINT_WAVEB_CHANGE 3 /* use change of intersection depth from previous frame */ +enum { + MOD_DPAINT_WAVEB_DEPTH = 0, /* use intersection depth */ + MOD_DPAINT_WAVEB_FORCE = 1, /* act as a force on intersection area */ + MOD_DPAINT_WAVEB_REFLECT = 2, /* obstacle that reflects waves */ + MOD_DPAINT_WAVEB_CHANGE = 3, /* use change of intersection depth from previous frame */ +}; /* brush ray_dir */ -#define MOD_DPAINT_RAY_CANVAS 0 -#define MOD_DPAINT_RAY_BRUSH_AVG 1 -#define MOD_DPAINT_RAY_ZPLUS 2 - +enum { + MOD_DPAINT_RAY_CANVAS = 0, + MOD_DPAINT_RAY_BRUSH_AVG = 1, + MOD_DPAINT_RAY_ZPLUS = 2, +}; /* Brush settings */ typedef struct DynamicPaintBrushSettings { diff --git a/source/blender/makesdna/DNA_freestyle_types.h b/source/blender/makesdna/DNA_freestyle_types.h index d099511a088..2359d1e9738 100644 --- a/source/blender/makesdna/DNA_freestyle_types.h +++ b/source/blender/makesdna/DNA_freestyle_types.h @@ -44,60 +44,74 @@ struct Group; struct Text; /* FreestyleConfig::flags */ -#define FREESTYLE_SUGGESTIVE_CONTOURS_FLAG (1 << 0) -#define FREESTYLE_RIDGES_AND_VALLEYS_FLAG (1 << 1) -#define FREESTYLE_MATERIAL_BOUNDARIES_FLAG (1 << 2) -#define FREESTYLE_FACE_SMOOTHNESS_FLAG (1 << 3) -#define FREESTYLE_ADVANCED_OPTIONS_FLAG (1 << 4) -#define FREESTYLE_CULLING (1 << 5) -#define FREESTYLE_VIEW_MAP_CACHE (1 << 6) +enum { + FREESTYLE_SUGGESTIVE_CONTOURS_FLAG = 1 << 0, + FREESTYLE_RIDGES_AND_VALLEYS_FLAG = 1 << 1, + FREESTYLE_MATERIAL_BOUNDARIES_FLAG = 1 << 2, + FREESTYLE_FACE_SMOOTHNESS_FLAG = 1 << 3, + FREESTYLE_ADVANCED_OPTIONS_FLAG = 1 << 4, + FREESTYLE_CULLING = 1 << 5, + FREESTYLE_VIEW_MAP_CACHE = 1 << 6, +}; /* FreestyleConfig::mode */ -#define FREESTYLE_CONTROL_SCRIPT_MODE 1 -#define FREESTYLE_CONTROL_EDITOR_MODE 2 +enum { + FREESTYLE_CONTROL_SCRIPT_MODE = 1, + FREESTYLE_CONTROL_EDITOR_MODE = 2, +}; /* FreestyleLineSet::flags */ -#define FREESTYLE_LINESET_CURRENT (1 << 0) -#define FREESTYLE_LINESET_ENABLED (1 << 1) -#define FREESTYLE_LINESET_FE_NOT (1 << 2) -#define FREESTYLE_LINESET_FE_AND (1 << 3) -#define FREESTYLE_LINESET_GR_NOT (1 << 4) -#define FREESTYLE_LINESET_FM_NOT (1 << 5) -#define FREESTYLE_LINESET_FM_BOTH (1 << 6) +enum { + FREESTYLE_LINESET_CURRENT = 1 << 0, + FREESTYLE_LINESET_ENABLED = 1 << 1, + FREESTYLE_LINESET_FE_NOT = 1 << 2, + FREESTYLE_LINESET_FE_AND = 1 << 3, + FREESTYLE_LINESET_GR_NOT = 1 << 4, + FREESTYLE_LINESET_FM_NOT = 1 << 5, + FREESTYLE_LINESET_FM_BOTH = 1 << 6, +}; /* FreestyleLineSet::selection */ -#define FREESTYLE_SEL_VISIBILITY (1 << 0) -#define FREESTYLE_SEL_EDGE_TYPES (1 << 1) -#define FREESTYLE_SEL_GROUP (1 << 2) -#define FREESTYLE_SEL_IMAGE_BORDER (1 << 3) -#define FREESTYLE_SEL_FACE_MARK (1 << 4) +enum { + FREESTYLE_SEL_VISIBILITY = 1 << 0, + FREESTYLE_SEL_EDGE_TYPES = 1 << 1, + FREESTYLE_SEL_GROUP = 1 << 2, + FREESTYLE_SEL_IMAGE_BORDER = 1 << 3, + FREESTYLE_SEL_FACE_MARK = 1 << 4, +}; /* FreestyleLineSet::edge_types, exclude_edge_types */ -#define FREESTYLE_FE_SILHOUETTE (1 << 0) -#define FREESTYLE_FE_BORDER (1 << 1) -#define FREESTYLE_FE_CREASE (1 << 2) -#define FREESTYLE_FE_RIDGE_VALLEY (1 << 3) -/* Note: FREESTYLE_FE_VALLEY = (1 << 4) is no longer used */ -#define FREESTYLE_FE_SUGGESTIVE_CONTOUR (1 << 5) -#define FREESTYLE_FE_MATERIAL_BOUNDARY (1 << 6) -#define FREESTYLE_FE_CONTOUR (1 << 7) -#define FREESTYLE_FE_EXTERNAL_CONTOUR (1 << 8) -#define FREESTYLE_FE_EDGE_MARK (1 << 9) +enum { + FREESTYLE_FE_SILHOUETTE = 1 << 0, + FREESTYLE_FE_BORDER = 1 << 1, + FREESTYLE_FE_CREASE = 1 << 2, + FREESTYLE_FE_RIDGE_VALLEY = 1 << 3, + /* FREESTYLE_FE_VALLEY = 1 << 4, */ /* No longer used */ + FREESTYLE_FE_SUGGESTIVE_CONTOUR = 1 << 5, + FREESTYLE_FE_MATERIAL_BOUNDARY = 1 << 6, + FREESTYLE_FE_CONTOUR = 1 << 7, + FREESTYLE_FE_EXTERNAL_CONTOUR = 1 << 8, + FREESTYLE_FE_EDGE_MARK = 1 << 9, +}; /* FreestyleLineSet::qi */ -#define FREESTYLE_QI_VISIBLE 1 -#define FREESTYLE_QI_HIDDEN 2 -#define FREESTYLE_QI_RANGE 3 +enum { + FREESTYLE_QI_VISIBLE = 1, + FREESTYLE_QI_HIDDEN = 2, + FREESTYLE_QI_RANGE = 3, +}; /* FreestyleConfig::raycasting_algorithm */ /* Defines should be replaced with ViewMapBuilder::visibility_algo */ -#define FREESTYLE_ALGO_REGULAR 1 -#define FREESTYLE_ALGO_FAST 2 -#define FREESTYLE_ALGO_VERYFAST 3 -#define FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL 4 -#define FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL 5 -#define FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE 6 -#define FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE 7 +enum { + FREESTYLE_ALGO_REGULAR = 1, + FREESTYLE_ALGO_FAST = 2, + FREESTYLE_ALGO_VERYFAST = 3, + FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL = 4, + FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL = 5, + FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE = 6, + FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE = 7, +}; typedef struct FreestyleLineSet { struct FreestyleLineSet *next, *prev; diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 2bf874d3a85..3fb047ebbe7 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -33,6 +33,9 @@ #include "DNA_listBase.h" #include "DNA_ID.h" +struct AnimData; + + /* Grease-Pencil Annotations - 'Stroke Point' * -> Coordinates may either be 2d or 3d depending on settings at the time * -> Coordinates of point on stroke, in proportions of window size @@ -42,8 +45,15 @@ typedef struct bGPDspoint { float x, y, z; /* co-ordinates of point (usually 2d, but can be 3d as well) */ float pressure; /* pressure of input device (from 0 to 1) at this point */ float time; /* seconds since start of stroke */ + int flag; /* additional options (NOTE: can shrink this field down later if needed) */ } bGPDspoint; +/* bGPDspoint->flag */ +typedef enum eGPDspoint_Flag { + /* stroke point is selected (for editing) */ + GP_SPOINT_SELECT = (1 << 0) +} eGPSPoint_Flag; + /* Grease-Pencil Annotations - 'Stroke' * -> A stroke represents a (simplified version) of the curve * drawn by the user in one 'mousedown'->'mouseup' operation @@ -61,15 +71,18 @@ typedef struct bGPDstroke { } bGPDstroke; /* bGPDstroke->flag */ +typedef enum eGPDstroke_Flag { /* stroke is in 3d-space */ -#define GP_STROKE_3DSPACE (1<<0) + GP_STROKE_3DSPACE = (1 << 0), /* stroke is in 2d-space */ -#define GP_STROKE_2DSPACE (1<<1) + GP_STROKE_2DSPACE = (1 << 1), /* stroke is in 2d-space (but with special 'image' scaling) */ -#define GP_STROKE_2DIMAGE (1<<2) + GP_STROKE_2DIMAGE = (1 << 2), + /* stroke is selected */ + GP_STROKE_SELECT = (1 << 3), /* only for use with stroke-buffer (while drawing eraser) */ -#define GP_STROKE_ERASER (1<<15) - + GP_STROKE_ERASER = (1 << 15) +} eGPDstroke_Flag; /* Grease-Pencil Annotations - 'Frame' * -> Acts as storage for the 'image' formed by strokes @@ -80,15 +93,18 @@ typedef struct bGPDframe { ListBase strokes; /* list of the simplified 'strokes' that make up the frame's data */ int framenum; /* frame number of this frame */ - int flag; /* temp settings */ + + short flag; /* temp settings */ + short key_type; /* keyframe type (eBezTriple_KeyframeType) */ } bGPDframe; -/* bGPDframe->flag */ +/* bGPDframe->flag */ +typedef enum eGPDframe_Flag { /* frame is being painted on */ -#define GP_FRAME_PAINT (1<<0) + GP_FRAME_PAINT = (1 << 0), /* for editing in Action Editor */ -#define GP_FRAME_SELECT (1<<1) - + GP_FRAME_SELECT = (1 << 1) +} eGPDframe_Flag; /* Grease-Pencil Annotations - 'Layer' */ typedef struct bGPDlayer { @@ -97,38 +113,52 @@ typedef struct bGPDlayer { ListBase frames; /* list of annotations to display for frames (bGPDframe list) */ bGPDframe *actframe; /* active frame (should be the frame that is currently being displayed) */ - int flag; /* settings for layer */ + short flag; /* settings for layer */ short thickness; /* current thickness to apply to strokes */ - short gstep; /* max number of frames between active and ghost to show (0=only those on either side) */ + + short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */ + short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */ + + float gcolor_prev[3]; /* optional color for ghosts before the active frame */ + float gcolor_next[3]; /* optional color for ghosts after the active frame */ float color[4]; /* color that should be used to draw all the strokes in this layer */ + float fill[4]; /* color that should be used for drawing "fills" for strokes */ char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3") * this is used for the name of the layer too and kept unique. */ } bGPDlayer; /* bGPDlayer->flag */ +typedef enum eGPDlayer_Flag { /* don't display layer */ -#define GP_LAYER_HIDE (1<<0) + GP_LAYER_HIDE = (1 << 0), /* protected from further editing */ -#define GP_LAYER_LOCKED (1<<1) + GP_LAYER_LOCKED = (1 << 1), /* layer is 'active' layer being edited */ -#define GP_LAYER_ACTIVE (1<<2) + GP_LAYER_ACTIVE = (1 << 2), /* draw points of stroke for debugging purposes */ -#define GP_LAYER_DRAWDEBUG (1<<3) - /* do onionskinning */ -#define GP_LAYER_ONIONSKIN (1<<4) + GP_LAYER_DRAWDEBUG = (1 << 3), + /* do onion skinning */ + GP_LAYER_ONIONSKIN = (1 << 4), /* for editing in Action Editor */ -#define GP_LAYER_SELECT (1<<5) + GP_LAYER_SELECT = (1 << 5), /* current frame for layer can't be changed */ -#define GP_LAYER_FRAMELOCK (1<<6) + GP_LAYER_FRAMELOCK = (1 << 6), /* don't render xray (which is default) */ -#define GP_LAYER_NO_XRAY (1<<7) - + GP_LAYER_NO_XRAY = (1 << 7), + /* use custom color for ghosts before current frame */ + GP_LAYER_GHOST_PREVCOL = (1 << 8), + /* use custom color for ghosts after current frame */ + GP_LAYER_GHOST_NEXTCOL = (1 << 9), + /* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */ + GP_LAYER_VOLUMETRIC = (1 << 10), +} eGPDlayer_Flag; /* Grease-Pencil Annotations - 'DataBlock' */ typedef struct bGPdata { - ID id; /* Grease Pencil data is */ + ID id; /* Grease Pencil data is a datablock */ + struct AnimData *adt; /* animation data - for animating draw settings */ /* saved Grease-Pencil data */ ListBase layers; /* bGPDlayers */ @@ -144,23 +174,33 @@ typedef struct bGPdata { } bGPdata; /* bGPdata->flag */ -// XXX many of these flags should be deprecated for more general ideas in 2.5 +/* NOTE: A few flags have been deprecated since early 2.5, + * since they have been made redundant by interaction + * changes made during the porting process. + */ +typedef enum eGPdata_Flag { /* don't allow painting to occur at all */ - // XXX is deprecated - not well understood -// #define GP_DATA_LMBPLOCK (1<<0) + /* GP_DATA_LMBPLOCK = (1 << 0), */ + /* show debugging info in viewport (i.e. status print) */ -#define GP_DATA_DISPINFO (1<<1) + GP_DATA_DISPINFO = (1 << 1), /* in Action Editor, show as expanded channel */ -#define GP_DATA_EXPAND (1<<2) + GP_DATA_EXPAND = (1 << 2), + /* is the block overriding all clicks? */ - // XXX is deprecated - nasty old concept -// #define GP_DATA_EDITPAINT (1<<3) + /* GP_DATA_EDITPAINT = (1 << 3), */ + /* new strokes are added in viewport space */ -#define GP_DATA_VIEWALIGN (1<<4) - /* Project into the screens Z values */ -#define GP_DATA_DEPTH_VIEW (1<<5) -#define GP_DATA_DEPTH_STROKE (1<<6) + GP_DATA_VIEWALIGN = (1 << 4), + + /* Project into the screen's Z values */ + GP_DATA_DEPTH_VIEW = (1 << 5), + GP_DATA_DEPTH_STROKE = (1 << 6), -#define GP_DATA_DEPTH_STROKE_ENDPOINTS (1<<7) + GP_DATA_DEPTH_STROKE_ENDPOINTS = (1 << 7), + + /* Stroke Editing Mode - Toggle to enable alternative keymap for easier editing of stroke points */ + GP_DATA_STROKE_EDITMODE = (1 << 8) +} eGPdata_Flag; #endif /* __DNA_GPENCIL_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h index 16e40fa52e1..60ab01c901b 100644 --- a/source/blender/makesdna/DNA_key_types.h +++ b/source/blender/makesdna/DNA_key_types.h @@ -91,10 +91,10 @@ typedef struct Key { ID *from; - short type; /* absolute or relative shape key */ - short totkey; /* (totkey == BLI_listbase_count(&key->block)) */ - short slurph; /* quaint feature to delay moving points based on their order (Key->type == KEY_NORMAL) only */ + int totkey; /* (totkey == BLI_listbase_count(&key->block)) */ short flag; + char type; /* absolute or relative shape key */ + char pad2; /* only used when (Key->type == KEY_NORMAL), this value is used as a time slider, * rather then using the scenes time, this value can be animated to give greater control */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 688e17ef56a..8067fa5db2d 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -201,7 +201,7 @@ enum { ME_DRAW_VNORMALS = 1 << 3, ME_DRAWEIGHT = 1 << 4, - ME_HIDDENEDGES = 1 << 5, + /* ME_HIDDENEDGES = 1 << 5, */ /* DEPRECATED */ ME_DRAWCREASES = 1 << 6, ME_DRAWSEAMS = 1 << 7, diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 5ab82f86ff5..7b1a9bba3a2 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -82,7 +82,8 @@ typedef enum ModifierType { eModifierType_MeshCache = 46, eModifierType_LaplacianDeform = 47, eModifierType_Wireframe = 48, - eModifierType_PointCache = 49, + eModifierType_DataTransfer = 49, + eModifierType_PointCache = 50, NUM_MODIFIER_TYPES } ModifierType; @@ -1367,6 +1368,49 @@ enum { MOD_WIREFRAME_CREASE = (1 << 5), }; + +typedef struct DataTransferModifierData { + ModifierData modifier; + + struct Object *ob_source; + + int data_types; /* See DT_TYPE_ enum in ED_object.h */ + + /* See MREMAP_MODE_ enum in BKE_mesh_mapping.h */ + int vmap_mode; + int emap_mode; + int lmap_mode; + int pmap_mode; + + float map_max_distance; + float map_ray_radius; + float islands_precision; + + int pad_i1; + + int layers_select_src[4]; /* DT_MULTILAYER_INDEX_MAX; See DT_FROMLAYERS_ enum in ED_object.h */ + int layers_select_dst[4]; /* DT_MULTILAYER_INDEX_MAX; See DT_TOLAYERS_ enum in ED_object.h */ + + int mix_mode; /* See CDT_MIX_ enum in BKE_customdata.h */ + float mix_factor; + char defgrp_name[64]; /* MAX_VGROUP_NAME */ + + int flags; +} DataTransferModifierData; + +/* DataTransferModifierData.flags */ +enum { + MOD_DATATRANSFER_OBSRC_TRANSFORM = 1 << 0, + MOD_DATATRANSFER_MAP_MAXDIST = 1 << 1, + MOD_DATATRANSFER_INVERT_VGROUP = 1 << 2, + + /* Only for UI really. */ + MOD_DATATRANSFER_USE_VERT = 1 << 28, + MOD_DATATRANSFER_USE_EDGE = 1 << 29, + MOD_DATATRANSFER_USE_LOOP = 1 << 30, + MOD_DATATRANSFER_USE_POLY = 1 << 31, +}; + /* point cache modifier */ typedef struct PointCacheModifierData { ModifierData modifier; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 745b21618ca..49f8b3cd4d0 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -985,25 +985,36 @@ typedef struct UnifiedPaintSettings { /* record movement of mouse so that rake can start at an intuitive angle */ float last_rake[2]; + float last_rake_angle; + + int last_stroke_valid; + float average_stroke_accum[3]; + int average_stroke_counter; + float brush_rotation; + float brush_rotation_sec; /********************************************************************************* * all data below are used to communicate with cursor drawing and tex sampling * *********************************************************************************/ - int draw_anchored; int anchored_size; - char draw_inverted; - char pad3[7]; - float overlap_factor; /* normalization factor due to accumulated value of curve along spacing. * Calculated when brush spacing changes to dampen strength of stroke * if space attenuation is used*/ + char draw_inverted; + /* check is there an ongoing stroke right now */ + char stroke_active; + + char draw_anchored; + char do_linear_conversion; + float anchored_initial_mouse[2]; - /* check is there an ongoing stroke right now */ - int stroke_active; + /* radius of brush, premultiplied with pressure. + * In case of anchored brushes contains the anchored radius */ + float pixel_radius; /* drawing pressure */ float size_pressure_value; @@ -1015,13 +1026,7 @@ typedef struct UnifiedPaintSettings { float mask_tex_mouse[2]; /* ColorSpace cache to avoid locking up during sampling */ - int do_linear_conversion; struct ColorSpace *colorspace; - - /* radius of brush, premultiplied with pressure. - * In case of anchored brushes contains the anchored radius */ - float pixel_radius; - int pad4; } UnifiedPaintSettings; typedef enum { @@ -1093,9 +1098,10 @@ typedef struct ToolSettings { short autoik_chainlen; /* runtime only */ /* Grease Pencil */ - char gpencil_flags; + char gpencil_flags; /* flags/options for how the tool works */ + char gpencil_src; /* for main 3D view Grease Pencil, where data comes from */ - char pad[5]; + char pad[4]; /* Image Paint (8 byttse aligned please!) */ struct ImagePaintSettings imapaint; @@ -1769,6 +1775,12 @@ typedef enum ImagePaintMode { /* toolsettings->gpencil_flags */ #define GP_TOOL_FLAG_PAINTSESSIONS_ON (1<<0) +/* toolsettings->gpencil_src */ +typedef enum eGPencil_Source_3D { + GP_TOOL_SOURCE_SCENE = 0, + GP_TOOL_SOURCE_OBJECT = 1 +} eGPencil_Source_3d; + /* toolsettings->particle flag */ #define PE_KEEP_LENGTHS 1 #define PE_LOCK_FIRST 2 diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 47a08c62f95..7372f55c3de 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -57,24 +57,23 @@ typedef struct bScreen { struct Scene *scene; struct Scene *newscene; /* temporary when switching */ - int redraws_flag; /* user-setting for which editors get redrawn during anim playback (used to be time->redraws) */ - int pad1; - - short state; /* temp screen for image render display or fileselect */ - short temp; /* temp screen in a temp window, don't save (like user prefs) */ short winid; /* winid from WM, starts with 1 */ - short do_draw; /* notifier for drawing edges */ - short do_refresh; /* notifier for scale screen, changed screen, etc */ - short do_draw_gesture; /* notifier for gesture draw. */ - short do_draw_paintcursor; /* notifier for paint cursor draw. */ - short do_draw_drag; /* notifier for dragging draw. */ - short swap; /* indicator to survive swap-exchange systems */ + short redraws_flag; /* user-setting for which editors get redrawn during anim playback (used to be time->redraws) */ + + char temp; /* temp screen in a temp window, don't save (like user prefs) */ + char state; /* temp screen for image render display or fileselect */ + char do_draw; /* notifier for drawing edges */ + char do_refresh; /* notifier for scale screen, changed screen, etc */ + char do_draw_gesture; /* notifier for gesture draw. */ + char do_draw_paintcursor; /* notifier for paint cursor draw. */ + char do_draw_drag; /* notifier for dragging draw. */ + char swap; /* indicator to survive swap-exchange systems */ + char skip_handling; /* set to delay screen handling after switching back from maximized area */ + char pad[7]; short mainwin; /* screensize subwindow, for screenedges and global menus */ short subwinactive; /* active subwindow */ - - short pad; - + struct wmTimer *animtimer; /* if set, screen has timer handler added in window */ void *context; /* context callback */ } bScreen; @@ -215,7 +214,7 @@ typedef struct ScrArea { short do_refresh; /* private, for spacetype refresh callback */ short flag; short region_active_win; /* index of last used region of 'RGN_TYPE_WINDOW' - * runtuime variable, updated by executing operators */ + * runtime variable, updated by executing operators */ char temp, pad; struct SpaceType *type; /* callbacks for this space type */ @@ -272,12 +271,16 @@ typedef struct ARegion { // #define WIN_EQUAL 3 // UNUSED /* area->flag */ -#define HEADER_NO_PULLDOWN (1 << 0) -#define AREA_FLAG_DRAWJOINTO (1 << 1) -#define AREA_FLAG_DRAWJOINFROM (1 << 2) -#define AREA_TEMP_INFO (1 << 3) -#define AREA_FLAG_DRAWSPLIT_H (1 << 4) -#define AREA_FLAG_DRAWSPLIT_V (1 << 5) +enum { + HEADER_NO_PULLDOWN = (1 << 0), + AREA_FLAG_DRAWJOINTO = (1 << 1), + AREA_FLAG_DRAWJOINFROM = (1 << 2), + AREA_TEMP_INFO = (1 << 3), + AREA_FLAG_DRAWSPLIT_H = (1 << 4), + AREA_FLAG_DRAWSPLIT_V = (1 << 5), + /* used to check if we should switch back to prevspace (of a different type) */ + AREA_FLAG_TEMP_TYPE = (1 << 6), +}; #define EDGEWIDTH 1 #define AREAGRID 4 diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index af33ae80ed9..20678bdae49 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -131,10 +131,11 @@ typedef struct Sequence { int flag, type; /*flags bitmap (see below) and the type of sequence*/ int len; /* the length of the contents of this strip - before handles are applied */ - int start, startofs, endofs; - int startstill, endstill; + int start; /* start frame of contents of strip in absolute frame coordinates. For metastrips start of first strip startdisp */ + int startofs, endofs; /* frames after the first frame where display starts, frames before the last frame where display ends */ + int startstill, endstill; /* frames that use the first frame before data begins, frames that use the last frame after data ends */ int machine, depth; /*machine - the strip channel, depth - the depth in the sequence when dealing with metastrips */ - int startdisp, enddisp; /*starting and ending points in the sequence*/ + int startdisp, enddisp; /* starting and ending points of the strip in the sequence*/ float sat; float mul, handsize; @@ -362,6 +363,9 @@ enum { SEQ_AUDIO_PITCH_ANIMATED = (1 << 25), SEQ_AUDIO_PAN_ANIMATED = (1 << 26), SEQ_AUDIO_DRAW_WAVEFORM = (1 << 27), + + /* don't include Grease Pencil in OpenGL previews of Scene strips */ + SEQ_SCENE_NO_GPENCIL = (1 << 28), SEQ_INVALID_EFFECT = (1 << 31), }; diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h index d7a51359777..4ab22e4f7b7 100644 --- a/source/blender/makesdna/DNA_sound_types.h +++ b/source/blender/makesdna/DNA_sound_types.h @@ -95,6 +95,8 @@ typedef struct bSound { */ void *playback_handle; + /* mutex for asynchronous loading of sounds */ + void *mutex; /* XXX unused currently (SOUND_TYPE_LIMITER) */ /* float start, end; */ } bSound; @@ -116,9 +118,10 @@ enum { }; enum { - SOUND_FLAGS_3D = (1 << 3), /* deprecated! used for sound actuator loading */ - SOUND_FLAGS_CACHING = (1 << 4), - SOUND_FLAGS_MONO = (1 << 5), + SOUND_FLAGS_3D = (1 << 3), /* deprecated! used for sound actuator loading */ + SOUND_FLAGS_CACHING = (1 << 4), + SOUND_FLAGS_MONO = (1 << 5), + SOUND_FLAGS_WAVEFORM_LOADING = (1 << 6), }; #if (DNA_DEPRECATED_GCC_POISON == 1) diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index a8fe8ceb6b0..f65cef1a0d1 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -497,6 +497,8 @@ typedef struct SpaceSeq { float zoom DNA_DEPRECATED; /* deprecated, handled by View2D now */ int view; /* see SEQ_VIEW_* below */ int overlay_type; + int draw_flag; /* overlay an image of the editing on below the strips */ + int pad; struct bGPdata *gpd; /* grease-pencil data */ @@ -513,6 +515,13 @@ typedef enum eSpaceSeq_RegionType { SEQ_DRAW_IMG_HISTOGRAM = 4, } eSpaceSeq_RegionType; +/* sseq->draw_flag */ +typedef enum eSpaceSeq_DrawFlag { + SEQ_DRAW_BACKDROP = (1 << 0), + SEQ_DRAW_OFFSET_EXT = (1 << 1), +} eSpaceSeq_DrawFlag; + + /* sseq->flag */ typedef enum eSpaceSeq_Flag { SEQ_DRAWFRAMES = (1 << 0), @@ -522,6 +531,8 @@ typedef enum eSpaceSeq_Flag { SEQ_SHOW_GPENCIL = (1 << 4), SEQ_NO_DRAW_CFRANUM = (1 << 5), SEQ_USE_ALPHA = (1 << 6), /* use RGBA display mode for preview */ + SEQ_ALL_WAVEFORMS = (1 << 7), /* draw all waveforms */ + SEQ_NO_WAVEFORMS = (1 << 8), /* draw no waveforms */ } eSpaceSeq_Flag; /* sseq->view */ @@ -565,14 +576,17 @@ typedef enum eSpaceSeq_OverlayType { /* Config and Input for File Selector */ typedef struct FileSelectParams { char title[96]; /* title, also used for the text of the execute button */ - char dir[1056]; /* directory, FILE_MAX_LIBEXTRA, 1024 + 32, this is for extreme case when 1023 length path + char dir[1090]; /* directory, FILE_MAX_LIBEXTRA, 1024 + 66, this is for extreme case when 1023 length path * needs to be linked in, where foo.blend/Armature need adding */ + char pad_c1[2]; char file[256]; /* file */ char renamefile[256]; char renameedit[256]; /* annoying but the first is only used for initialization */ char filter_glob[64]; /* list of filetypes to filter */ + char filter_search[64]; /* text items' name must match to be shown. */ + int active_file; int sel_first; int sel_last; @@ -680,28 +694,28 @@ typedef enum eFileSel_Params_Flag { /* files in filesel list: file types */ typedef enum eFileSel_File_Types { - BLENDERFILE = (1 << 2), - BLENDERFILE_BACKUP = (1 << 3), - IMAGEFILE = (1 << 4), - MOVIEFILE = (1 << 5), - PYSCRIPTFILE = (1 << 6), - FTFONTFILE = (1 << 7), - SOUNDFILE = (1 << 8), - TEXTFILE = (1 << 9), - MOVIEFILE_ICON = (1 << 10), /* movie file that preview can't load */ - FOLDERFILE = (1 << 11), /* represents folders for filtering */ - BTXFILE = (1 << 12), - COLLADAFILE = (1 << 13), - OPERATORFILE = (1 << 14), /* from filter_glob operator property */ - APPLICATIONBUNDLE = (1 << 15), + FILE_TYPE_BLENDER = (1 << 2), + FILE_TYPE_BLENDER_BACKUP = (1 << 3), + FILE_TYPE_IMAGE = (1 << 4), + FILE_TYPE_MOVIE = (1 << 5), + FILE_TYPE_PYSCRIPT = (1 << 6), + FILE_TYPE_FTFONT = (1 << 7), + FILE_TYPE_SOUND = (1 << 8), + FILE_TYPE_TEXT = (1 << 9), + FILE_TYPE_MOVIE_ICON = (1 << 10), /* movie file that preview can't load */ + FILE_TYPE_FOLDER = (1 << 11), /* represents folders for filtering */ + FILE_TYPE_BTX = (1 << 12), + FILE_TYPE_COLLADA = (1 << 13), + FILE_TYPE_OPERATOR = (1 << 14), /* from filter_glob operator property */ + FILE_TYPE_APPLICATIONBUNDLE = (1 << 15), } eFileSel_File_Types; /* Selection Flags in filesel: struct direntry, unsigned char selflag */ typedef enum eDirEntry_SelectFlag { -/* ACTIVE_FILE = (1 << 1), */ /* UNUSED */ - HILITED_FILE = (1 << 2), - SELECTED_FILE = (1 << 3), - EDITING_FILE = (1 << 4), +/* FILE_SEL_ACTIVE = (1 << 1), */ /* UNUSED */ + FILE_SEL_HIGHLIGHTED = (1 << 2), + FILE_SEL_SELECTED = (1 << 3), + FILE_SEL_EDITING = (1 << 4), } eDirEntry_SelectFlag; /* Image/UV Editor ======================================== */ diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index d256cfb2e85..042645eeb76 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -62,11 +62,12 @@ typedef struct MTex { char uvname[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ char projx, projy, projz, mapping; - float ofs[3], size[3], rot; - + char brush_map_mode, brush_angle_mode; + char pad[2]; + float ofs[3], size[3], rot, random_angle; + short texflag, colormodel, pmapto, pmaptoneg; short normapspace, which_output; - char brush_map_mode, pad[7]; float r, g, b, k; float def_var, rt; @@ -512,6 +513,10 @@ typedef struct ColorMapping { #define MTEX_MAP_MODE_RANDOM 4 #define MTEX_MAP_MODE_STENCIL 5 +/* brush_angle_mode */ +#define MTEX_ANGLE_RANDOM 1 +#define MTEX_ANGLE_RAKE 2 + /* **************** ColorBand ********************* */ /* colormode */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index d8653e1f5fe..11807ba5338 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -168,7 +168,7 @@ typedef struct ThemeUI { uiPanelColors panel; /* depricated, but we keep it for do_versions (2.66.1) */ - char emboss[4]; + char widget_emboss[4]; /* fac: 0 - 1 for blend factor, width in pixels */ float menu_shadow_fac; @@ -251,6 +251,7 @@ typedef struct ThemeSpace { char bone_solid[4], bone_pose[4], bone_pose_active[4]; char strip[4], strip_select[4]; char cframe[4]; + char time_keyframe[4], time_gp_keyframe[4]; char freestyle_edge_mark[4], freestyle_face_mark[4]; char nurb_uline[4], nurb_vline[4]; @@ -295,7 +296,10 @@ typedef struct ThemeSpace { char bundle_solid[4]; char path_before[4], path_after[4]; char camera_path[4]; - char hpad[3]; + char hpad[2]; + + char gp_vertex_size; + char gp_vertex[4], gp_vertex_select[4]; char preview_back[4]; char preview_stitch_face[4]; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 3efba488299..0eee28e73d9 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -201,7 +201,9 @@ typedef struct View3D { char gridflag; /* transform widget info */ - char twtype, twmode, twflag, pad2[2]; + char twtype, twmode, twflag; + + short flag3; /* afterdraw, for xray & transparent */ struct ListBase afterdraw_transp; @@ -267,21 +269,24 @@ typedef struct View3D { ((view >= RV3D_VIEW_FRONT) && (view <= RV3D_VIEW_BOTTOM)) /* View3d->flag2 (short) */ -#define V3D_RENDER_OVERRIDE 4 -#define V3D_SOLID_TEX 8 -#define V3D_SHOW_GPENCIL 16 -#define V3D_LOCK_CAMERA 32 -#define V3D_RENDER_SHADOW 64 /* This is a runtime only flag that's used to tell draw_mesh_object() that we're doing a shadow pass instead of a regular draw */ -#define V3D_SHOW_RECONSTRUCTION 128 -#define V3D_SHOW_CAMERAPATH 256 -#define V3D_SHOW_BUNDLENAME 512 -#define V3D_BACKFACE_CULLING 1024 -#define V3D_RENDER_BORDER 2048 -#define V3D_SOLID_MATCAP 4096 /* user flag */ -#define V3D_SHOW_SOLID_MATCAP 8192 /* runtime flag */ -#define V3D_OCCLUDE_WIRE 16384 -#define V3D_SHADELESS_TEX 32768 - +#define V3D_RENDER_OVERRIDE (1 << 2) +#define V3D_SOLID_TEX (1 << 3) +#define V3D_SHOW_GPENCIL (1 << 4) +#define V3D_LOCK_CAMERA (1 << 5) +#define V3D_RENDER_SHADOW (1 << 6) /* This is a runtime only flag that's used to tell draw_mesh_object() that we're doing a shadow pass instead of a regular draw */ +#define V3D_SHOW_RECONSTRUCTION (1 << 7) +#define V3D_SHOW_CAMERAPATH (1 << 8) +#define V3D_SHOW_BUNDLENAME (1 << 9) +#define V3D_BACKFACE_CULLING (1 << 10) +#define V3D_RENDER_BORDER (1 << 11) +#define V3D_SOLID_MATCAP (1 << 12) /* user flag */ +#define V3D_SHOW_SOLID_MATCAP (1 << 13) /* runtime flag */ +#define V3D_OCCLUDE_WIRE (1 << 14) +#define V3D_SHADELESS_TEX (1 << 15) + + +/* View3d->flag3 (short) */ +#define V3D_SHOW_WORLD (1 << 0) /* View3D->around */ #define V3D_CENTER 0 diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 73a70b48712..1a0562ae8c5 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -165,6 +165,13 @@ enum { WM_INIT_KEYMAP = (1<<1), }; +/* IME is win32 only! */ +#ifndef WIN32 +# ifdef __GNUC__ +# define ime_data ime_data __attribute__ ((deprecated)) +# endif +#endif + /* the savable part, rest of data is local in ghostwinlay */ typedef struct wmWindow { struct wmWindow *next, *prev; @@ -197,6 +204,10 @@ typedef struct wmWindow { struct wmGesture *tweak; /* internal for wm_operators.c */ + /* Input Method Editor data - complex character input (esp. for asian character input) + * Currently WIN32, runtime-only data */ + struct wmIMEData *ime_data; + int drawmethod, drawfail; /* internal for wm_draw.c only */ void *drawdata; /* internal for wm_draw.c only */ @@ -208,6 +219,10 @@ typedef struct wmWindow { ListBase gesture; /* gesture stuff */ } wmWindow; +#ifdef ime_data +# undef ime_data +#endif + /* These two Lines with # tell makesdna this struct can be excluded. */ /* should be something like DNA_EXCLUDE * but the preprocessor first removes all comments, spaces etc */ diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h index 50542797f0b..2a9bcc20a9f 100644 --- a/source/blender/makesdna/DNA_world_types.h +++ b/source/blender/makesdna/DNA_world_types.h @@ -128,6 +128,7 @@ typedef struct World { /* nodes */ struct bNodeTree *nodetree; + ListBase gpumaterial; /* runtime */ } World; /* **************** WORLD ********************* */ diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 46b51080419..5f5714ec831 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -910,7 +910,7 @@ static void dna_write(FILE *file, const void *pntr, const int size) int i; const char *data; - data = (char *) pntr; + data = (const char *)pntr; for (i = 0; i < size; i++) { fprintf(file, "%d, ", data[i]); diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index c8902de756f..3e1a029567d 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -199,6 +199,7 @@ extern StructRNA RNA_CurveMapping; extern StructRNA RNA_CurveModifier; extern StructRNA RNA_CurvePoint; extern StructRNA RNA_DampedTrackConstraint; +extern StructRNA RNA_DataTransferModifier; extern StructRNA RNA_DecimateModifier; extern StructRNA RNA_DelaySensor; extern StructRNA RNA_DisplaceModifier; @@ -506,6 +507,7 @@ extern StructRNA RNA_ShaderNodeMaterial; extern StructRNA RNA_ShaderNodeMath; extern StructRNA RNA_ShaderNodeMixRGB; extern StructRNA RNA_ShaderNodeNormal; +extern StructRNA RNA_ShaderNodeGamma; extern StructRNA RNA_ShaderNodeOutput; extern StructRNA RNA_ShaderNodeScript; extern StructRNA RNA_ShaderNodeRGB; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 3d4ed0d6f51..4d836601ac4 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -184,6 +184,14 @@ extern EnumPropertyItem linestyle_geometry_modifier_type_items[]; extern EnumPropertyItem window_cursor_items[]; +extern EnumPropertyItem DT_method_vertex_items[]; +extern EnumPropertyItem DT_method_edge_items[]; +extern EnumPropertyItem DT_method_loop_items[]; +extern EnumPropertyItem DT_method_poly_items[]; +extern EnumPropertyItem DT_mix_mode_items[]; +extern EnumPropertyItem DT_layers_select_src_items[]; +extern EnumPropertyItem DT_layers_select_dst_items[]; + struct bContext; struct PointerRNA; struct PropertyRNA; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 83f3870c29a..a9c0f591858 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -147,7 +147,7 @@ typedef enum PropertySubType { } PropertySubType; /* Make sure enums are updated with these */ -/* HIGHEST FLAG IN USE: 1 << 30 */ +/* HIGHEST FLAG IN USE: 1 << 31 */ typedef enum PropertyFlag { /* editable means the property is editable in the user * interface, properties are editable by default except @@ -165,6 +165,10 @@ typedef enum PropertyFlag { * and collections */ PROP_ANIMATABLE = (1 << 1), + /* This flag means when the property's widget is in 'textedit' mode, it will be updated after every typed char, + * instead of waiting final validation. Used e.g. for text searchbox. */ + PROP_TEXTEDIT_UPDATE = (1 << 31), + /* icon */ PROP_ICONS_CONSECUTIVE = (1 << 12), diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 40d752a3ed2..0c1701f6089 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -35,7 +35,6 @@ #include "BLI_utildefines.h" -#include "RNA_access.h" #include "RNA_define.h" #include "RNA_types.h" @@ -47,6 +46,14 @@ # endif #endif +/* stub for BLI_abort() */ +#ifndef NDEBUG +void BLI_system_backtrace(FILE *fp) +{ + (void)fp; +} +#endif + /* Replace if different */ #define TMP_EXT ".tmp" @@ -1621,7 +1628,7 @@ static void rna_def_property_funcs_header(FILE *f, StructRNA *srna, PropertyDefR EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop; int i; - if (eprop->item) { + if (eprop->item && eprop->totitem) { fprintf(f, "enum {\n"); for (i = 0; i < eprop->totitem; i++) @@ -3676,7 +3683,7 @@ static const char *cpp_classes = "" " int length;\n" "\n" " DynamicArray() : data(NULL), length(0) {}\n" -" DynamicArray(int new_length) : data(NULL), length(new_length) { data = (float *)malloc(sizeof(T) * new_length); }\n" +" DynamicArray(int new_length) : data(NULL), length(new_length) { data = (T *)malloc(sizeof(T) * new_length); }\n" " DynamicArray(const DynamicArray<T>& other) { copy_from(other); }\n" " const DynamicArray<T>& operator = (const DynamicArray<T>& other) { copy_from(other); return *this; }\n" "\n" @@ -3687,7 +3694,7 @@ static const char *cpp_classes = "" "protected:\n" " void copy_from(const DynamicArray<T>& other) {\n" " if (data) free(data);\n" -" data = (float *)malloc(sizeof(T) * other.length);\n" +" data = (T *)malloc(sizeof(T) * other.length);\n" " memcpy(data, other.data, sizeof(T) * other.length);\n" " length = other.length;\n" " }\n" diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 51d81295f8c..009e3799c49 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -64,6 +64,7 @@ EnumPropertyItem id_type_items[] = { {ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""}, {ID_MB, "META", ICON_META_DATA, "MetaBall", ""}, {ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""}, + {ID_MC, "MOVIECLIP", ICON_CLIP, "MovieClip", ""}, {ID_NT, "NODETREE", ICON_NODETREE, "NodeTree", ""}, {ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""}, {ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""}, @@ -71,12 +72,12 @@ EnumPropertyItem id_type_items[] = { {ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""}, {ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""}, {ID_SCR, "SCREEN", ICON_SPLITSCREEN, "Screen", ""}, + {ID_SO, "SOUND", ICON_PLAY_AUDIO, "Sound", ""}, {ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""}, - {ID_SO, "SOUND", ICON_PLAY_AUDIO, "Sound", ""}, {ID_TXT, "TEXT", ICON_TEXT, "Text", ""}, {ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""}, - {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""}, {ID_WM, "WINDOWMANAGER", ICON_FULLSCREEN, "Window Manager", ""}, + {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""}, {0, NULL, 0, NULL, NULL} }; @@ -141,23 +142,23 @@ short RNA_type_to_ID_code(StructRNA *type) if (RNA_struct_is_a(type, &RNA_Lattice)) return ID_LT; if (RNA_struct_is_a(type, &RNA_Material)) return ID_MA; if (RNA_struct_is_a(type, &RNA_MetaBall)) return ID_MB; - if (RNA_struct_is_a(type, &RNA_NodeTree)) return ID_NT; + if (RNA_struct_is_a(type, &RNA_MovieClip)) return ID_MC; if (RNA_struct_is_a(type, &RNA_Mesh)) return ID_ME; + if (RNA_struct_is_a(type, &RNA_Mask)) return ID_MSK; + if (RNA_struct_is_a(type, &RNA_NodeTree)) return ID_NT; if (RNA_struct_is_a(type, &RNA_Object)) return ID_OB; if (RNA_struct_is_a(type, &RNA_ParticleSettings)) return ID_PA; + if (RNA_struct_is_a(type, &RNA_Palette)) return ID_PAL; + if (RNA_struct_is_a(type, &RNA_PaintCurve)) return ID_PC; if (RNA_struct_is_a(type, &RNA_Scene)) return ID_SCE; if (RNA_struct_is_a(type, &RNA_Screen)) return ID_SCR; - if (RNA_struct_is_a(type, &RNA_Speaker)) return ID_SPK; if (RNA_struct_is_a(type, &RNA_Sound)) return ID_SO; - if (RNA_struct_is_a(type, &RNA_Text)) return ID_TXT; + if (RNA_struct_is_a(type, &RNA_Speaker)) return ID_SPK; if (RNA_struct_is_a(type, &RNA_Texture)) return ID_TE; + if (RNA_struct_is_a(type, &RNA_Text)) return ID_TXT; if (RNA_struct_is_a(type, &RNA_VectorFont)) return ID_VF; if (RNA_struct_is_a(type, &RNA_World)) return ID_WO; if (RNA_struct_is_a(type, &RNA_WindowManager)) return ID_WM; - if (RNA_struct_is_a(type, &RNA_MovieClip)) return ID_MC; - if (RNA_struct_is_a(type, &RNA_Mask)) return ID_MSK; - if (RNA_struct_is_a(type, &RNA_Palette)) return ID_PAL; - if (RNA_struct_is_a(type, &RNA_PaintCurve)) return ID_PC; return 0; } @@ -180,23 +181,23 @@ StructRNA *ID_code_to_RNA_type(short idcode) case ID_LT: return &RNA_Lattice; case ID_MA: return &RNA_Material; case ID_MB: return &RNA_MetaBall; - case ID_NT: return &RNA_NodeTree; + case ID_MC: return &RNA_MovieClip; case ID_ME: return &RNA_Mesh; + case ID_MSK: return &RNA_Mask; + case ID_NT: return &RNA_NodeTree; case ID_OB: return &RNA_Object; case ID_PA: return &RNA_ParticleSettings; + case ID_PAL: return &RNA_Palette; + case ID_PC: return &RNA_PaintCurve; case ID_SCE: return &RNA_Scene; case ID_SCR: return &RNA_Screen; - case ID_SPK: return &RNA_Speaker; case ID_SO: return &RNA_Sound; - case ID_TXT: return &RNA_Text; + case ID_SPK: return &RNA_Speaker; case ID_TE: return &RNA_Texture; + case ID_TXT: return &RNA_Text; case ID_VF: return &RNA_VectorFont; - case ID_WO: return &RNA_World; case ID_WM: return &RNA_WindowManager; - case ID_MC: return &RNA_MovieClip; - case ID_MSK: return &RNA_Mask; - case ID_PAL: return &RNA_Palette; - case ID_PC: return &RNA_PaintCurve; + case ID_WO: return &RNA_World; default: return &RNA_ID; } diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index e681552103b..09b970fe7fd 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -466,7 +466,7 @@ static const char *rna_ensure_property_identifier(const PropertyRNA *prop) if (prop->magic == RNA_MAGIC) return prop->identifier; else - return ((IDProperty *)prop)->name; + return ((const IDProperty *)prop)->name; } static const char *rna_ensure_property_description(PropertyRNA *prop) @@ -499,7 +499,7 @@ static const char *rna_ensure_property_name(const PropertyRNA *prop) if (prop->magic == RNA_MAGIC) name = prop->name; else - name = ((IDProperty *)prop)->name; + name = ((const IDProperty *)prop)->name; return name; } @@ -4284,7 +4284,7 @@ char *RNA_path_append(const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *pr /* add .identifier */ if (path) { - BLI_dynstr_append(dynstr, (char *)path); + BLI_dynstr_append(dynstr, path); if (*path) BLI_dynstr_append(dynstr, "."); } diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 8d7a05896a3..e256d145016 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -462,6 +462,12 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Display Speaker", "Include visualization of speaker related animation data"); RNA_def_property_ui_icon(prop, ICON_SPEAKER, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + + prop = RNA_def_property(srna, "show_gpencil", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOGPENCIL); + RNA_def_property_ui_text(prop, "Display Grease Pencil", "Include visualization of Grease Pencil related animation data and frames"); + RNA_def_property_ui_icon(prop, ICON_GREASEPENCIL, 0); + RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); } static void rna_def_action_group(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 0114ffa35c0..6792dd7e5f8 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -55,16 +55,16 @@ static EnumPropertyItem actuator_type_items[] = { {ACT_2DFILTER, "FILTER_2D", 0, "Filter 2D", ""}, {ACT_GAME, "GAME", 0, "Game", ""}, {ACT_MESSAGE, "MESSAGE", 0, "Message", ""}, - {ACT_MOUSE, "MOUSE", 0, "Mouse", ""}, {ACT_OBJECT, "MOTION", 0, "Motion", ""}, + {ACT_MOUSE, "MOUSE", 0, "Mouse", ""}, {ACT_PARENT, "PARENT", 0, "Parent", ""}, {ACT_PROPERTY, "PROPERTY", 0, "Property", ""}, {ACT_RANDOM, "RANDOM", 0, "Random", ""}, {ACT_SCENE, "SCENE", 0, "Scene", ""}, {ACT_SOUND, "SOUND", 0, "Sound", ""}, {ACT_STATE, "STATE", 0, "State", ""}, - {ACT_VISIBILITY, "VISIBILITY", 0, "Visibility", ""}, {ACT_STEERING, "STEERING", 0, "Steering", ""}, + {ACT_VISIBILITY, "VISIBILITY", 0, "Visibility", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index bbc2e0572fa..81ba3a9066f 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -194,14 +194,20 @@ static int rna_SculptToolCapabilities_has_random_texture_angle_get(PointerRNA *p SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); } -static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr) +static int rna_TextureCapabilities_has_random_texture_angle_get(PointerRNA *ptr) { - Brush *br = (Brush *)ptr->data; - return (ELEM(br->mtex.brush_map_mode, + MTex *mtex = (MTex *)ptr->data; + return ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_AREA, - MTEX_MAP_MODE_RANDOM) && - !(br->flag & BRUSH_ANCHORED)); + MTEX_MAP_MODE_RANDOM); +} + + +static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr) +{ + Brush *br = (Brush *)ptr->data; + return !(br->flag & BRUSH_ANCHORED); } static int rna_SculptToolCapabilities_has_sculpt_plane_get(PointerRNA *ptr) @@ -270,15 +276,10 @@ static int rna_SculptToolCapabilities_has_strength_pressure_get(PointerRNA *ptr) return !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK); } -static int rna_BrushCapabilities_has_texture_angle_get(PointerRNA *ptr) +static int rna_TextureCapabilities_has_texture_angle_get(PointerRNA *ptr) { - Brush *br = (Brush *)ptr->data; - return ELEM(br->mtex.brush_map_mode, - MTEX_MAP_MODE_VIEW, - MTEX_MAP_MODE_AREA, - MTEX_MAP_MODE_TILED, - MTEX_MAP_MODE_STENCIL, - MTEX_MAP_MODE_RANDOM); + MTex *mtex = (MTex *)ptr->data; + return mtex->brush_map_mode != MTEX_MAP_MODE_3D; } static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr) @@ -287,10 +288,10 @@ static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr) return !ELEM(br->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH); } -static int rna_BrushCapabilities_has_texture_angle_source_get(PointerRNA *ptr) +static int rna_TextureCapabilities_has_texture_angle_source_get(PointerRNA *ptr) { - Brush *br = (Brush *)ptr->data; - return ELEM(br->mtex.brush_map_mode, + MTex *mtex = (MTex *)ptr->data; + return ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_AREA, MTEX_MAP_MODE_RANDOM); @@ -627,6 +628,15 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; +#define TEXTURE_CAPABILITY(prop_name_, ui_name_) \ + prop = RNA_def_property(srna, #prop_name_, \ + PROP_BOOLEAN, PROP_NONE); \ + RNA_def_property_clear_flag(prop, PROP_EDITABLE); \ + RNA_def_property_boolean_funcs(prop, "rna_TextureCapabilities_" \ + #prop_name_ "_get", NULL); \ + RNA_def_property_ui_text(prop, ui_name_, NULL) + + srna = RNA_def_struct(brna, "BrushTextureSlot", "TextureSlot"); RNA_def_struct_sdna(srna, "MTex"); RNA_def_struct_ui_text(srna, "Brush Texture Slot", "Texture slot for textures in a Brush datablock"); @@ -654,6 +664,25 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna) RNA_def_property_enum_items(prop, prop_mask_paint_map_mode_items); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update"); + + prop = RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RAKE); + RNA_def_property_ui_text(prop, "Rake", ""); + RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update"); + + prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RANDOM); + RNA_def_property_ui_text(prop, "Random", ""); + RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update"); + + prop = RNA_def_property(srna, "random_angle", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_range(prop, 0, M_PI * 2); + RNA_def_property_ui_text(prop, "Random Angle", "Brush texture random angle"); + RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update"); + + TEXTURE_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source"); + TEXTURE_CAPABILITY(has_random_texture_angle, "Has Random Texture Angle"); + TEXTURE_CAPABILITY(has_texture_angle, "Has Texture Angle Source"); } static void rna_def_sculpt_capabilities(BlenderRNA *brna) @@ -717,8 +746,6 @@ static void rna_def_brush_capabilities(BlenderRNA *brna) BRUSH_CAPABILITY(has_overlay, "Has Overlay"); BRUSH_CAPABILITY(has_random_texture_angle, "Has Random Texture Angle"); - BRUSH_CAPABILITY(has_texture_angle, "Has Texture Angle"); - BRUSH_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source"); BRUSH_CAPABILITY(has_spacing, "Has Spacing"); BRUSH_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke"); @@ -786,19 +813,6 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static EnumPropertyItem texture_angle_source_items[] = { - {0, "USER", 0, "User", "Rotate the brush texture by given angle"}, - {BRUSH_RAKE, "RAKE", 0, "Rake", "Rotate the brush texture to match the stroke direction"}, - {BRUSH_RANDOM_ROTATION, "RANDOM", 0, "Random", "Rotate the brush texture at random"}, - {0, NULL, 0, NULL, NULL} - }; - - static EnumPropertyItem texture_angle_source_no_random_items[] = { - {0, "USER", 0, "User", "Rotate the brush texture by given angle"}, - {BRUSH_RAKE, "RAKE", 0, "Rake", "Rotate the brush texture to match the stroke direction"}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem brush_sculpt_plane_items[] = { {SCULPT_DISP_DIR_AREA, "AREA", 0, "Area Plane", ""}, {SCULPT_DISP_DIR_VIEW, "VIEW", 0, "View Plane", ""}, @@ -881,18 +895,6 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stroke Method", ""); RNA_def_property_update(prop, 0, "rna_Brush_stroke_update"); - prop = RNA_def_property(srna, "texture_angle_source_random", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); - RNA_def_property_enum_items(prop, texture_angle_source_items); - RNA_def_property_ui_text(prop, "Texture Angle Source", ""); - RNA_def_property_update(prop, 0, "rna_Brush_update"); - - prop = RNA_def_property(srna, "texture_angle_source_no_random", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); - RNA_def_property_enum_items(prop, texture_angle_source_no_random_items); - RNA_def_property_ui_text(prop, "Texture Angle Source", ""); - RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "sculpt_plane", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, brush_sculpt_plane_items); RNA_def_property_ui_text(prop, "Sculpt Plane", ""); @@ -1158,22 +1160,12 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Inverse Smooth Pressure", "Lighter pressure causes more smoothing to be applied"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RAKE); - RNA_def_property_ui_text(prop, "Rake", "Rotate the brush texture to match the stroke direction"); - RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_relative_jitter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BRUSH_ABSOLUTE_JITTER); RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true); RNA_def_property_ui_text(prop, "Absolute Jitter", "Jittering happens in screen space, not relative to brush size"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_random_rotation", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RANDOM_ROTATION); - RNA_def_property_ui_text(prop, "Random Rotation", "Rotate the brush texture at random"); - RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_plane_trim", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PLANE_TRIM); RNA_def_property_ui_text(prop, "Use Plane Trim", "Enable Plane Trim"); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index fa2a3258d1a..37201eca5f6 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -614,6 +614,10 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain) IMB_free_anim(seq->anim); seq->anim = NULL; } + if (seq->strip->proxy && seq->strip->proxy->anim) { + IMB_free_anim(seq->strip->proxy->anim); + seq->strip->proxy->anim = NULL; + } BKE_sequence_invalidate_cache(scene, seq); BKE_sequencer_preprocessed_cache_cleanup_sequence(seq); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 77355dbad0e..b6845b1df2e 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1388,7 +1388,7 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna) prop = RNA_def_property(srna, "bulge_smooth", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0, 1.0f); - RNA_def_property_ui_text(prop, "Volume Variation Smoothness", ""); + RNA_def_property_ui_text(prop, "Volume Variation Smoothness", "Strength of volume stretching clamping"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } @@ -2272,8 +2272,10 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) {CONSTRAINT_SPLINEIK_XZS_NONE, "NONE", 0, "None", "Don't scale the X and Z axes (Default)"}, {CONSTRAINT_SPLINEIK_XZS_ORIGINAL, "BONE_ORIGINAL", 0, "Bone Original", "Use the original scaling of the bones"}, + {CONSTRAINT_SPLINEIK_XZS_INVERSE, "INVERSE_PRESERVE", 0, "Inverse Scale", + "Scale of the X and Z axes is the inverse of the Y-Scale"}, {CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC, "VOLUME_PRESERVE", 0, "Volume Preservation", - "Scale of the X and Z axes is the inverse of the Y-Scale"}, + "Scale of the X and Z axes are adjusted to preserve the volume of the bones"}, {0, NULL, 0, NULL, NULL} }; @@ -2333,12 +2335,44 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) "on top of XZ Scale mode"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* xz scaling mode */ prop = RNA_def_property(srna, "xz_scale_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "xzScaleMode"); RNA_def_property_enum_items(prop, splineik_xz_scale_mode); RNA_def_property_ui_text(prop, "XZ Scale Mode", "Method used for determining the scaling of the X and Z axes of the bones"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + /* volume presevation for "volumetric" scale mode */ + prop = RNA_def_property(srna, "bulge", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.f); + RNA_def_property_ui_text(prop, "Volume Variation", "Factor between volume variation and stretching"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "use_bulge_min", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_USE_BULGE_MIN); + RNA_def_property_ui_text(prop, "Use Volume Variation Minimum", "Use lower limit for volume variation"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "use_bulge_max", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_USE_BULGE_MAX); + RNA_def_property_ui_text(prop, "Use Volume Variation Maximum", "Use upper limit for volume variation"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "bulge_min", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0f); + RNA_def_property_ui_text(prop, "Volume Variation Minimum", "Minimum volume stretching factor"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "bulge_max", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 1.0, 100.0f); + RNA_def_property_ui_text(prop, "Volume Variation Maximum", "Maximum volume stretching factor"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "bulge_smooth", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0, 1.0f); + RNA_def_property_ui_text(prop, "Volume Variation Smoothness", "Strength of volume stretching clamping"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } static void rna_def_constraint_pivot(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 6668ce812cf..54c08009792 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -639,7 +639,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna) if (srna->flag & STRUCT_RUNTIME) rna_freelinkN(&brna->structs, srna); #else - (void)brna, (void)srna; + UNUSED_VARS(brna, srna); #endif } diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index c4677710676..6b61b37ce5c 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -44,6 +44,8 @@ #ifdef RNA_RUNTIME +#include "BLI_math.h" + #include "WM_api.h" #include "BKE_gpencil.h" @@ -53,6 +55,16 @@ static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } +static char *rna_GPencilLayer_path(PointerRNA *ptr) +{ + bGPDlayer *gpl = (bGPDlayer *)ptr->data; + char name_esc[sizeof(gpl->info) * 2]; + + BLI_strescape(name_esc, gpl->info, sizeof(name_esc)); + + return BLI_sprintfN("layers[\"%s\"]", name_esc); +} + static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr) { bGPDlayer *gpl = (bGPDlayer *)ptr->data; @@ -64,9 +76,54 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr) return 1; } -static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr) +static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *max, + int *softmin, int *softmax) { + bGPDlayer *gpl = ptr->data; + + /* The restrictions on max width here are due to OpenGL on Windows not supporting + * any widths greater than 10 (for driver-drawn) strokes/points. + * + * Although most of our 2D strokes also don't suffer from this restriction, + * it's relatively hard to test for that. So, for now, only volumetric strokes + * get to be larger... + */ + if (gpl->flag & GP_LAYER_VOLUMETRIC) { + *min = 1; + *max = 300; + + *softmin = 1; + *softmax = 100; + } + else { + *min = 1; + *max = 10; + + *softmin = 1; + *softmax = 10; + } +} +static int rna_GPencilLayer_is_stroke_visible_get(PointerRNA *ptr) +{ + /* see drawgpencil.c -> gp_draw_data_layers() for more details + * about this limit for showing/not showing + */ + bGPDlayer *gpl = (bGPDlayer *)ptr->data; + return (gpl->color[3] > 0.001f); +} + +static int rna_GPencilLayer_is_fill_visible_get(PointerRNA *ptr) +{ + /* see drawgpencil.c -> gp_draw_data_layers() for more details + * about this limit for showing/not showing + */ + bGPDlayer *gpl = (bGPDlayer *)ptr->data; + return (gpl->fill[3] > 0.001f); +} + +static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr) +{ bGPdata *gpd = ptr->id.data; if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */ @@ -106,6 +163,33 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value) } } +static int rna_GPencil_active_layer_index_get(PointerRNA *ptr) +{ + bGPdata *gpd = (bGPdata *)ptr->id.data; + bGPDlayer *gpl = gpencil_layer_getactive(gpd); + + return BLI_findindex(&gpd->layers, gpl); +} + +static void rna_GPencil_active_layer_index_set(PointerRNA *ptr, int value) +{ + bGPdata *gpd = (bGPdata *)ptr->id.data; + bGPDlayer *gpl = BLI_findlink(&gpd->layers, value); + + gpencil_layer_setactive(gpd, gpl); +} + +static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +{ + bGPdata *gpd = (bGPdata *)ptr->id.data; + + *min = 0; + *max = max_ii(0, BLI_listbase_count(&gpd->layers) - 1); + + *softmin = *min; + *softmax = *max; +} + static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value) { bGPdata *gpd = ptr->id.data; @@ -117,6 +201,63 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value) BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); } + +static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd, const bGPDspoint *pt, bGPDlayer **r_gpl, bGPDframe **r_gpf) +{ + bGPDlayer *gpl; + bGPDstroke *gps; + + /* sanity checks */ + if (ELEM(NULL, gpd, pt)) { + return NULL; + } + + if (r_gpl) *r_gpl = NULL; + if (r_gpf) *r_gpf = NULL; + + /* there's no faster alternative than just looping over everything... */ + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->actframe) { + for (gps = gpl->actframe->strokes.first; gps; gps = gps->next) { + if ((pt >= gps->points) && (pt < &gps->points[gps->totpoints])) { + /* found it */ + if (r_gpl) *r_gpl = gpl; + if (r_gpf) *r_gpf = gpl->actframe; + + return gps; + } + } + } + } + + /* didn't find it */ + return NULL; +} + +static void rna_GPencil_stroke_point_select_set(PointerRNA *ptr, const int value) +{ + bGPdata *gpd = ptr->id.data; + bGPDspoint *pt = ptr->data; + bGPDstroke *gps = NULL; + + /* Ensure that corresponding stroke is set + * - Since we don't have direct access, we're going to have to search + * - We don't apply selection value unless we can find the corresponding + * stroke, so that they don't get out of sync + */ + gps = rna_GPencil_stroke_point_find_stroke(gpd, pt, NULL, NULL); + if (gps) { + /* Set the new selection state for the point */ + if (value) + pt->flag |= GP_SPOINT_SELECT; + else + pt->flag &= ~GP_SPOINT_SELECT; + + /* Check if the stroke should be selected or not... */ + gpencil_stroke_sync_selection(gps); + } +} + static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count) { if (count > 0) { @@ -180,6 +321,27 @@ static void rna_GPencil_stroke_remove(bGPDframe *frame, ReportList *reports, Poi WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } +static void rna_GPencil_stroke_select_set(PointerRNA *ptr, const int value) +{ + bGPDstroke *gps = ptr->data; + bGPDspoint *pt; + int i; + + /* set new value */ + if (value) + gps->flag |= GP_STROKE_SELECT; + else + gps->flag &= ~GP_STROKE_SELECT; + + /* ensure that the stroke's points are selected in the same way */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (value) + pt->flag |= GP_SPOINT_SELECT; + else + pt->flag &= ~GP_SPOINT_SELECT; + } +} + static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, ReportList *reports, int frame_number) { bGPDframe *frame; @@ -291,6 +453,12 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT); + RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set"); + RNA_def_property_ui_text(prop, "Select", "Point is selected for viewport editing"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); } static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop) @@ -338,12 +506,19 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna) RNA_def_property_struct_type(prop, "GPencilStrokePoint"); RNA_def_property_ui_text(prop, "Stroke Points", "Stroke data points"); rna_def_gpencil_stroke_points_api(brna, prop); - + + /* Settings */ prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, stroke_draw_mode_items); RNA_def_property_ui_text(prop, "Draw Mode", ""); RNA_def_property_update(prop, 0, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_SELECT); + RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_select_set"); + RNA_def_property_ui_text(prop, "Select", "Stroke is selected for viewport editing"); + RNA_def_property_update(prop, 0, "rna_GPencil_update"); } static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop) @@ -455,6 +630,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) srna = RNA_def_struct(brna, "GPencilLayer", NULL); RNA_def_struct_sdna(srna, "bGPDlayer"); RNA_def_struct_ui_text(srna, "Grease Pencil Layer", "Collection of related sketches"); + RNA_def_struct_path_func(srna, "rna_GPencilLayer_path"); /* Name */ prop = RNA_def_property(srna, "info", PROP_STRING, PROP_NONE); @@ -477,7 +653,14 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_editable_func(prop, "rna_GPencilLayer_active_frame_editable"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - /* Drawing Color */ + /* Draw Style */ + // TODO: replace these with a "draw type" combo (i.e. strokes only, filled strokes, strokes + fills, volumetric)? + prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_VOLUMETRIC); + RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in a volumetric effect"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + /* Stroke Drawing Color */ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -486,14 +669,29 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "color[3]"); - RNA_def_property_range(prop, 0.3, 1.0f); + RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Fill Drawing Color */ + prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "fill"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "fill[3]"); + RNA_def_property_range(prop, 0.0, 1.0f); + RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Line Thickness */ prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "thickness"); - RNA_def_property_range(prop, 1, 10); + //RNA_def_property_range(prop, 1, 10); /* 10 px limit comes from Windows OpenGL limits for natively-drawn strokes */ + RNA_def_property_int_funcs(prop, NULL, NULL, "rna_GPencilLayer_line_width_range"); RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); @@ -503,29 +701,59 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - prop = RNA_def_property(srna, "ghost_range_max", PROP_INT, PROP_NONE); + prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "gstep"); RNA_def_property_range(prop, 0, 120); - RNA_def_property_ui_text(prop, "Max Ghost Range", - "Maximum number of frames on either side of the active frame to show " - "(0 = show the 'first' available sketch on either side)"); + RNA_def_property_ui_text(prop, "Frames Before", + "Maximum number of frames to show before current frame " + "(0 = show only the previous sketch)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "gstep_next"); + RNA_def_property_range(prop, 0, 120); + RNA_def_property_ui_text(prop, "Frames After", + "Maximum number of frames to show after current frame " + "(0 = show only the next sketch)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL); + RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "gcolor_prev"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "gcolor_next"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Flags */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1); RNA_def_property_ui_text(prop, "Hide", "Set layer Visibility"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_LOCKED); + RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1); RNA_def_property_ui_text(prop, "Locked", "Protect layer from further editing and/or frame changes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "lock_frame", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_FRAMELOCK); + RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1); RNA_def_property_ui_text(prop, "Frame Locked", "Lock current frame displayed by layer"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* expose as layers.active */ #if 0 @@ -539,7 +767,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SELECT); RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* XXX keep this option? */ prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE); @@ -554,6 +782,17 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Read-only state props (for simpler UI code) */ + prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_stroke_visible_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible"); + + prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_GPencilLayer_is_fill_visible_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible"); + /* Layers API */ func = RNA_def_function(srna, "clear", "rna_GPencil_layer_clear"); RNA_def_function_ui_description(func, "Remove all the grease pencil layer data"); @@ -592,6 +831,14 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active Layer", "Active grease pencil layer"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + + RNA_def_property_int_funcs(prop, + "rna_GPencil_active_layer_index_get", + "rna_GPencil_active_layer_index_set", + "rna_GPencil_active_layer_index_range"); + RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer"); } static void rna_def_gpencil_data(BlenderRNA *brna) @@ -620,6 +867,9 @@ static void rna_def_gpencil_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Layers", ""); rna_def_gpencil_layers_api(brna, prop); + /* Animation Data */ + rna_def_animdata_common(srna); + /* Flags */ prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); @@ -631,7 +881,13 @@ static void rna_def_gpencil_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_DEPTH_STROKE_ENDPOINTS); RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - + + prop = RNA_def_property(srna, "use_stroke_edit_mode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_EDITMODE); + RNA_def_property_ui_text(prop, "Stroke Edit Mode", "Enable alternative keymap to make editing stroke points easier"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_update"); + + /* API Functions */ func = RNA_def_function(srna, "clear", "rna_GPencil_clear"); RNA_def_function_ui_description(func, "Remove all the grease pencil data"); } diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 141de511a09..b1935b34251 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -292,11 +292,21 @@ static int rna_Image_depth_get(PointerRNA *ptr) static int rna_Image_frame_duration_get(PointerRNA *ptr) { - Image *im = (Image *)ptr->data; + Image *ima = ptr->id.data; + int duration = 1; + + if (!ima->anim) { + /* acquire ensures ima->anim is set, if possible! */ + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + BKE_image_release_ibuf(ima, ibuf, lock); + } + + if (ima->anim) { + duration = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN); + } - if (im->anim) - return IMB_anim_get_duration(im->anim, IMB_TC_RECORD_RUN); - return 1; + return duration; } static int rna_Image_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) @@ -665,7 +675,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - prop = RNA_def_property(srna, "generated_color", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "generated_color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "gen_color"); RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Color", "Fill color for the generated image"); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index d9a59c4dc55..90f90ea8632 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -74,7 +74,7 @@ static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports } if (scene) { - ImageUser iuser; + ImageUser iuser = {0}; void *lock; iuser.scene = scene; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 2b1df7a713e..2c00b70d1a9 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -288,6 +288,7 @@ void RNA_api_ui_layout(struct StructRNA *srna); void RNA_api_window(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); void RNA_api_space_node(struct StructRNA *srna); +void RNA_api_space_text(struct StructRNA *srna); void RNA_api_region_view3d(struct StructRNA *srna); void RNA_api_sensor(struct StructRNA *srna); void RNA_api_controller(struct StructRNA *srna); diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index 7d10511d1c4..8a3626de81d 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -675,13 +675,6 @@ static void rna_def_key(BlenderRNA *brna) RNA_def_property_range(prop, MINFRAME, MAXFRAME); RNA_def_property_ui_text(prop, "Evaluation Time", "Evaluation time for absolute shape keys"); RNA_def_property_update(prop, 0, "rna_Key_update_data"); - - prop = RNA_def_property(srna, "slurph", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "slurph"); - RNA_def_property_range(prop, -500, 500); - RNA_def_property_ui_text(prop, "Slurph", - "Create a delay (in frames) in applying key positions, first vertex goes first"); - RNA_def_property_update(prop, 0, "rna_Key_update_data"); } void RNA_def_key(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index b0b99dcd2ca..3d6eab2bc88 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1415,8 +1415,6 @@ static char *rna_FaceCustomData_data_path(PointerRNA *ptr, const char *collectio } - - static char *rna_MeshUVLoop_path(PointerRNA *ptr) { return rna_LoopCustomData_data_path(ptr, "uv_layers", CD_MLOOPUV); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 5c63b95eaaf..d8d27a06bb5 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -43,10 +43,15 @@ #include "BLF_translation.h" #include "BKE_animsys.h" +#include "BKE_data_transfer.h" +#include "BKE_DerivedMesh.h" #include "BKE_dynamicpaint.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" #include "BKE_multires.h" #include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */ +#include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -57,6 +62,7 @@ EnumPropertyItem modifier_type_items[] = { {0, "", 0, N_("Modify"), ""}, + {eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""}, {eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""}, {eModifierType_PointCache, "POINT_CACHE", ICON_MOD_MESHDEFORM, "Point Cache", ""}, {eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""}, @@ -128,9 +134,114 @@ EnumPropertyItem modifier_triangulate_ngon_method_items[] = { {0, NULL, 0, NULL, NULL} }; +/* ***** Data Transfer ***** */ + +EnumPropertyItem DT_method_vertex_items[] = { + {MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology", + "Copy from identical topology meshes"}, + {MREMAP_MODE_VERT_NEAREST, "NEAREST", 0, "Nearest vertex", + "Copy from closest vertex"}, + {MREMAP_MODE_VERT_EDGE_NEAREST, "EDGE_NEAREST", 0, "Nearest Edge Vertex", + "Copy from closest vertex of closest edge"}, + {MREMAP_MODE_VERT_EDGEINTERP_NEAREST, "EDGEINTERP_NEAREST", 0, "Nearest Edge Interpolated", + "Copy from interpolated values of vertices from closest point on closest edge"}, + {MREMAP_MODE_VERT_POLY_NEAREST, "POLY_NEAREST", 0, "Nearest Face Vertex", + "Copy from closest vertex of closest face"}, + {MREMAP_MODE_VERT_POLYINTERP_NEAREST, "POLYINTERP_NEAREST", 0, "Nearest Face Interpolated", + "Copy from interpolated values of vertices from closest point on closest face"}, + {MREMAP_MODE_VERT_POLYINTERP_VNORPROJ, "POLYINTERP_VNORPROJ", 0, "Projected Face Interpolated", + "Copy from interpolated values of vertices from point on closest face hit by normal-projection"}, + {0, NULL, 0, NULL, NULL} +}; + +EnumPropertyItem DT_method_edge_items[] = { + {MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology", + "Copy from identical topology meshes"}, + {MREMAP_MODE_EDGE_VERT_NEAREST, "VERT_NEAREST", 0, "Nearest Vertices", + "Copy from most similar edge (edge which vertices are the closest of destination edge’s ones)"}, + {MREMAP_MODE_EDGE_NEAREST, "NEAREST", 0, "Nearest Edge", + "Copy from closest edge (using midpoints)"}, + {MREMAP_MODE_EDGE_POLY_NEAREST, "POLY_NEAREST", 0, "Nearest Face Edge", + "Copy from closest edge of closest face (using midpoints)"}, + {MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ, "EDGEINTERP_VNORPROJ", 0, "Projected Edge Interpolated", + "Interpolate all source edges hit by the projection of destination one along its own normal (from vertices)"}, + {0, NULL, 0, NULL, NULL} +}; + +EnumPropertyItem DT_method_loop_items[] = { + {MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology", + "Copy from identical topology meshes"}, + {MREMAP_MODE_LOOP_NEAREST_LOOPNOR, "NEAREST_NORMAL", 0, "Nearest Corner And Best Matching Normal", + "Copy from nearest corner which has the best matching normal"}, + {MREMAP_MODE_LOOP_NEAREST_POLYNOR, "NEAREST_POLYNOR", 0, "Nearest Corner And Best Matching Face Normal", + "Copy from nearest corner which has the face with the best matching normal to destination corner's face one"}, + {MREMAP_MODE_LOOP_POLY_NEAREST, "NEAREST_POLY", 0, "Nearest Corner Of Nearest Face", + "Copy from nearest corner of nearest polygon"}, + {MREMAP_MODE_LOOP_POLYINTERP_NEAREST, "POLYINTERP_NEAREST", 0, "Nearest Face Interpolated", + "Copy from interpolated corners of the nearest source polygon"}, + {MREMAP_MODE_LOOP_POLYINTERP_LNORPROJ, "POLYINTERP_LNORPROJ", 0, "Projected Face Interpolated", + "Copy from interpolated corners of the source polygon hit by corner normal projection"}, + {0, NULL, 0, NULL, NULL} +}; + +EnumPropertyItem DT_method_poly_items[] = { + {MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology", + "Copy from identical topology meshes"}, + {MREMAP_MODE_POLY_NEAREST, "NEAREST", 0, "Nearest Face", + "Copy from nearest polygon (using center points)"}, + {MREMAP_MODE_POLY_NOR, "NORMAL", 0, "Best Normal-Matching", + "Copy from source polygon which normal is the closest to destination one"}, + {MREMAP_MODE_POLY_POLYINTERP_PNORPROJ, "POLYINTERP_PNORPROJ", 0, "Projected Face Interpolated", + "Interpolate all source polygons intersected by the projection of destination one along its own normal"}, + {0, NULL, 0, NULL, NULL} +}; + +EnumPropertyItem DT_mix_mode_items[] = { + {CDT_MIX_TRANSFER, "REPLACE", 0, "Replace", + "Overwrite all elements' data"}, + {CDT_MIX_REPLACE_ABOVE_THRESHOLD, "ABOVE_THRESHOLD", 0, "Above Threshold", + "Only replace destination elements where data is above given threshold (exact behavior depends on data type)"}, + {CDT_MIX_REPLACE_BELOW_THRESHOLD, "BELOW_THRESHOLD", 0, "Below Threshold", + "Only replace destination elements where data is below given threshold (exact behavior depends on data type)"}, + {CDT_MIX_MIX, "MIX", 0, "Mix", + "Mix source value into destination one, using given threshold as factor"}, + {CDT_MIX_ADD, "ADD", 0, "Add", + "Add source value to destination one, using given threshold as factor"}, + {CDT_MIX_SUB, "SUB", 0, "Subtract", + "Subtract source value to destination one, using given threshold as factor"}, + {CDT_MIX_MUL, "MUL", 0, "Multiply", + "Multiply source value to destination one, using given threshold as factor"}, + /* etc. etc. */ + {0, NULL, 0, NULL, NULL} +}; + +EnumPropertyItem DT_layers_select_src_items[] = { + {DT_LAYERS_ACTIVE_SRC, "ACTIVE", 0, "Active Layer", + "Only transfer active data layer"}, + {DT_LAYERS_ALL_SRC, "ALL", 0, "All Layers", + "Transfer all data layers"}, + {DT_LAYERS_VGROUP_SRC_BONE_SELECT, "BONE_SELECT", 0, "Selected Pose Bones", + "Transfer all vertex groups used by selected pose bones"}, + {DT_LAYERS_VGROUP_SRC_BONE_DEFORM, "BONE_DEFORM", 0, "Deform Pose Bones", + "Transfer all vertex groups used by deform bones"}, + {0, NULL, 0, NULL, NULL} +}; + +EnumPropertyItem DT_layers_select_dst_items[] = { + {DT_LAYERS_ACTIVE_DST, "ACTIVE", 0, "Active Layer", + "Affect active data layer of all targets"}, + {DT_LAYERS_NAME_DST, "NAME", 0, "By Name", + "Match target data layers to affect by name"}, + {DT_LAYERS_INDEX_DST, "INDEX", 0, "By Order", + "Match target data layers to affect by order (indices)"}, + {0, NULL, 0, NULL, NULL} +}; + + #ifdef RNA_RUNTIME #include "DNA_particle_types.h" +#include "DNA_curve_types.h" #include "DNA_smoke_types.h" #include "BKE_context.h" @@ -245,6 +356,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_LaplacianDeformModifier; case eModifierType_Wireframe: return &RNA_WireframeModifier; + case eModifierType_DataTransfer: + return &RNA_DataTransferModifier; case eModifierType_PointCache: return &RNA_PointCacheModifier; /* Default */ @@ -312,6 +425,7 @@ RNA_MOD_VGROUP_NAME_SET(Armature, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Bevel, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Cast, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Curve, name); +RNA_MOD_VGROUP_NAME_SET(DataTransfer, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Decimate, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Displace, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Hook, name); @@ -402,6 +516,7 @@ RNA_MOD_OBJECT_SET(Array, curve_ob, OB_CURVE); RNA_MOD_OBJECT_SET(Boolean, object, OB_MESH); RNA_MOD_OBJECT_SET(Cast, object, OB_EMPTY); RNA_MOD_OBJECT_SET(Curve, object, OB_CURVE); +RNA_MOD_OBJECT_SET(DataTransfer, ob_source, OB_MESH); RNA_MOD_OBJECT_SET(Lattice, object, OB_LATTICE); RNA_MOD_OBJECT_SET(Mask, ob_arm, OB_ARMATURE); RNA_MOD_OBJECT_SET(MeshDeform, object, OB_MESH); @@ -607,6 +722,299 @@ static int rna_LaplacianDeformModifier_is_bind_get(PointerRNA *ptr) return ((lmd->flag & MOD_LAPLACIANDEFORM_BIND) && (lmd->cache_system != NULL)); } +/* NOTE: Curve and array modifiers requires curve path to be evaluated, + * dependency graph will make sure that curve eval would create such a path, + * but if curve was already evaluated we might miss path. + * + * So what we do here is: if path was not calculated for target curve we + * tag it for update. + */ + +static void rna_CurveModifier_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + CurveModifierData *cmd = (CurveModifierData *)ptr->data; + rna_Modifier_update(bmain, scene, ptr); + DAG_relations_tag_update(bmain); + if (cmd->object != NULL) { + Curve *curve = cmd->object->data; + if ((curve->flag & CU_PATH) == 0) { + DAG_id_tag_update(&curve->id, OB_RECALC_DATA); + } + } +} + +static void rna_ArrayModifier_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + ArrayModifierData *amd = (ArrayModifierData *)ptr->data; + rna_Modifier_update(bmain, scene, ptr); + DAG_relations_tag_update(bmain); + if (amd->curve_ob != NULL) { + Curve *curve = amd->curve_ob->data; + if ((curve->flag & CU_PATH) == 0) { + DAG_id_tag_update(&curve->id, OB_RECALC_DATA); + } + } +} + + +static void rna_DataTransferModifier_use_data_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data; + + if (!(dtmd->flags & MOD_DATATRANSFER_USE_VERT)) { + dtmd->data_types &= ~DT_TYPE_VERT_ALL; + } + if (!(dtmd->flags & MOD_DATATRANSFER_USE_EDGE)) { + dtmd->data_types &= ~DT_TYPE_EDGE_ALL; + } + if (!(dtmd->flags & MOD_DATATRANSFER_USE_LOOP)) { + dtmd->data_types &= ~DT_TYPE_LOOP_ALL; + } + if (!(dtmd->flags & MOD_DATATRANSFER_USE_POLY)) { + dtmd->data_types &= ~DT_TYPE_POLY_ALL; + } + + rna_Modifier_update(bmain, scene, ptr); +} + +static void rna_DataTransferModifier_data_types_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data; + const int item_types = BKE_object_data_transfer_get_dttypes_item_types(dtmd->data_types); + + if (item_types & ME_VERT) { + dtmd->flags |= MOD_DATATRANSFER_USE_VERT; + } + if (item_types & ME_EDGE) { + dtmd->flags |= MOD_DATATRANSFER_USE_EDGE; + } + if (item_types & ME_LOOP) { + dtmd->flags |= MOD_DATATRANSFER_USE_LOOP; + } + if (item_types & ME_POLY) { + dtmd->flags |= MOD_DATATRANSFER_USE_POLY; + } + + rna_Modifier_update(bmain, scene, ptr); +} + +static EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data; + EnumPropertyItem *item = NULL, tmp_item = {0}; + int totitem = 0; + + if (!C) { /* needed for docs and i18n tools */ + return DT_layers_select_src_items; + } + + /* No active here! */ + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ALL_SRC); + + if (STREQ(RNA_property_identifier(prop), "layers_vgroup_select_src")) { + Object *ob_src = dtmd->ob_source; + +#if 0 /* XXX Don't think we want this in modifier version... */ + if (BKE_object_pose_armature_get(ob_src)) { + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM); + } +#endif + + if (ob_src) { + bDeformGroup *dg; + int i; + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = dg->name; + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (STREQ(RNA_property_identifier(prop), "layers_shapekey_select_src")) { + /* TODO */ + } + else if (STREQ(RNA_property_identifier(prop), "layers_uv_select_src")) { + Object *ob_src = dtmd->ob_source; + + if (ob_src) { + DerivedMesh *dm_src; + CustomData *pdata; + int num_data, i; + + /* XXX Is this OK? */ + dm_src = mesh_get_derived_final(dtmd->modifier.scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY); + pdata = dm_src->getPolyDataLayout(dm_src); + num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (STREQ(RNA_property_identifier(prop), "layers_vcol_select_src")) { + Object *ob_src = dtmd->ob_source; + + if (ob_src) { + DerivedMesh *dm_src; + CustomData *ldata; + int num_data, i; + + /* XXX Is this OK? */ + dm_src = mesh_get_derived_final(dtmd->modifier.scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL); + ldata = dm_src->getLoopDataLayout(dm_src); + num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data; + EnumPropertyItem *item = NULL, tmp_item = {0}; + int totitem = 0; + + if (!C) { /* needed for docs and i18n tools */ + return DT_layers_select_dst_items; + } + + /* No active here! */ + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_NAME_DST); + RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_INDEX_DST); + + if (STREQ(RNA_property_identifier(prop), "layers_vgroup_select_dst")) { + /* Only list destination layers if we have a single source! */ + if (dtmd->layers_select_src[DT_MULTILAYER_INDEX_MDEFORMVERT] >= 0) { + Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */ + + if (ob_dst) { + bDeformGroup *dg; + int i; + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0, dg = ob_dst->defbase.first; dg; i++, dg = dg->next) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = dg->name; + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + } + else if (STREQ(RNA_property_identifier(prop), "layers_shapekey_select_dst")) { + /* TODO */ + } + else if (STREQ(RNA_property_identifier(prop), "layers_uv_select_dst")) { + /* Only list destination layers if we have a single source! */ + if (dtmd->layers_select_src[DT_MULTILAYER_INDEX_UV] >= 0) { + Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */ + + if (ob_dst && ob_dst->data) { + Mesh *me_dst; + CustomData *pdata; + int num_data, i; + + me_dst = ob_dst->data; + pdata = &me_dst->pdata; + num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + } + else if (STREQ(RNA_property_identifier(prop), "layers_vcol_select_dst")) { + /* Only list destination layers if we have a single source! */ + if (dtmd->layers_select_src[DT_MULTILAYER_INDEX_VCOL] >= 0) { + Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */ + + if (ob_dst && ob_dst->data) { + Mesh *me_dst; + CustomData *ldata; + int num_data, i; + + me_dst = ob_dst->data; + ldata = &me_dst->ldata; + num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + } + + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static EnumPropertyItem *rna_DataTransferModifier_mix_mode_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data; + EnumPropertyItem *item = NULL; + int totitem = 0; + + bool support_advanced_mixing, support_threshold; + + if (!C) { /* needed for docs and i18n tools */ + return DT_mix_mode_items; + } + + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_TRANSFER); + + BKE_object_data_transfer_get_dttypes_capacity(dtmd->data_types, &support_advanced_mixing, &support_threshold); + + if (support_threshold) { + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD); + } + + if (support_advanced_mixing) { + RNA_enum_item_add_separator(&item, &totitem); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MIX); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_ADD); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_SUB); + RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MUL); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + #else static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[]) @@ -879,7 +1287,7 @@ static void rna_def_modifier_curve(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Object", "Curve object to deform with"); RNA_def_property_pointer_funcs(prop, NULL, "rna_CurveModifier_object_set", NULL, "rna_Curve_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + RNA_def_property_update(prop, 0, "rna_CurveModifier_dependency_update"); prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); @@ -1402,7 +1810,7 @@ static void rna_def_modifier_array(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Curve", "Curve object to fit array length to"); RNA_def_property_pointer_funcs(prop, NULL, "rna_ArrayModifier_curve_ob_set", NULL, "rna_Curve_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + RNA_def_property_update(prop, 0, "rna_ArrayModifier_dependency_update"); /* Offset parameters */ prop = RNA_def_property(srna, "use_constant_offset", PROP_BOOLEAN, PROP_NONE); @@ -2456,7 +2864,7 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "origin", PROP_POINTER, PROP_NONE); - RNA_def_property_ui_text(prop, "Origin", "Origin of modifier space coordinates"); + RNA_def_property_ui_text(prop, "Origin", "Offset the origin and orientation of the deformation"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); @@ -3667,6 +4075,251 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); } +static void rna_def_modifier_datatransfer(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem DT_layer_vert_items[] = { +#if 0 /* XXX When SkinModifier is enabled, it seems to erase its own CD_MVERT_SKIN layer from final DM :( */ + {DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"}, +#endif + {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem DT_layer_vert_vgroup_items[] = { + {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, "Vertex Group(s)", "Transfer active or all vertex groups"}, + {0, NULL, 0, NULL, NULL} + }; +#if 0 /* XXX For now, would like to finish/merge work from 2014 gsoc first. */ + static EnumPropertyItem DT_layer_vert_shapekey_items[] = { + {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"}, + {0, NULL, 0, NULL, NULL} + }; +#endif + + static EnumPropertyItem DT_layer_edge_items[] = { + {DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"}, + {DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"}, + {DT_TYPE_CREASE, "CREASE", 0, "Subsurf Crease", "Transfer crease values"}, + {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"}, + {DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem DT_layer_loop_items[] = { + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem DT_layer_loop_vcol_items[] = { + {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem DT_layer_loop_uv_items[] = { + {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem DT_layer_poly_items[] = { + {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"}, + {DT_TYPE_FREESTYLE_FACE, "FREESTYLE_FACE", 0, "Freestyle Mark", "Transfer Freestyle face mark"}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "DataTransferModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Data Transfer Modifier", "Modifier transferring some data from a source mesh"); + RNA_def_struct_sdna(srna, "DataTransferModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_DATA_TRANSFER); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "ob_source"); + RNA_def_property_ui_text(prop, "Source Object", "Object to transfer data from"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_pointer_funcs(prop, NULL, "rna_DataTransferModifier_ob_source_set", NULL, "rna_Mesh_object_poll"); + RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + prop = RNA_def_boolean(srna, "use_object_transform", true, "Object Transform", + "Evaluate source and destination meshes in their respective object spaces"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_OBSRC_TRANSFORM); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* Generic, UI-only data types toggles. */ + prop = RNA_def_boolean(srna, "use_vert_data", false, "Vertex Data", "Enable vertex data transfer"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_USE_VERT); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_use_data_update"); + + prop = RNA_def_boolean(srna, "use_edge_data", false, "Edge Data", "Enable edge data transfer"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_USE_EDGE); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_use_data_update"); + + prop = RNA_def_boolean(srna, "use_loop_data", false, "Face Corner Data", "Enable face corner data transfer"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_USE_LOOP); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_use_data_update"); + + prop = RNA_def_boolean(srna, "use_poly_data", false, "Face Data", "Enable face data transfer"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_USE_POLY); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_use_data_update"); + + /* Actual data types selection. */ + prop = RNA_def_enum(srna, "data_types_verts", DT_layer_vert_items, 0, "Vertex Data Types", + "Which vertex data layers to transfer"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_sdna(prop, NULL, "data_types"); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update"); + prop = RNA_def_enum(srna, "data_types_verts_vgroup", DT_layer_vert_vgroup_items, 0, "Vertex Data Types", + "Which vertex data layers to transfer"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_sdna(prop, NULL, "data_types"); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update"); + + prop = RNA_def_enum(srna, "data_types_edges", DT_layer_edge_items, 0, "Edge Data Types", + "Which edge data layers to transfer"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_sdna(prop, NULL, "data_types"); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update"); + + prop = RNA_def_enum(srna, "data_types_loops", DT_layer_loop_items, 0, "Face Corner Data Types", + "Which face corner data layers to transfer"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_sdna(prop, NULL, "data_types"); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update"); + prop = RNA_def_enum(srna, "data_types_loops_vcol", DT_layer_loop_vcol_items, 0, "Face Corner Data Types", + "Which face corner data layers to transfer"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_sdna(prop, NULL, "data_types"); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update"); + prop = RNA_def_enum(srna, "data_types_loops_uv", DT_layer_loop_uv_items, 0, "Face Corner Data Types", + "Which face corner data layers to transfer"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_sdna(prop, NULL, "data_types"); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update"); + + prop = RNA_def_enum(srna, "data_types_polys", DT_layer_poly_items, 0, "Poly Data Types", + "Which poly data layers to transfer"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_sdna(prop, NULL, "data_types"); + RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update"); + + /* Mapping methods. */ + prop = RNA_def_enum(srna, "vert_mapping", DT_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping", + "Method used to map source vertices to destination ones"); + RNA_def_property_enum_sdna(prop, NULL, "vmap_mode"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_enum(srna, "edge_mapping", DT_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping", + "Method used to map source edges to destination ones"); + RNA_def_property_enum_sdna(prop, NULL, "emap_mode"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_enum(srna, "loop_mapping", DT_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR, + "Face Corner Mapping", "Method used to map source faces' corners to destination ones"); + RNA_def_property_enum_sdna(prop, NULL, "lmap_mode"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_enum(srna, "poly_mapping", DT_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping", + "Method used to map source faces to destination ones"); + RNA_def_property_enum_sdna(prop, NULL, "pmap_mode"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* Mapping options and filtering. */ + prop = RNA_def_boolean(srna, "use_max_distance", false, "Only Neighbor Geometry", + "Source elements must be closer than given distance from destination one"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_MAP_MAXDIST); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_float(srna, "max_distance", 1.0f, 0.0f, FLT_MAX, "Max Distance", + "Maximum allowed distance between source and destination element, for non-topology mappings", + 0.0f, 100.0f); + RNA_def_property_float_sdna(prop, NULL, "map_max_distance"); + RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_float(srna, "ray_radius", 0.0f, 0.0f, FLT_MAX, "Ray Radius", + "'Width' of rays (especially useful when raycasting against vertices or edges)", 0.0f, 10.0f); + RNA_def_property_float_sdna(prop, NULL, "map_ray_radius"); + RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_float(srna, "islands_precision", 0.0f, 0.0f, 1.0f, "Islands Handling Refinement", + "Factor controlling precision of islands handling " + "(typically, 0.1 should be enough, higher values can make things really slow)", 0.0f, 1.0f); + RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* How to handle multi-layers types of data. */ + prop = RNA_def_enum(srna, "layers_vgroup_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_MDEFORMVERT]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + +#if 0 + prop = RNA_def_enum(srna, "layers_shapekey_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_SHAPEKEY]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +#endif + + prop = RNA_def_enum(srna, "layers_vcol_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_VCOL]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_enum(srna, "layers_uv_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC, + "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_UV]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_enum(srna, "layers_vgroup_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_MDEFORMVERT]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + +#if 0 + prop = RNA_def_enum(srna, "layers_shapekey_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_SHAPEKEY]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +#endif + + prop = RNA_def_enum(srna, "layers_vcol_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_VCOL]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_enum(srna, "layers_uv_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST, + "Destination Layers Matching", "How to match source and destination layers"); + RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_UV]"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* Mix stuff */ + prop = RNA_def_enum(srna, "mix_mode", DT_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode", + "How to affect destination elements with source values"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_mix_mode_itemf"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_float(srna, "mix_factor", 1.0f, 0.0f, 1.0f, "Mix Factor", + "Factor to use when applying data to destination (exact behavior depends on mix mode)", + 0.0f, 1.0f); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_string(srna, "vertex_group", NULL, MAX_VGROUP_NAME, "Vertex Group", + "Vertex group name for selecting the affected areas"); + RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_DataTransferModifier_defgrp_name_set"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_boolean(srna, "invert_vertex_group", false, "Invert", "Invert vertex group influence"); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_INVERT_VGROUP); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +} + static void rna_def_modifier_pointcache(BlenderRNA *brna) { StructRNA *srna; @@ -3797,6 +4450,7 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_meshcache(brna); rna_def_modifier_laplaciandeform(brna); rna_def_modifier_wireframe(brna); + rna_def_modifier_datatransfer(brna); rna_def_modifier_pointcache(brna); } diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index 170856a3061..e891ab520f9 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -317,8 +317,8 @@ static void rna_def_movieclip(BlenderRNA *brna) /* grease pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this movie clip"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 91dcb9f4d81..fa8d2669161 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2199,6 +2199,10 @@ static void rna_NodeSocketStandard_float_range(PointerRNA *ptr, float *min, floa bNodeSocketValueFloat *dval = sock->default_value; int subtype = sock->typeinfo->subtype; + if (dval->max < dval->min) { + dval->max = dval->min; + } + *min = (subtype == PROP_UNSIGNED ? 0.0f : -FLT_MAX); *max = FLT_MAX; *softmin = dval->min; @@ -2211,6 +2215,10 @@ static void rna_NodeSocketStandard_int_range(PointerRNA *ptr, int *min, int *max bNodeSocketValueInt *dval = sock->default_value; int subtype = sock->typeinfo->subtype; + if (dval->max < dval->min) { + dval->max = dval->min; + } + *min = (subtype == PROP_UNSIGNED ? 0 : INT_MIN); *max = INT_MAX; *softmin = dval->min; @@ -2222,6 +2230,10 @@ static void rna_NodeSocketStandard_vector_range(PointerRNA *ptr, float *min, flo bNodeSocket *sock = ptr->data; bNodeSocketValueVector *dval = sock->default_value; + if (dval->max < dval->min) { + dval->max = dval->min; + } + *min = -FLT_MAX; *max = FLT_MAX; *softmin = dval->min; @@ -7572,8 +7584,8 @@ static void rna_def_nodetree(BlenderRNA *brna) /* Grease Pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock"); RNA_def_property_update(prop, NC_NODE, NULL); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 8ebeeafbc58..f9a76005df8 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -42,10 +42,13 @@ #include "BLI_utildefines.h" #include "BLI_listbase.h" +#include "BKE_camera.h" #include "BKE_paint.h" #include "BKE_editmesh.h" #include "BKE_group.h" /* needed for BKE_group_object_exists() */ #include "BKE_object.h" /* Needed for BKE_object_matrix_local_get() */ +#include "BKE_object_deform.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -231,21 +234,21 @@ static void rna_Object_matrix_local_get(PointerRNA *ptr, float values[16]) static void rna_Object_matrix_local_set(PointerRNA *ptr, const float values[16]) { Object *ob = ptr->id.data; + float local_mat[4][4]; - /* localspace matrix is truly relative to the parent, but parameters - * stored in object are relative to parentinv matrix. Undo the parent - * inverse part before updating obmat and calling apply_obmat() */ + /* localspace matrix is truly relative to the parent, but parameters stored in object are + * relative to parentinv matrix. Undo the parent inverse part before applying it as local matrix. */ if (ob->parent) { float invmat[4][4]; invert_m4_m4(invmat, ob->parentinv); - mul_m4_m4m4(ob->obmat, invmat, (float(*)[4])values); + mul_m4_m4m4(local_mat, invmat, (float(*)[4])values); } else { - copy_m4_m4(ob->obmat, (float(*)[4])values); + copy_m4_m4(local_mat, (float(*)[4])values); } - /* don't use compat so we get predictable rotation */ - BKE_object_apply_mat4(ob, ob->obmat, false, false); + /* don't use compat so we get predictable rotation, and do not use parenting either, because it's a local matrix! */ + BKE_object_apply_mat4(ob, local_mat, false, false); } static void rna_Object_matrix_basis_get(PointerRNA *ptr, float values[16]) @@ -775,7 +778,7 @@ static void rna_Object_rotation_axis_angle_set(PointerRNA *ptr, const float *val /* for now, assume that rotation mode is axis-angle */ ob->rotAngle = value[0]; - copy_v3_v3(ob->rotAxis, (float *)&value[1]); + copy_v3_v3(ob->rotAxis, &value[1]); /* TODO: validate axis? */ } @@ -1389,7 +1392,7 @@ static void rna_Object_boundbox_get(PointerRNA *ptr, float *values) static bDeformGroup *rna_Object_vgroup_new(Object *ob, const char *name) { - bDeformGroup *defgroup = ED_vgroup_add_name(ob, name); + bDeformGroup *defgroup = BKE_object_defgroup_add_name(ob, name); WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); @@ -1404,7 +1407,7 @@ static void rna_Object_vgroup_remove(Object *ob, ReportList *reports, PointerRNA return; } - ED_vgroup_delete(ob, defgroup); + BKE_object_defgroup_remove(ob, defgroup); RNA_POINTER_INVALIDATE(defgroup_ptr); WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); @@ -1412,7 +1415,7 @@ static void rna_Object_vgroup_remove(Object *ob, ReportList *reports, PointerRNA static void rna_Object_vgroup_clear(Object *ob) { - ED_vgroup_clear(ob); + BKE_object_defgroup_remove_all(ob); WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); } @@ -1422,7 +1425,7 @@ static void rna_VertexGroup_vertex_add(ID *id, bDeformGroup *def, ReportList *re { Object *ob = (Object *)id; - if (ED_vgroup_object_is_edit_mode(ob)) { + if (BKE_object_is_in_editmode_vgroup(ob)) { BKE_report(reports, RPT_ERROR, "VertexGroup.add(): cannot be called while object is in edit mode"); return; } @@ -1437,7 +1440,7 @@ static void rna_VertexGroup_vertex_remove(ID *id, bDeformGroup *dg, ReportList * { Object *ob = (Object *)id; - if (ED_vgroup_object_is_edit_mode(ob)) { + if (BKE_object_is_in_editmode_vgroup(ob)) { BKE_report(reports, RPT_ERROR, "VertexGroup.remove(): cannot be called while object is in edit mode"); return; } @@ -2427,7 +2430,9 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "matrix_local", PROP_FLOAT, PROP_MATRIX); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Local Matrix", "Parent relative transformation matrix"); + RNA_def_property_ui_text(prop, "Local Matrix", "Parent relative transformation matrix - " + "WARNING: Only takes into account 'Object' parenting, so e.g. in case of bone parenting " + "you get a matrix relative to the Armature object, not to the actual parent bone"); RNA_def_property_float_funcs(prop, "rna_Object_matrix_local_get", "rna_Object_matrix_local_set", NULL); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, NULL); @@ -2727,16 +2732,16 @@ static void rna_def_object(BlenderRNA *brna) /* Grease Pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); /* pose */ prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "poselib"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Action"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Pose Library", "Action used as a pose library for armatures"); prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 831e5486236..1b4bc10551b 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -109,7 +109,29 @@ static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseCh } } - BKE_constraint_mat_convertspace(ob, pchan, (float (*)[4])mat_ret, from, to); + BKE_constraint_mat_convertspace(ob, pchan, (float (*)[4])mat_ret, from, to, false); +} + +static void rna_Object_calc_matrix_camera( + Object *ob, float mat_ret[16], int width, int height, float scalex, float scaley) +{ + CameraParams params; + + /* setup parameters */ + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, ob); + + /* compute matrix, viewplane, .. */ + BKE_camera_params_compute_viewplane(¶ms, width, height, scalex, scaley); + BKE_camera_params_compute_matrix(¶ms); + + copy_m4_m4((float (*)[4])mat_ret, params.winmat); +} + +static void rna_Object_camera_fit_coords( + Object *ob, Scene *scene, int num_cos, float *cos, float co_ret[3], float *scale_ret) +{ + BKE_camera_view_frame_fit_to_coords(scene, (float (*)[3])cos, num_cos / 3, ob, co_ret, scale_ret); } /* copied from Mesh_getFromObject and adapted to RNA interface */ @@ -203,10 +225,9 @@ static void rna_Object_free_duplilist(Object *ob) static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *reports, const char *name, int from_mix) { - Scene *scene = CTX_data_scene(C); KeyBlock *kb = NULL; - if ((kb = BKE_object_insert_shape_key(scene, ob, name, from_mix))) { + if ((kb = BKE_object_insert_shape_key(ob, name, from_mix))) { PointerRNA keyptr; RNA_pointer_create((ID *)ob->data, &RNA_ShapeKey, kb, &keyptr); @@ -468,6 +489,35 @@ void RNA_api_object(StructRNA *srna) parm = RNA_def_enum(func, "to_space", space_items, CONSTRAINT_SPACE_WORLD, "", "The space to which you want to transform 'matrix'"); + /* Camera-related operations */ + func = RNA_def_function(srna, "calc_matrix_camera", "rna_Object_calc_matrix_camera"); + RNA_def_function_ui_description(func, "Generate the camera projection matrix of this object " + "(mostly useful for Camera and Lamp types)"); + parm = RNA_def_property(func, "result", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The camera projection matrix"); + RNA_def_function_output(func, parm); + parm = RNA_def_int(func, "x", 1, 0, INT_MAX, "", "Width of the render area", 0, 10000); + parm = RNA_def_int(func, "y", 1, 0, INT_MAX, "", "Height of the render area", 0, 10000); + parm = RNA_def_float(func, "scale_x", 1.0f, 1.0e-6f, FLT_MAX, "", "Width scaling factor", 1.0e-2f, 100.0f); + parm = RNA_def_float(func, "scale_y", 1.0f, 1.0e-6f, FLT_MAX, "", "height scaling factor", 1.0e-2f, 100.0f); + + func = RNA_def_function(srna, "camera_fit_coords", "rna_Object_camera_fit_coords"); + RNA_def_function_ui_description(func, "Compute the coordinate (and scale for ortho cameras) " + "given object should be to 'see' all given coordinates"); + parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to get render size information from, if available"); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_float_array(func, "coordinates", 1, NULL, -FLT_MAX, FLT_MAX, "", "Coordinates to fit in", + -FLT_MAX, FLT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_DYNAMIC); + parm = RNA_def_property(func, "co_return", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(parm, 3); + RNA_def_property_ui_text(parm, "", "The location to aim to be able to see all given points"); + RNA_def_property_flag(parm, PROP_OUTPUT); + parm = RNA_def_property(func, "scale_return", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(parm, "", "The ortho scale to aim to be able to see all given points (if relevant)"); + RNA_def_property_flag(parm, PROP_OUTPUT); + /* mesh */ func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh"); RNA_def_function_ui_description(func, "Create a Mesh datablock with modifiers applied"); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index f72f97b1681..07dac63f3fe 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -258,7 +258,7 @@ static void rna_PoseChannel_rotation_axis_angle_set(PointerRNA *ptr, const float /* for now, assume that rotation mode is axis-angle */ pchan->rotAngle = value[0]; - copy_v3_v3(pchan->rotAxis, (float *)&value[1]); + copy_v3_v3(pchan->rotAxis, &value[1]); /* TODO: validate axis? */ } diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 0ee654d4ecc..6db9c8e9cd9 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -38,7 +38,6 @@ #include "RE_engine.h" #include "RE_pipeline.h" -#include "RE_engine.h" EnumPropertyItem render_pass_type_items[] = { @@ -520,6 +519,11 @@ static void rna_def_render_engine(BlenderRNA *brna) prop = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); RNA_def_property_flag(prop, PROP_REQUIRED); + func = RNA_def_function(srna, "error_set", "RE_engine_set_error_message"); + RNA_def_function_ui_description(func, "Set error message displaying after the render is finished"); + prop = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); + RNA_def_property_flag(prop, PROP_REQUIRED); + func = RNA_def_function(srna, "bind_display_space_shader", "engine_bind_display_space_shader"); RNA_def_function_ui_description(func, "Bind GLSL fragment shader that converts linear colors to display space colors using scene color management settings"); prop = RNA_def_pointer(func, "scene", "Scene", "", ""); diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 86a8b162614..58a12f62644 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -644,8 +644,7 @@ static void rna_RigidBodyWorld_convex_sweep_test( BKE_report(reports, RPT_ERROR, "Rigidbody world was not properly initialized, need to step the simulation first"); } #else - (void)rbw, (void)reports, (void)object, (void)ray_start, (void)ray_end; - (void)r_location, (void)r_hitpoint, (void)r_normal, (void)r_hit; + UNUSED_VARS(rbw, reports, object, ray_start, ray_end, r_location, r_hitpoint, r_normal, r_hit); #endif } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 519a52b04e2..d9587b8d983 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -737,7 +737,7 @@ static int rna_RenderSettings_threads_mode_get(PointerRNA *ptr) return (rd->mode & R_FIXED_THREADS); } -static int rna_RenderSettings_is_movie_fomat_get(PointerRNA *ptr) +static int rna_RenderSettings_is_movie_format_get(PointerRNA *ptr) { RenderData *rd = (RenderData *)ptr->data; return BKE_imtype_is_movie(rd->im_format.imtype); @@ -1773,6 +1773,14 @@ static void rna_def_tool_settings(BlenderRNA *brna) {WT_VGROUP_BONE_DEFORM_OFF, "OTHER_DEFORM", 0, "Other", "Vertex Groups assigned to non Deform Bones"}, {0, NULL, 0, NULL, NULL} }; + + static EnumPropertyItem gpencil_source_3d_items[] = { + {GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene", + "Grease Pencil data attached to the current scene is used, unless the active object already has Grease Pencil data (i.e. for old files)"}, + {GP_TOOL_SOURCE_OBJECT, "OBJECT", 0, "Object", + "Grease Pencil datablocks attached to the active object are used (required using pre 2.73 add-ons, e.g. BSurfaces)"}, + {0, NULL, 0, NULL, NULL} + }; srna = RNA_def_struct(brna, "ToolSettings", NULL); @@ -1965,6 +1973,13 @@ static void rna_def_tool_settings(BlenderRNA *brna) "Allow drawing multiple strokes at a time with Grease Pencil"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* xxx: need toolbar to be redrawn... */ + prop = RNA_def_property(srna, "grease_pencil_source", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_src"); + RNA_def_property_enum_items(prop, gpencil_source_3d_items); + RNA_def_property_ui_text(prop, "Grease Pencil Source", + "Datablock where active Grease Pencil data is found from"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + /* Auto Keying */ prop = RNA_def_property(srna, "use_keyframe_insert_auto", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_mode", AUTOKEY_ON); @@ -4801,7 +4816,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "is_movie_format", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_is_movie_fomat_get", NULL); + RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_is_movie_format_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Movie Format", "When true the format is a movie"); @@ -5459,7 +5474,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "lay", 1); RNA_def_property_array(prop, 20); RNA_def_property_boolean_funcs(prop, NULL, "rna_Scene_layer_set"); - RNA_def_property_ui_text(prop, "Layers", "Visible layers - Shift-Click to select multiple layers"); + RNA_def_property_ui_text(prop, "Layers", "Visible layers - Shift-Click/Drag to select multiple layers"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_Scene_layer_update"); /* active layer */ @@ -5738,10 +5753,10 @@ void RNA_def_scene(BlenderRNA *brna) /* Grease Pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); /* Transform Orientations */ prop = RNA_def_property(srna, "orientations", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 84134e7cd3a..be618c5d1a3 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -47,12 +47,14 @@ #include "BKE_animsys.h" #include "BKE_depsgraph.h" +#include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_scene.h" #include "BKE_writeavi.h" #include "ED_transform.h" +#include "ED_uvedit.h" #ifdef WITH_PYTHON # include "BPY_extern.h" @@ -90,6 +92,20 @@ static void rna_Scene_frame_set(Scene *scene, int frame, float subframe) } } +static void rna_Scene_uvedit_aspect(Scene *scene, Object *ob, float *aspect) +{ + if ((ob->type == OB_MESH) && (ob->mode == OB_MODE_EDIT)) { + BMEditMesh *em; + em = BKE_editmesh_from_object(ob); + if (EDBM_mtexpoly_check(em)) { + ED_uvedit_get_aspect(scene, ob, em->bm, aspect, aspect + 1); + return; + } + } + + aspect[0] = aspect[1] = 1.0f; +} + static void rna_Scene_update_tagged(Scene *scene) { #ifdef WITH_PYTHON @@ -191,6 +207,15 @@ void RNA_api_scene(StructRNA *srna) RNA_def_function_ui_description(func, "Update data tagged to be updated from previous access to data or operators"); + func = RNA_def_function(srna, "uvedit_aspect", "rna_Scene_uvedit_aspect"); + RNA_def_function_ui_description(func, "Get uv aspect for current object"); + parm = RNA_def_pointer(func, "object", "Object", "", "Object"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + + parm = RNA_def_float_vector(func, "result", 2, NULL, 0.0f, FLT_MAX, "", "aspect", 0.0f, FLT_MAX); + RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_function_output(func, parm); + /* Ray Cast */ func = RNA_def_function(srna, "ray_cast", "rna_Scene_ray_cast"); RNA_def_function_ui_description(func, "Cast a ray onto in object space"); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 86a28fb80bf..7b01acff6a5 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -110,7 +110,9 @@ static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), static int rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr)) { - return (ED_screen_animation_playing(G.main->wm.first) != NULL); + /* can be NULL on file load, T42619 */ + wmWindowManager *wm = G.main->wm.first; + return wm ? (ED_screen_animation_playing(wm) != NULL) : 0; } static int rna_Screen_fullscreen_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 09e42e48e93..8e83543812d 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -289,7 +289,8 @@ static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr)) static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { - Brush *br = (Brush *)ptr->data; + Paint *paint = ptr->data; + Brush *br = paint->brush; BKE_paint_invalidate_overlay_all(); WM_main_add_notifier(NC_BRUSH | NA_EDITED, br); } @@ -303,22 +304,27 @@ static void rna_ImaPaint_viewport_update(Main *UNUSED(bmain), Scene *UNUSED(scen static void rna_ImaPaint_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { Object *ob = OBACT; - - /* of course we need to invalidate here */ - BKE_texpaint_slots_refresh_object(scene, ob); - /* we assume that changing the current mode will invalidate the uv layers so we need to refresh display */ - GPU_drawobject_free(ob->derivedFinal); - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + if (ob && ob->type == OB_MESH) { + /* of course we need to invalidate here */ + BKE_texpaint_slots_refresh_object(scene, ob); + + /* we assume that changing the current mode will invalidate the uv layers so we need to refresh display */ + GPU_drawobject_free(ob->derivedFinal); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + } } static void rna_ImaPaint_stencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { - Object *ob = OBACT; - GPU_drawobject_free(ob->derivedFinal); - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + Object *ob = OBACT; + + if (ob && ob->type == OB_MESH) { + GPU_drawobject_free(ob->derivedFinal); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + } } static void rna_ImaPaint_canvas_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) @@ -342,9 +348,11 @@ static void rna_ImaPaint_canvas_update(Main *bmain, Scene *scene, PointerRNA *UN } } - GPU_drawobject_free(ob->derivedFinal); - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + if (ob && ob->type == OB_MESH) { + GPU_drawobject_free(ob->derivedFinal); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + } } static int rna_ImaPaint_detect_data(ImagePaintSettings *imapaint) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 00f0a6ff487..dda0e8493d9 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1846,6 +1846,11 @@ static void rna_def_scene(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Camera_object_poll"); RNA_def_property_ui_text(prop, "Camera Override", "Override the scenes active camera"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + + prop = RNA_def_property(srna, "use_grease_pencil", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_SCENE_NO_GPENCIL); + RNA_def_property_ui_text(prop, "Use Grease Pencil", "Show Grease Pencil strokes in OpenGL previews"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); rna_def_filter_video(srna); rna_def_proxy(srna); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 70370f1ae36..3d358b412c8 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -313,6 +313,7 @@ static Sequence *rna_Sequences_new_effect(ID *id, Editing *ed, ReportList *repor seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE; + BKE_sequence_calc(scene, seq); BKE_sequence_calc_disp(scene, seq); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c index 206a72a01b0..aa39e81d390 100644 --- a/source/blender/makesrna/intern/rna_sound.c +++ b/source/blender/makesrna/intern/rna_sound.c @@ -38,6 +38,7 @@ #include "BKE_sound.h" #include "BKE_context.h" +#include "BKE_sequencer.h" static void rna_Sound_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { @@ -59,9 +60,9 @@ static void rna_Sound_caching_set(PointerRNA *ptr, const int value) sound_delete_cache(sound); } -static void rna_Sound_caching_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Sound_caching_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) { - sound_update_sequencer(bmain, (bSound *)(ptr->data)); + BKE_sequencer_update_sound(scene, (bSound *)(ptr->data)); } #else diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 68173ebefb4..af0e69cdc3e 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -266,13 +266,7 @@ static ScrArea *rna_area_from_space(PointerRNA *ptr) { bScreen *sc = (bScreen *)ptr->id.data; SpaceLink *link = (SpaceLink *)ptr->data; - ScrArea *sa; - - for (sa = sc->areabase.first; sa; sa = sa->next) - if (BLI_findindex(&sa->spacedata, link) != -1) - return sa; - - return NULL; + return BKE_screen_find_area_from_space(sc, link); } static void area_region_from_regiondata(bScreen *sc, void *regiondata, ScrArea **r_sa, ARegion **r_ar) @@ -485,7 +479,7 @@ static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(sce BKE_previewimg_free(&ma->preview); if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ma); } @@ -856,7 +850,6 @@ static void rna_SpaceTextEditor_updateEdited(Main *UNUSED(bmain), Scene *UNUSED( WM_main_add_notifier(NC_TEXT | NA_EDITED, st->text); } - /* Space Properties */ /* note: this function exists only to avoid id refcounting */ @@ -1588,6 +1581,7 @@ static void rna_def_space_outliner(BlenderRNA *brna) prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "search_string"); RNA_def_property_ui_text(prop, "Display Filter", "Live search filtering string"); + RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "use_filter_case_sensitive", PROP_BOOLEAN, PROP_NONE); @@ -2041,6 +2035,11 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Only Render", "Display only objects which will be rendered"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_world", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_SHOW_WORLD); + RNA_def_property_ui_text(prop, "World Background", "Display world colors in the background"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "use_occlude_geometry", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ZBUF_SELECT); RNA_def_property_ui_text(prop, "Occlude Geometry", "Limit selection to visible (clipped with depth buffer)"); @@ -2201,13 +2200,20 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "persmat"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* XXX: for now, it's too risky for users to do this */ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); - RNA_def_property_ui_text(prop, "Perspective Matrix", "Current perspective matrix of the 3D region"); + RNA_def_property_ui_text(prop, "Perspective Matrix", + "Current perspective matrix (``window_matrix * view_matrix``)"); + + prop = RNA_def_property(srna, "window_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "winmat"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Window Matrix", "Current window matrix"); prop = RNA_def_property(srna, "view_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_float_sdna(prop, NULL, "viewmat"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_float_funcs(prop, NULL, "rna_RegionView3D_view_matrix_set", NULL); - RNA_def_property_ui_text(prop, "View Matrix", "Current view matrix of the 3D region"); + RNA_def_property_ui_text(prop, "View Matrix", "Current view matrix"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "view_perspective", PROP_ENUM, PROP_NONE); @@ -2425,8 +2431,8 @@ static void rna_def_space_image(BlenderRNA *brna) /* grease pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); @@ -2509,6 +2515,16 @@ static void rna_def_space_sequencer(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem waveform_type_draw_items[] = { + {SEQ_NO_WAVEFORMS, "NO_WAVEFORMS", 0, "Waveforms Off", + "No waveforms drawn for any sound strips"}, + {SEQ_ALL_WAVEFORMS, "ALL_WAVEFORMS", 0, "Waveforms On", + "Waveforms drawn for all sound strips"}, + {0, "DEFAULT_WAVEFORMS", 0, "Use Strip Option", + "Waveforms drawn according to strip setting"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "SpaceSequenceEditor", "Space"); RNA_def_struct_sdna(srna, "SpaceSeq"); RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data"); @@ -2578,6 +2594,12 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the preview to draw"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + prop = RNA_def_property(srna, "waveform_draw_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, waveform_type_draw_items); + RNA_def_property_ui_text(prop, "Waveform Drawing", "How Waveforms are drawn"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + prop = RNA_def_property(srna, "draw_overexposed", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "zebra"); RNA_def_property_ui_text(prop, "Show Overexposed", "Show overexposed areas with zebra stripes"); @@ -2594,8 +2616,8 @@ static void rna_def_space_sequencer(BlenderRNA *brna) /* grease pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); @@ -2604,6 +2626,16 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_property_enum_items(prop, overlay_type_items); RNA_def_property_ui_text(prop, "Overlay Type", "Overlay draw type"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_backdrop", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "draw_flag", SEQ_DRAW_BACKDROP); + RNA_def_property_ui_text(prop, "Use Backdrop", "Display result under strips"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_offset", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "draw_flag", SEQ_DRAW_OFFSET_EXT); + RNA_def_property_ui_text(prop, "Show Offsets", "Display strip in/out offsets"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); } static void rna_def_space_text(BlenderRNA *brna) @@ -2716,6 +2748,8 @@ static void rna_def_space_text(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "replacestr"); RNA_def_property_ui_text(prop, "Replace Text", "Text to replace selected text with using the replace tool"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL); + + RNA_api_space_text(srna); } static void rna_def_space_dopesheet(BlenderRNA *brna) @@ -2935,14 +2969,12 @@ static void rna_def_space_graph(BlenderRNA *brna) RNA_def_property_enum_items(prop, autosnap_items); RNA_def_property_ui_text(prop, "Auto Snap", "Automatic time snapping settings for transformations"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); - + /* readonly state info */ prop = RNA_def_property(srna, "has_ghost_curves", PROP_BOOLEAN, PROP_NONE); - /* XXX: hack to make this compile, since this property doesn't actually exist*/ - RNA_def_property_boolean_sdna(prop, NULL, "flag", 0); RNA_def_property_boolean_funcs(prop, "rna_SpaceGraphEditor_has_ghost_curves_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Has Ghost Curves", "Graph Editor instance has some ghost curves stored"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); /* nromalize curves */ prop = RNA_def_property(srna, "use_normalization", PROP_BOOLEAN, PROP_NONE); @@ -3078,7 +3110,6 @@ static void rna_def_console_line(BlenderRNA *brna) srna = RNA_def_struct(brna, "ConsoleLine", NULL); RNA_def_struct_ui_text(srna, "Console Input", "Input line for the interactive console"); - /* XXX using non-inited "prop", uh? RNA_def_property_update(prop, NC_SPACE|ND_SPACE_CONSOLE, NULL); */ prop = RNA_def_property(srna, "body", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_ConsoleLine_body_get", "rna_ConsoleLine_body_length", @@ -3203,55 +3234,55 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_image", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", IMAGEFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_IMAGE); RNA_def_property_ui_text(prop, "Filter Images", "Show image files"); RNA_def_property_ui_icon(prop, ICON_FILE_IMAGE, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_blender", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", BLENDERFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_BLENDER); RNA_def_property_ui_text(prop, "Filter Blender", "Show .blend files"); RNA_def_property_ui_icon(prop, ICON_FILE_BLEND, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_backup", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", BLENDERFILE_BACKUP); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_BLENDER_BACKUP); RNA_def_property_ui_text(prop, "Filter BlenderBackup files", "Show .blend1, .blend2, etc. files"); RNA_def_property_ui_icon(prop, ICON_FILE_BACKUP, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_movie", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", MOVIEFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_MOVIE); RNA_def_property_ui_text(prop, "Filter Movies", "Show movie files"); RNA_def_property_ui_icon(prop, ICON_FILE_MOVIE, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_script", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", PYSCRIPTFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_PYSCRIPT); RNA_def_property_ui_text(prop, "Filter Script", "Show script files"); RNA_def_property_ui_icon(prop, ICON_FILE_SCRIPT, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_font", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", FTFONTFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_FTFONT); RNA_def_property_ui_text(prop, "Filter Fonts", "Show font files"); RNA_def_property_ui_icon(prop, ICON_FILE_FONT, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_sound", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", SOUNDFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_SOUND); RNA_def_property_ui_text(prop, "Filter Sound", "Show sound files"); RNA_def_property_ui_icon(prop, ICON_FILE_SOUND, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_text", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", TEXTFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_TEXT); RNA_def_property_ui_text(prop, "Filter Text", "Show text files"); RNA_def_property_ui_icon(prop, ICON_FILE_TEXT, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter_folder", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filter", FOLDERFILE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_FOLDER); RNA_def_property_ui_text(prop, "Filter Folder", "Show folders"); RNA_def_property_ui_icon(prop, ICON_FILE_FOLDER, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -3261,6 +3292,11 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Extension Filter", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + prop = RNA_def_property(srna, "filter_search", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "filter_search"); + RNA_def_property_ui_text(prop, "Name Filter", "Filter by name, supports '*' wildcard"); + RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } static void rna_def_space_filebrowser(BlenderRNA *brna) @@ -3345,6 +3381,7 @@ static void rna_def_space_userpref(BlenderRNA *brna) prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "filter"); + RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE); RNA_def_property_ui_text(prop, "Filter", "Search term for filtering in the UI"); } diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index aed77378241..4114ee8a289 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -31,6 +31,8 @@ #ifdef RNA_RUNTIME +#include "ED_text.h" + static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d) { bScreen *sc = (bScreen *)id; @@ -49,6 +51,19 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d) } } +static void rna_SpaceTextEditor_region_location_from_cursor( + ID *id, SpaceText *st, + int line, int column, int r_pixel_pos[2]) +{ + bScreen *sc = (bScreen *)id; + ScrArea *sa = BKE_screen_find_area_from_space(sc, (SpaceLink *)st); + if (sa) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + const int cursor_co[2] = {line, column}; + ED_text_region_location_from_cursor(st, ar, cursor_co, r_pixel_pos); + } +} + #else void RNA_api_region_view3d(StructRNA *srna) @@ -74,4 +89,20 @@ void RNA_api_space_node(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED); } +void RNA_api_space_text(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "region_location_from_cursor", "rna_SpaceTextEditor_region_location_from_cursor"); + RNA_def_function_ui_description(func, "Retrieve the region position from the given line and character position"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_int(func, "line", 0, INT_MIN, INT_MAX, "Line", "Line index", 0, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_int(func, "column", 0, INT_MIN, INT_MAX, "Column", "Column index", 0, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_int_array(func, "result", 2, 0, -1, INT_MAX, "", "Region coordinates", -1, INT_MAX); + RNA_def_function_output(func, parm); +} + #endif diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index f098a659671..188a30d23ce 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -119,6 +119,7 @@ static EnumPropertyItem blend_type_items[] = { #include "BKE_main.h" #include "ED_node.h" +#include "ED_render.h" static StructRNA *rna_Texture_refine(struct PointerRNA *ptr) { @@ -443,8 +444,10 @@ static void rna_Envmap_source_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Tex *tex = ptr->id.data; - if (tex->env) + if (tex->env) { + ED_preview_kill_jobs(bmain->wm.first, bmain); BKE_free_envmapdata(tex->env); + } rna_Texture_update(bmain, scene, ptr); } diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 899da62d9d3..5a70d47a19a 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1435,8 +1435,8 @@ static void rna_def_trackingTrack(BlenderRNA *brna) /* grease pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); - RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this track"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 92c5530202b..a61846fa028 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1062,6 +1062,7 @@ static void rna_def_uilist(BlenderRNA *brna) prop = RNA_def_property(srna, "filter_name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "filter_byname"); + RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE); RNA_def_property_ui_text(prop, "Filter by Name", "Only show items matching this name (use '*' as wildcard)"); prop = RNA_def_property(srna, "use_filter_invert", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 33c35313b38..4f889c91665 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -137,9 +137,7 @@ static void rna_uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const /* Get translated name (label). */ name = rna_translate_ui_text(name, text_ctxt, NULL, prop, translate); - - /* XXX This will search property again :( */ - uiItemMenuEnumR(layout, ptr, propname, name, icon); + uiItemMenuEnumR_prop(layout, ptr, prop, name, icon); } static void rna_uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index ab5039df627..fa0e1db10e2 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -35,6 +35,8 @@ #include "BLI_utildefines.h" +#include "BKE_appdir.h" +#include "BKE_DerivedMesh.h" #include "BKE_sound.h" #include "BKE_addon.h" @@ -48,6 +50,7 @@ #include "WM_types.h" #include "BLF_translation.h" +#include "GPU_buffers.h" #ifdef WITH_CYCLES static EnumPropertyItem compute_device_type_items[] = { @@ -141,6 +144,15 @@ static void rna_userdef_language_update(Main *UNUSED(bmain), Scene *UNUSED(scene UI_reinit_font(); } +static void rna_userdef_vbo_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + Object *ob; + + for (ob = bmain->object.first; ob; ob = ob->id.next) { + GPU_drawobject_free(ob->derivedFinal); + } +} + static void rna_userdef_show_manipulator_update(Main *bmain, Scene *scene, PointerRNA *ptr) { UserDef *userdef = (UserDef *)ptr->data; @@ -414,7 +426,7 @@ static void rna_userdef_pathcompare_remove(ReportList *reports, PointerRNA *path static void rna_userdef_temp_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { - BLI_temp_dir_init(U.tempdir); + BKE_tempdir_init(U.tempdir); } static void rna_userdef_text_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) @@ -1031,10 +1043,10 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Icon Alpha", "Transparency of icons in the interface, to reduce contrast"); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "emboss", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "emboss"); + prop = RNA_def_property(srna, "widget_emboss", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "widget_emboss"); RNA_def_property_array(prop, 4); - RNA_def_property_ui_text(prop, "Emboss", ""); + RNA_def_property_ui_text(prop, "Widget Emboss", "Color of the 1px shadow line underlying widgets"); RNA_def_property_update(prop, 0, "rna_userdef_update"); /* axis */ @@ -1476,6 +1488,26 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs } } +static void rna_def_userdef_theme_spaces_gpencil(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "gp_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Grease Pencil Vertex", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "gp_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Grease Pencil Vertex Select", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "gp_vertex_size", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 1, 10); + RNA_def_property_ui_text(prop, "Grease Pencil Vertex Size", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); +} + static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) { StructRNA *srna; @@ -1504,6 +1536,8 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Wire Edit", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + rna_def_userdef_theme_spaces_gpencil(srna); prop = RNA_def_property(srna, "lamp", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 4); @@ -2034,6 +2068,8 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna) rna_def_userdef_theme_spaces_main(srna); rna_def_userdef_theme_spaces_list_main(srna); + + rna_def_userdef_theme_spaces_gpencil(srna); prop = RNA_def_property(srna, "node_selected", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "select"); @@ -2238,6 +2274,18 @@ static void rna_def_userdef_theme_space_time(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "time_keyframe", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "time_keyframe"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Keyframe", "Base color for keyframe indicator lines"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "time_grease_pencil", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "time_gp_keyframe"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Grease Pencil", "Color of Grease Pencil keyframes"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); } static void rna_def_userdef_theme_space_image(BlenderRNA *brna) @@ -2253,8 +2301,10 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Theme Image Editor", "Theme settings for the Image Editor"); rna_def_userdef_theme_spaces_main(srna); + rna_def_userdef_theme_spaces_gpencil(srna); rna_def_userdef_theme_spaces_vertex(srna); rna_def_userdef_theme_spaces_face(srna); + prop = RNA_def_property(srna, "editmesh_active", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 4); @@ -2349,6 +2399,7 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Theme Sequence Editor", "Theme settings for the Sequence Editor"); rna_def_userdef_theme_spaces_main(srna); + rna_def_userdef_theme_spaces_gpencil(srna); prop = RNA_def_property(srna, "grid", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); @@ -2760,6 +2811,8 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) rna_def_userdef_theme_spaces_main(srna); rna_def_userdef_theme_spaces_list_main(srna); + + rna_def_userdef_theme_spaces_gpencil(srna); prop = RNA_def_property(srna, "marker_outline", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "marker_outline"); @@ -3951,7 +4004,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "VBOs", "Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering"); /* this isn't essential but nice to check if VBO draws any differently */ - RNA_def_property_update(prop, NC_WINDOW, NULL); + RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_vbo_update"); prop = RNA_def_property(srna, "anisotropic_filter", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "anisotropic_filter"); diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index f63350ea0ae..721cbaf21c7 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -89,7 +89,7 @@ static void rna_World_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR World *wo = ptr->id.data; DAG_id_tag_update(&wo->id, 0); - WM_main_add_notifier(NC_WORLD, wo); + WM_main_add_notifier(NC_WORLD | ND_WORLD, wo); } static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 58bd515efdb..876a95d8d8c 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -53,6 +53,7 @@ set(SRC intern/MOD_cloth.c intern/MOD_collision.c intern/MOD_curve.c + intern/MOD_datatransfer.c intern/MOD_decimate.c intern/MOD_displace.c intern/MOD_dynamicpaint.c diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h index 2e50c5a045e..8edcb7e0380 100644 --- a/source/blender/modifiers/MOD_modifiertypes.h +++ b/source/blender/modifiers/MOD_modifiertypes.h @@ -81,6 +81,7 @@ extern ModifierTypeInfo modifierType_UVWarp; extern ModifierTypeInfo modifierType_MeshCache; extern ModifierTypeInfo modifierType_LaplacianDeform; extern ModifierTypeInfo modifierType_Wireframe; +extern ModifierTypeInfo modifierType_DataTransfer; extern ModifierTypeInfo modifierType_PointCache; /* MOD_util.c */ diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 6046de2cf61..b6d75afaf23 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -167,8 +167,8 @@ typedef struct SortVertsElem { static int svert_sum_cmp(const void *e1, const void *e2) { - const SortVertsElem *sv1 = (SortVertsElem *)e1; - const SortVertsElem *sv2 = (SortVertsElem *)e2; + const SortVertsElem *sv1 = e1; + const SortVertsElem *sv2 = e2; if (sv1->sum_co > sv2->sum_co) return 1; else if (sv1->sum_co < sv2->sum_co) return -1; @@ -404,7 +404,7 @@ static DerivedMesh *arrayModifier_doArray( int *full_doubles_map = NULL; int tot_doubles; - const bool use_merge = amd->flags & MOD_ARR_MERGE; + const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0; const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge; const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob); /* allow pole vertices to be used by many faces */ diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 49c0c091dee..22636e7c4d0 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -39,8 +39,6 @@ #include "BLI_utildefines.h" -#include "BLF_translation.h" - #include "BKE_cdderivedmesh.h" #include "BKE_modifier.h" @@ -49,8 +47,6 @@ #include "MOD_boolean_util.h" #include "MOD_util.h" -#include "PIL_time.h" - static void copyData(ModifierData *md, ModifierData *target) { #if 0 diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c index 6e62a21ec4c..061b1198f7e 100644 --- a/source/blender/modifiers/intern/MOD_boolean_util.c +++ b/source/blender/modifiers/intern/MOD_boolean_util.c @@ -365,14 +365,6 @@ BLI_INLINE MPoly *which_mpoly(ExportMeshData *export_data, int which_mesh) return mpoly; } -static void allocate_custom_layers(CustomData *data, int type, int num_elements, int num_layers) -{ - int i; - for (i = 0; i < num_layers; i++) { - CustomData_add_layer(data, type, CD_DEFAULT, NULL, num_elements); - } -} - /* Create new external mesh */ static void exporter_InitGeomArrays(ExportMeshData *export_data, int num_verts, int num_edges, @@ -392,24 +384,15 @@ static void exporter_InitGeomArrays(ExportMeshData *export_data, export_data->mloop = dm->getLoopArray(dm); export_data->mpoly = dm->getPolyArray(dm); - /* Allocate layers for UV layers and vertex colors. - * Without this interpolation of those data will not happen. - */ - allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops, - CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPCOL)); - allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops, - CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPUV)); - - allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops, - CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPCOL)); - allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops, - CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPUV)); - /* Merge custom data layers from operands. * * Will only create custom data layers for all the layers which appears in * the operand. Data for those layers will not be allocated or initialized. */ + + CustomData_merge(&dm_left->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops); + CustomData_merge(&dm_right->loopData, &dm->loopData, merge_mask, CD_DEFAULT, num_loops); + CustomData_merge(&dm_left->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys); CustomData_merge(&dm_right->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys); diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index f6ade2bf303..f30529bc40f 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -40,16 +40,16 @@ #include "BLI_math_vector.h" #include "BLI_ghash.h" -#include "DNA_scene_types.h" #include "DNA_meshdata_types.h" #include "BKE_cdderivedmesh.h" -#include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_scene.h" -#include "MOD_util.h" +#ifdef _OPENMP +# include "BKE_mesh.h" /* BKE_MESH_OMP_LIMIT */ +#endif static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index d2ac04d6f81..491b3deef01 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -32,7 +32,6 @@ * \ingroup modifiers */ - #include "DNA_object_force.h" #include "DNA_object_types.h" #include "DNA_pointcache_types.h" @@ -51,8 +50,6 @@ #include "BKE_pointcache.h" #include "BKE_scene.h" -#include "MOD_util.h" - static void initData(ModifierData *md) { CollisionModifierData *collmd = (CollisionModifierData *) md; diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index fbc72cef0e8..9c3ccf033a5 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -32,7 +32,6 @@ * \ingroup modifiers */ - #include <string.h> #include "DNA_scene_types.h" @@ -47,7 +46,6 @@ #include "depsgraph_private.h" -#include "MOD_util.h" static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c new file mode 100644 index 00000000000..2dca3218e41 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -0,0 +1,221 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): None yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_datatransfer.c + * \ingroup modifiers + */ + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BKE_customdata.h" +#include "BKE_data_transfer.h" +#include "BKE_DerivedMesh.h" +#include "BKE_library.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" +#include "BKE_modifier.h" +#include "BKE_report.h" + +#include "MEM_guardedalloc.h" +#include "MOD_util.h" + +#include "depsgraph_private.h" + +/************************************** + * Modifiers functions. * + **************************************/ +static void initData(ModifierData *md) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + int i; + + dtmd->ob_source = NULL; + dtmd->data_types = 0; + + dtmd->vmap_mode = MREMAP_MODE_VERT_NEAREST; + dtmd->emap_mode = MREMAP_MODE_EDGE_NEAREST; + dtmd->lmap_mode = MREMAP_MODE_LOOP_NEAREST_POLYNOR; + dtmd->pmap_mode = MREMAP_MODE_POLY_NEAREST; + + dtmd->map_max_distance = 1.0f; + dtmd->map_ray_radius = 0.0f; + + for (i = 0; i < DT_MULTILAYER_INDEX_MAX; i++) { + dtmd->layers_select_src[i] = DT_LAYERS_ALL_SRC; + dtmd->layers_select_dst[i] = DT_LAYERS_NAME_DST; + } + + dtmd->mix_mode = CDT_MIX_TRANSFER; + dtmd->mix_factor = 1.0f; + dtmd->defgrp_name[0] = '\0'; + + dtmd->flags = MOD_DATATRANSFER_OBSRC_TRANSFORM; +} + +static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + CustomDataMask dataMask = 0; + + if (dtmd->defgrp_name[0]) { + /* We need vertex groups! */ + dataMask |= CD_MASK_MDEFORMVERT; + } + + dataMask |= BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types); + + return dataMask; +} + +static bool dependsOnNormals(ModifierData *md) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + int item_types = BKE_object_data_transfer_get_dttypes_item_types(dtmd->data_types); + + if ((item_types & ME_VERT) && (dtmd->vmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + if ((item_types & ME_EDGE) && (dtmd->emap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + if ((item_types & ME_LOOP) && (dtmd->lmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + if ((item_types & ME_POLY) && (dtmd->pmap_mode & (MREMAP_USE_NORPROJ | MREMAP_USE_NORMAL))) { + return true; + } + + return false; +} + +static void foreachObjectLink(ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + walk(userData, ob, &dtmd->ob_source); +} + +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) +{ + foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); +} + +static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene), + Object *UNUSED(ob), DagNode *obNode) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + DagNode *curNode; + + if (dtmd->ob_source) { + curNode = dag_get_node(forest, dtmd->ob_source); + + dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, + "DataTransfer Modifier"); + } +} + +static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + /* If no source object, bypass. */ + return (dtmd->ob_source == NULL); +} + +#define HIGH_POLY_WARNING 10000 + +static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, + ModifierApplyFlag UNUSED(flag)) +{ + DataTransferModifierData *dtmd = (DataTransferModifierData *) md; + DerivedMesh *dm = derivedData; + ReportList reports; + + const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0; + + const float max_dist = (dtmd->flags & MOD_DATATRANSFER_MAP_MAXDIST) ? dtmd->map_max_distance : FLT_MAX; + + SpaceTransform space_transform_data; + SpaceTransform *space_transform = (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) ? &space_transform_data : NULL; + + if (space_transform) { + BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source); + } + + BKE_reports_init(&reports, RPT_STORE); + + /* Note: no islands precision for now here. */ + BKE_object_data_transfer_dm(md->scene, dtmd->ob_source, ob, dm, dtmd->data_types, false, + dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode, + space_transform, max_dist, dtmd->map_ray_radius, 0.0f, + dtmd->layers_select_src, dtmd->layers_select_dst, + dtmd->mix_mode, dtmd->mix_factor, dtmd->defgrp_name, invert_vgroup, &reports); + + if (BKE_reports_contain(&reports, RPT_ERROR)) { + modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR)); + } + else if (dm->getNumVerts(dm) > HIGH_POLY_WARNING || ((Mesh *)(dtmd->ob_source->data))->totvert > HIGH_POLY_WARNING) { + modifier_setError(md, "You are using a rather high poly as source or destination, computation might be slow"); + } + + return dm; +} + + +ModifierTypeInfo modifierType_DataTransfer = { + /* name */ "DataTransfer", + /* structName */ "DataTransferModifierData", + /* structSize */ sizeof(DataTransferModifierData), + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | + eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_UsesPreview, + + /* copyData */ NULL, + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + /* applyModifierEM */ NULL, + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepgraph */ updateDepgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index b844b9e3bde..8a92deec8eb 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -35,17 +35,12 @@ #include "DNA_object_types.h" #include "BLI_math.h" -#include "BLI_string.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" - #include "MEM_guardedalloc.h" -#include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_deform.h" -#include "BKE_particle.h" #include "BKE_cdderivedmesh.h" #include "bmesh.h" diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 838ceb5cfe0..5236365da70 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -28,7 +28,6 @@ #include <stddef.h> #include "DNA_dynamicpaint_types.h" -#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -40,8 +39,6 @@ #include "depsgraph_private.h" -#include "MOD_util.h" - static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index d3c7e7d4779..32a6303d19d 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -54,7 +54,6 @@ #include "MEM_guardedalloc.h" -#include "MOD_util.h" static void initData(ModifierData *md) { @@ -892,7 +891,7 @@ static DerivedMesh *explodeMesh(ExplodeModifierData *emd, /* get particle */ pa = pars + ed_v2; - psys_get_birth_coordinates(&sim, pa, &birth, 0, 0); + psys_get_birth_coords(&sim, pa, &birth, 0, 0); state.time = cfra; psys_get_particle_state(&sim, ed_v2, &state, 1); diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c index d3c56b8d7f7..9c973cd0d50 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim.c +++ b/source/blender/modifiers/intern/MOD_fluidsim.c @@ -45,7 +45,6 @@ #include "depsgraph_private.h" -#include "MOD_util.h" #include "MOD_fluidsim_util.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index ffadcda3e8c..a4f6d005d94 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -767,7 +767,7 @@ static void LaplacianDeformModifier_do( LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { - (void)lmd, (void)ob, (void)dm, (void)vertexCos, (void)numVerts; + UNUSED_VARS(lmd, ob, dm, vertexCos, numVerts); } #endif /* WITH_OPENNL */ diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index 9ba0bfc7ce9..6f33bfa73fc 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -41,7 +41,6 @@ #include "BKE_deform.h" #include "BKE_modifier.h" -#include "MOD_modifiertypes.h" #include "MOD_util.h" #ifdef WITH_OPENNL @@ -613,7 +612,7 @@ static void laplaciansmoothModifier_do( LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { - (void)smd, (void)ob, (void)dm, (void)vertexCos, (void)numVerts; + UNUSED_VARS(smd, ob, dm, vertexCos, numVerts); } #endif /* WITH_OPENNL */ diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index e4a359a93e2..86687865d02 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -38,7 +38,6 @@ #include "DNA_object_types.h" #include "BLI_utildefines.h" -#include "BLI_string.h" #include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index 5cb9feb4fac..254ca0bda08 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -51,8 +51,6 @@ #include "depsgraph_private.h" -#include "MOD_util.h" - static void copyData(ModifierData *md, ModifierData *target) { #if 0 diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index 925d9691892..db50d49f790 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -48,8 +48,6 @@ #include "MOD_modifiertypes.h" -#include "MOD_util.h" - static void initData(ModifierData *md) { MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c index 3ef0ee54886..679bdcd1d47 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c +++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c @@ -31,7 +31,6 @@ #include "BLI_sys_types.h" #include "BLI_utildefines.h" #include "BLI_fileops.h" -#include "BLI_math.h" #ifdef __BIG_ENDIAN__ # include "BLI_endian_switch.h" #endif diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index c253c0314ad..584b5b5fc76 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -40,8 +40,6 @@ #include "BLI_task.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" - #include "BKE_cdderivedmesh.h" #include "BKE_global.h" #include "BKE_modifier.h" @@ -84,9 +82,16 @@ static void copyData(ModifierData *md, ModifierData *target) MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; MeshDeformModifierData *tmmd = (MeshDeformModifierData *) target; - tmmd->gridsize = mmd->gridsize; - tmmd->flag = mmd->flag; - tmmd->object = mmd->object; + *tmmd = *mmd; + + if (mmd->bindinfluences) tmmd->bindinfluences = MEM_dupallocN(mmd->bindinfluences); + if (mmd->bindoffsets) tmmd->bindoffsets = MEM_dupallocN(mmd->bindoffsets); + if (mmd->bindcagecos) tmmd->bindcagecos = MEM_dupallocN(mmd->bindcagecos); + if (mmd->dyngrid) tmmd->dyngrid = MEM_dupallocN(mmd->dyngrid); + if (mmd->dyninfluences) tmmd->dyninfluences = MEM_dupallocN(mmd->dyninfluences); + if (mmd->dynverts) tmmd->dynverts = MEM_dupallocN(mmd->dynverts); + if (mmd->bindweights) tmmd->dynverts = MEM_dupallocN(mmd->bindweights); /* deprecated */ + if (mmd->bindcos) tmmd->dynverts = MEM_dupallocN(mmd->bindcos); /* deprecated */ } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 5de4a76dcbe..7a7308639f5 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -42,8 +42,6 @@ #include "BKE_modifier.h" #include "BKE_deform.h" -#include "bmesh.h" - #include "MEM_guardedalloc.h" #include "depsgraph_private.h" diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index deae10b5bcb..4754813a744 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -44,11 +44,8 @@ #include "BKE_mesh.h" #include "BKE_multires.h" #include "BKE_modifier.h" -#include "BKE_paint.h" #include "BKE_subsurf.h" -#include "MOD_util.h" - static void initData(ModifierData *md) { MultiresModifierData *mmd = (MultiresModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index a324702a6ae..1c8dcdff46d 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -43,8 +43,6 @@ #include "BKE_modifier.h" #include "BKE_ocean.h" -#include "MOD_util.h" - #ifdef WITH_OCEANSIM static void init_cache_data(Object *ob, struct OceanModifierData *omd) { diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index 3ca791b7664..56197bfcca8 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -48,8 +48,6 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" -#include "MOD_util.h" - #include "depsgraph_private.h" diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c index 45725d1c453..f3327a03f2c 100644 --- a/source/blender/modifiers/intern/MOD_shapekey.c +++ b/source/blender/modifiers/intern/MOD_shapekey.c @@ -44,7 +44,7 @@ #include "MOD_modifiertypes.h" -static void deformVerts(ModifierData *md, Object *ob, +static void deformVerts(ModifierData *UNUSED(md), Object *ob, DerivedMesh *UNUSED(derivedData), float (*vertexCos)[3], int numVerts, @@ -54,8 +54,9 @@ static void deformVerts(ModifierData *md, Object *ob, if (key && key->block.first) { int deformedVerts_tot; - BKE_key_evaluate_object_ex(md->scene, ob, &deformedVerts_tot, - (float *)vertexCos, sizeof(*vertexCos) * numVerts); + BKE_key_evaluate_object_ex( + ob, &deformedVerts_tot, + (float *)vertexCos, sizeof(*vertexCos) * numVerts); } } diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index 229f4911ab4..302013b9b07 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -38,7 +38,6 @@ #include "DNA_object_types.h" #include "BLI_math.h" -#include "BLI_string.h" #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 3314196b776..19761c43cf0 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -244,8 +244,6 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object } - - /* SimpleDeform */ static void initData(ModifierData *md) { diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index d43fa11cfb9..2bde963029a 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -79,8 +79,6 @@ #include "bmesh.h" -#include "MOD_util.h" - typedef struct { float mat[3][3]; /* Vert that edge is pointing away from, no relation to @@ -328,8 +326,7 @@ static bool build_hull(SkinOutput *so, Frame **frames, int totframe) return true; #else - (void)so, (void)frames, (void)totframe; - (void)skin_frame_find_contained_faces; + UNUSED_VARS(so, frames, totframe, skin_frame_find_contained_faces); return false; #endif } @@ -1117,7 +1114,7 @@ static BMFace *collapse_face_corners(BMesh *bm, BMFace *f, int n, orig_verts[i] = NULL; } else if (orig_verts[i] && - !BM_vert_in_face(vf, orig_verts[i])) + !BM_vert_in_face(orig_verts[i], vf)) { wrong_face = true; break; diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index fcd4cc96410..f260c0491ee 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -52,9 +52,6 @@ #include "depsgraph_private.h" -#include "MOD_util.h" - - static void initData(ModifierData *md) { SmokeModifierData *smd = (SmokeModifierData *) md; diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 4cae3d662db..592ab4194ec 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -31,7 +31,6 @@ #include "BKE_cdderivedmesh.h" #include "BKE_modifier.h" -#include "BKE_editmesh.h" #include "bmesh.h" #include "bmesh_tools.h" diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index bbc5e28ddf3..228c42e526c 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -32,7 +32,6 @@ #include <string.h> -#include "DNA_curve_types.h" #include "DNA_image_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -48,8 +47,6 @@ #include "BKE_image.h" #include "BKE_lattice.h" #include "BKE_mesh.h" -#include "BKE_displist.h" -#include "BKE_scene.h" #include "BKE_modifier.h" @@ -58,8 +55,6 @@ #include "MEM_guardedalloc.h" -#include "RE_shader_ext.h" - #ifdef OPENNL_THREADING_HACK #include "BLI_threads.h" #endif @@ -309,6 +304,7 @@ void modifier_type_init(ModifierTypeInfo *types[]) INIT_TYPE(MeshCache); INIT_TYPE(LaplacianDeform); INIT_TYPE(Wireframe); + INIT_TYPE(DataTransfer); INIT_TYPE(PointCache); #undef INIT_TYPE } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 2ff93efdb86..75a074a245a 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -49,7 +49,6 @@ #include "BKE_DerivedMesh.h" #include "MOD_modifiertypes.h" -#include "MOD_util.h" #include "MEM_guardedalloc.h" #include "depsgraph_private.h" diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index 744b6b62c2a..c9de1dc083d 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -34,7 +34,6 @@ #include "BLI_utildefines.h" #include "DNA_color_types.h" /* CurveMapping. */ -#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -43,11 +42,9 @@ #include "BKE_cdderivedmesh.h" #include "BKE_colortools.h" /* CurveMapping. */ #include "BKE_deform.h" -#include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_texture.h" /* Texture masking. */ -#include "depsgraph_private.h" #include "MEM_guardedalloc.h" #include "MOD_util.h" #include "MOD_weightvg_util.h" @@ -235,8 +232,6 @@ void weightvg_do_mask(int num, const int *indices, float *org_w, const float *ne } - - /* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group. * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and * defgrp_idx can then have any value). diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index f36abcceae0..5a6e958457e 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -34,7 +34,6 @@ #include "BLI_rand.h" #include "DNA_color_types.h" /* CurveMapping. */ -#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -48,7 +47,6 @@ #include "depsgraph_private.h" #include "MEM_guardedalloc.h" -#include "MOD_util.h" #include "MOD_weightvg_util.h" /************************************** diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index bdc1099d682..099d4c7116e 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -44,7 +44,6 @@ #include "depsgraph_private.h" #include "MEM_guardedalloc.h" -#include "MOD_util.h" #include "MOD_weightvg_util.h" diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 71d4742980e..766ffe529ab 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -47,7 +47,6 @@ #include "depsgraph_private.h" #include "MEM_guardedalloc.h" -#include "MOD_util.h" #include "MOD_weightvg_util.h" // #define USE_TIMEIT diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 7349ca9f9ef..8b611f9e6da 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -23,20 +23,14 @@ * \ingroup modifiers */ -#include "MEM_guardedalloc.h" - #include "DNA_object_types.h" -#include "DNA_meshdata_types.h" -#include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_string.h" #include "BKE_cdderivedmesh.h" #include "BKE_deform.h" #include "MOD_modifiertypes.h" -#include "MOD_util.h" #include "bmesh.h" #include "tools/bmesh_wireframe.h" diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index 6d5b85da569..e616680647e 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -36,11 +36,8 @@ #include "DNA_scene_types.h" #include "DNA_node_types.h" -#include "BLI_listbase.h" - #include "BLF_translation.h" -#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" @@ -50,8 +47,6 @@ #include "node_common.h" #include "node_util.h" -#include "PIL_time.h" - #include "RNA_access.h" #include "NOD_composite.h" @@ -236,11 +231,10 @@ void ntreeCompositExecTree(Scene *scene, bNodeTree *ntree, RenderData *rd, int r #ifdef WITH_COMPOSITOR COM_execute(rd, scene, ntree, rendering, view_settings, display_settings); #else - (void)scene, (void)ntree, (void)rd, (void)rendering, (void)do_preview; - (void)view_settings, (void)display_settings; + UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings); #endif - (void)do_preview; + UNUSED_VARS(do_preview); } /* *********************************************** */ diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.c b/source/blender/nodes/composite/nodes/node_composite_boxmask.c index 9cb0f1c75c7..0390eb43da0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_boxmask.c +++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.c @@ -66,7 +66,3 @@ void register_node_type_cmp_boxmask(void) nodeRegisterType(&ntype); } - - - - diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c index 65f2391983e..70e52d432cd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c +++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c @@ -29,11 +29,8 @@ * \ingroup cmpnodes */ - - #include "node_composite_util.h" - /* ******************* Color Balance ********************************* */ static bNodeSocketTemplate cmp_node_colorbalance_in[] = { {SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR}, diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c index 36c12693bdf..75e7fa8fbac 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.c +++ b/source/blender/nodes/composite/nodes/node_composite_common.c @@ -35,7 +35,6 @@ #include "node_composite_util.h" #include "NOD_common.h" #include "node_common.h" -#include "node_exec.h" #include "BKE_node.h" diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.c b/source/blender/nodes/composite/nodes/node_composite_composite.c index 41d417c2cb4..be9ed457150 100644 --- a/source/blender/nodes/composite/nodes/node_composite_composite.c +++ b/source/blender/nodes/composite/nodes/node_composite_composite.c @@ -31,10 +31,6 @@ #include "node_composite_util.h" -#include "BKE_context.h" - -#include "RNA_access.h" - /* **************** COMPOSITE ******************** */ static bNodeSocketTemplate cmp_node_composite_in[] = { { SOCK_RGBA, 1, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.c b/source/blender/nodes/composite/nodes/node_composite_defocus.c index ef670b760c2..a3311755717 100644 --- a/source/blender/nodes/composite/nodes/node_composite_defocus.c +++ b/source/blender/nodes/composite/nodes/node_composite_defocus.c @@ -33,10 +33,6 @@ #include <limits.h> -#include "BKE_context.h" - -#include "RNA_access.h" - /* ************ qdn: Defocus node ****************** */ static bNodeSocketTemplate cmp_node_defocus_in[] = { { SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 659e582dc1d..ecc02e732ce 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -39,8 +39,6 @@ #include "BKE_global.h" #include "BKE_main.h" -#include "RNA_access.h" - /* **************** IMAGE (and RenderResult, multilayer image) ******************** */ static bNodeSocketTemplate cmp_node_rlayers_out[] = { diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.c b/source/blender/nodes/composite/nodes/node_composite_keying.c index 6b5def1ea93..ba179bcbcd3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keying.c +++ b/source/blender/nodes/composite/nodes/node_composite_keying.c @@ -34,12 +34,8 @@ #include "DNA_movieclip_types.h" -#include "BKE_movieclip.h" - -#include "BLI_listbase.h" #include "BLI_math_base.h" #include "BLI_math_color.h" -#include "BLI_voronoi.h" #include "node_composite_util.h" diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.c b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.c index 9965b55e088..0cdf15c0412 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.c +++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.c @@ -30,16 +30,10 @@ * \ingroup cmpnodes */ -#include "BLF_translation.h" - #include "DNA_movieclip_types.h" -#include "BKE_movieclip.h" - -#include "BLI_listbase.h" #include "BLI_math_base.h" #include "BLI_math_color.h" -#include "BLI_voronoi.h" #include "node_composite_util.h" diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.c b/source/blender/nodes/composite/nodes/node_composite_mask.c index 83cea47db1b..dd05d5d83ad 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mask.c +++ b/source/blender/nodes/composite/nodes/node_composite_mask.c @@ -30,12 +30,8 @@ * \ingroup cmpnodes */ -#include "BLF_translation.h" - #include "DNA_mask_types.h" -#include "BKE_mask.h" - #include "node_composite_util.h" /* **************** Translate ******************** */ diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.c b/source/blender/nodes/composite/nodes/node_composite_movieclip.c index fc0d8060644..0fece9dd4f6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_movieclip.c +++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.c @@ -30,13 +30,10 @@ * \ingroup cmpnodes */ - #include "node_composite_util.h" #include "BKE_context.h" -#include "RNA_access.h" - static bNodeSocketTemplate cmp_node_movieclip_out[] = { { SOCK_RGBA, 0, N_("Image")}, { SOCK_FLOAT, 0, N_("Alpha")}, diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c index 1d411aafe68..9c54009d2f1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c +++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c @@ -34,8 +34,6 @@ #include "BKE_context.h" -#include "RNA_access.h" - /* **************** Translate ******************** */ static bNodeSocketTemplate cmp_node_moviedistortion_in[] = { diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c index 57c39b082b4..8e602c6179c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -40,9 +40,6 @@ #include "node_composite_util.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - #include "intern/openexr/openexr_multi.h" diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c index 28e2a2a205b..00791c278ae 100644 --- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c +++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c @@ -30,13 +30,10 @@ * \ingroup cmpnodes */ - #include "node_composite_util.h" #include "BKE_context.h" -#include "RNA_access.h" - /* **************** Translate ******************** */ static bNodeSocketTemplate cmp_node_stabilize2d_in[] = { diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index c58c9c902ec..0e250dc3aa4 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -29,7 +29,6 @@ * \ingroup nodes */ - #include <string.h> #include <stddef.h> @@ -43,15 +42,12 @@ #include "BKE_node.h" -#include "RNA_access.h" #include "RNA_types.h" #include "MEM_guardedalloc.h" #include "node_common.h" #include "node_util.h" -#include "node_exec.h" -#include "NOD_socket.h" #include "NOD_common.h" diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c index 2ac1a2c85f3..282567b797f 100644 --- a/source/blender/nodes/intern/node_socket.c +++ b/source/blender/nodes/intern/node_socket.c @@ -41,7 +41,6 @@ #include "BKE_node.h" #include "RNA_access.h" -#include "RNA_define.h" #include "RNA_types.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index bea1d0532e8..f18ee1d649f 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -41,16 +41,13 @@ #include "DNA_linestyle_types.h" #include "BLI_listbase.h" -#include "BLI_math.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLF_translation.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_linestyle.h" -#include "BKE_main.h" #include "BKE_node.h" #include "BKE_scene.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.c index 2478fb4d38c..b387529e456 100644 --- a/source/blender/nodes/shader/nodes/node_shader_background.c +++ b/source/blender/nodes/shader/nodes/node_shader_background.c @@ -40,6 +40,11 @@ static bNodeSocketTemplate sh_node_background_out[] = { { -1, 0, "" } }; +static int node_shader_gpu_background(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + return GPU_stack_link(mat, "node_background", in, out, GPU_builtin(GPU_VIEW_NORMAL)); +} + /* node type definition */ void register_node_type_sh_background(void) { @@ -50,6 +55,7 @@ void register_node_type_sh_background(void) node_type_socket_templates(&ntype, sh_node_background_in, sh_node_background_out); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, node_shader_gpu_background); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c index 3ce01ce03bf..de152ee45d1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.c +++ b/source/blender/nodes/shader/nodes/node_shader_bump.c @@ -29,11 +29,8 @@ * \ingroup shdnodes */ - - #include "node_shader_util.h" - /* **************** BUMP ******************** */ static bNodeSocketTemplate sh_node_bump_in[] = { { SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c index 9956fd712c8..503fe034754 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.c +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c @@ -41,6 +41,18 @@ static bNodeSocketTemplate sh_node_gamma_out[] = { { -1, 0, "" } }; +static void node_shader_exec_gamma(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +{ + float col[3]; + float gamma; + nodestack_get_vec(col, SOCK_VECTOR, in[0]); + nodestack_get_vec(&gamma, SOCK_FLOAT, in[1]); + + out[0]->vec[0] = col[0] > 0.0 ? pow(col[0], gamma) : col[0]; + out[0]->vec[1] = col[1] > 0.0 ? pow(col[1], gamma) : col[1]; + out[0]->vec[2] = col[2] > 0.0 ? pow(col[2], gamma) : col[2]; +} + static int node_shader_gpu_gamma(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { return GPU_stack_link(mat, "node_gamma", in, out); @@ -51,10 +63,11 @@ void register_node_type_sh_gamma(void) static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0); - node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_gamma); node_type_gpu(&ntype, node_shader_gpu_gamma); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c index eb018e6c7eb..be2e3dcd311 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.c +++ b/source/blender/nodes/shader/nodes/node_shader_math.c @@ -233,7 +233,7 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( static const char *names[] = {"math_add", "math_subtract", "math_multiply", "math_divide", "math_sine", "math_cosine", "math_tangent", "math_asin", "math_acos", "math_atan", "math_pow", "math_log", "math_min", "math_max", - "math_round", "math_less_than", "math_greater_than", "math_modulo", "math_absolute"}; + "math_round", "math_less_than", "math_greater_than", "math_modulo", "math_abs"}; switch (node->custom1) { case NODE_MATH_ADD: @@ -256,6 +256,7 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( case NODE_MATH_ACOS: case NODE_MATH_ATAN: case NODE_MATH_ROUND: + case NODE_MATH_ABS: if (in[0].hasinput || !in[1].hasinput) { /* use only first item and terminator */ GPUNodeStack tmp_in[2]; diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.c index fcd738f0b15..092fc201aa7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal.c @@ -61,12 +61,12 @@ static void node_shader_exec_normal(void *UNUSED(data), int UNUSED(thread), bNod static int gpu_shader_normal(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { GPUNodeLink *vec = GPU_uniform(out[0].vec); - int ret = GPU_stack_link(mat, "normal", in, out, vec); - if (ret && GPU_material_use_new_shading_nodes(mat)) { - float fac[3] = {1.0f, 0.0f, 0.0f}; - GPU_link(mat, "invert", GPU_uniform(fac), out[1].link, &out[1].link); + if (GPU_material_use_new_shading_nodes(mat)) { + return GPU_stack_link(mat, "normal_new_shading", in, out, vec); + } + else { + return GPU_stack_link(mat, "normal", in, out, vec); } - return ret; } void register_node_type_sh_normal(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c index c8e47c47c5f..ad7389fd56e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c @@ -35,6 +35,16 @@ static bNodeSocketTemplate sh_node_output_world_in[] = { { -1, 0, "" } }; +static int node_shader_gpu_output_world(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + GPUNodeLink *outlink; + + GPU_stack_link(mat, "node_output_world", in, out, &outlink); + GPU_material_output_link(mat, outlink); + + return 1; +} + /* node type definition */ void register_node_type_sh_output_world(void) { @@ -45,7 +55,8 @@ void register_node_type_sh_output_world(void) node_type_socket_templates(&ntype, sh_node_output_world_in, NULL); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); - + node_type_gpu(&ntype, node_shader_gpu_output_world); + /* Do not allow muting output node. */ node_type_internal_links(&ntype, NULL); diff --git a/source/blender/nodes/shader/nodes/node_shader_script.c b/source/blender/nodes/shader/nodes/node_shader_script.c index d5ed38297da..f640dd5ea13 100644 --- a/source/blender/nodes/shader/nodes/node_shader_script.c +++ b/source/blender/nodes/shader/nodes/node_shader_script.c @@ -31,8 +31,6 @@ #include "node_shader_util.h" -#include "BKE_idprop.h" - /* **************** Script ******************** */ static void init(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c index 605a3b9faa3..6375dcc8782 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c @@ -65,9 +65,9 @@ void register_node_type_sh_sepxyz(void) /* **************** COMBINE XYZ ******************** */ static bNodeSocketTemplate sh_node_combxyz_in[] = { - { SOCK_FLOAT, 1, N_("X"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_UNSIGNED}, - { SOCK_FLOAT, 1, N_("Y"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_UNSIGNED}, - { SOCK_FLOAT, 1, N_("Z"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_UNSIGNED}, + { SOCK_FLOAT, 1, N_("X"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f}, + { SOCK_FLOAT, 1, N_("Y"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f}, + { SOCK_FLOAT, 1, N_("Z"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f}, { -1, 0, "" } }; static bNodeSocketTemplate sh_node_combxyz_out[] = { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c index 781b1bb5a93..85eca6ae990 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c @@ -46,10 +46,18 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *UNUSED(node), bNod { GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ""); - - return GPU_stack_link(mat, "node_tex_coord", in, out, - GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), orco, mtface); + GPUMatType type = GPU_Material_get_type(mat); + + if (type == GPU_MATERIAL_TYPE_MESH) { + return GPU_stack_link(mat, "node_tex_coord", in, out, + GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), orco, mtface); + } + else { + return GPU_stack_link(mat, "node_tex_coord_background", in, out, + GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), orco, mtface); + } } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index dcb3ef3c8a0..8d6a77455bb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -27,8 +27,6 @@ #include "../node_shader_util.h" -#include "IMB_colormanagement.h" - /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_tex_environment_in[] = { @@ -67,13 +65,22 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE if (!ima) return GPU_stack_link(mat, "node_tex_environment_empty", in, out); - if (!in[0].link) - in[0].link = GPU_builtin(GPU_VIEW_POSITION); - + if (!in[0].link) { + GPUMatType type = GPU_Material_get_type(mat); + + if (type == GPU_MATERIAL_TYPE_MESH) + in[0].link = GPU_builtin(GPU_VIEW_POSITION); + else + GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link); + } + node_shader_gpu_tex_mapping(mat, node, in, out); - ret = GPU_stack_link(mat, "node_tex_environment", in, out, GPU_image(ima, iuser, isdata)); - + if (tex->projection == SHD_PROJ_EQUIRECTANGULAR) + ret = GPU_stack_link(mat, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata)); + else + ret = GPU_stack_link(mat, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata)); + if (ret) { ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c index 0a11ee4a9b6..62db5b70891 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -27,8 +27,6 @@ #include "../node_shader_util.h" -#include "IMB_colormanagement.h" - /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_tex_image_in[] = { diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c index d02d72563ba..5cdbaf444f8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_texture.c +++ b/source/blender/nodes/shader/nodes/node_shader_texture.c @@ -29,11 +29,8 @@ * \ingroup shdnodes */ - #include "DNA_texture_types.h" -#include "IMB_colormanagement.h" - #include "node_shader_util.h" /* **************** TEXTURE ******************** */ diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c index 48eb4cadba4..67342e1e836 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c +++ b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c @@ -27,8 +27,6 @@ #include "../node_shader_util.h" -#include "DNA_customdata_types.h" - /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_uvalongstroke_out[] = { diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c index f2ea2faa5a7..9e75d915d44 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c +++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c @@ -29,11 +29,8 @@ * \ingroup shdnodes */ - - #include "node_shader_util.h" - /* **************** VECTOR MATH ******************** */ static bNodeSocketTemplate sh_node_vect_math_in[] = { { SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 1b790f87faf..79923c5f7d5 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -43,9 +43,7 @@ #include "BLF_translation.h" #include "BKE_context.h" -#include "BKE_global.h" #include "BKE_linestyle.h" -#include "BKE_main.h" #include "BKE_node.h" #include "BKE_paint.h" @@ -57,7 +55,6 @@ #include "RNA_access.h" -#include "RE_pipeline.h" #include "RE_shader_ext.h" diff --git a/source/blender/pointcache/util/util_path.cpp b/source/blender/pointcache/util/util_path.cpp index 4605d25d24e..4d543fb87e6 100644 --- a/source/blender/pointcache/util/util_path.cpp +++ b/source/blender/pointcache/util/util_path.cpp @@ -27,6 +27,7 @@ extern "C" { #include "DNA_ID.h" #include "DNA_pointcache_types.h" +#include "BKE_appdir.h" #include "BKE_global.h" #include "BKE_main.h" } @@ -58,7 +59,7 @@ static int ptc_path(char *filename, const char *path, ID *id, bool is_external, else { /* use the temp path. this is weak but better then not using point cache at all */ /* temporary directory is assumed to exist and ALWAYS has a trailing slash */ - BLI_snprintf(filename, FILE_MAX, "%s" PTC_DIRECTORY, BLI_temp_dir_session()); + BLI_snprintf(filename, FILE_MAX, "%s" PTC_DIRECTORY, BKE_tempdir_session()); } return BLI_add_slash(filename); /* new strlen() */ diff --git a/source/blender/python/bmesh/bmesh_py_ops.c b/source/blender/python/bmesh/bmesh_py_ops.c index 4fc0160bbd6..ee96c859858 100644 --- a/source/blender/python/bmesh/bmesh_py_ops.c +++ b/source/blender/python/bmesh/bmesh_py_ops.c @@ -37,17 +37,12 @@ #include "MEM_guardedalloc.h" -#include "../generic/py_capi_utils.h" #include "bmesh.h" #include "bmesh_py_ops_call.h" #include "bmesh_py_ops.h" /* own include */ -#include "bmesh_py_types.h" - -#include "bmesh_py_utils.h" - /* bmesh operator 'bmesh.ops.*' callable types * ******************************************* */ static PyTypeObject bmesh_op_Type; diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 2c07df98973..84c1031a24a 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -39,11 +39,11 @@ #include "bmesh.h" -#include "bmesh_py_ops.h" #include "bmesh_py_ops_call.h" /* own include */ #include "bmesh_py_types.h" -#include "bmesh_py_utils.h" + +#include "../generic/python_utildefines.h" static int bpy_bm_op_as_py_error(BMesh *bm) { @@ -542,20 +542,20 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot) item = PyFloat_FromDouble((double)BMO_SLOT_AS_FLOAT(slot)); break; case BMO_OP_SLOT_MAT: - item = Matrix_CreatePyObject((float *)BMO_SLOT_AS_MATRIX(slot), 4, 4, Py_NEW, NULL); + item = Matrix_CreatePyObject((float *)BMO_SLOT_AS_MATRIX(slot), 4, 4, NULL); break; case BMO_OP_SLOT_VEC: - item = Vector_CreatePyObject(BMO_SLOT_AS_VECTOR(slot), slot->len, Py_NEW, NULL); + item = Vector_CreatePyObject(BMO_SLOT_AS_VECTOR(slot), slot->len, NULL); break; case BMO_OP_SLOT_PTR: BLI_assert(0); /* currently we don't have any pointer return values in use */ - item = (Py_INCREF(Py_None), Py_None); + item = Py_INCREF_RET(Py_None); break; case BMO_OP_SLOT_ELEMENT_BUF: { if (slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) { BMHeader *ele = BMO_slot_buffer_get_single(slot); - item = ele ? BPy_BMElem_CreatePyObject(bm, ele) : (Py_INCREF(Py_None), Py_None); + item = ele ? BPy_BMElem_CreatePyObject(bm, ele) : Py_INCREF_RET(Py_None); } else { const int size = slot->len; @@ -666,7 +666,7 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot) } case BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL: /* can't convert from these */ - item = (Py_INCREF(Py_None), Py_None); + item = Py_INCREF_RET(Py_None); break; } break; @@ -745,7 +745,7 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw) ret = NULL; /* exception raised above */ } else if (bmop.slots_out[0].slot_name == NULL) { - ret = (Py_INCREF(Py_None), Py_None); + ret = Py_INCREF_RET(Py_None); } else { /* build return value */ @@ -761,7 +761,7 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw) /* this function doesn't throw exceptions */ item = bpy_slot_to_py(bm, slot); if (item == NULL) { - item = (Py_INCREF(Py_None), Py_None); + item = Py_INCREF_RET(Py_None); } #if 1 diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 8c13a66bea0..1da5599ea29 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -44,6 +44,7 @@ #include "../mathutils/mathutils.h" #include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" #include "bmesh_py_types.h" /* own include */ #include "bmesh_py_types_select.h" @@ -342,7 +343,7 @@ PyDoc_STRVAR(bpy_bmvert_co_doc, static PyObject *bpy_bmvert_co_get(BPy_BMVert *self) { BPY_BM_CHECK_OBJ(self); - return Vector_CreatePyObject(self->v->co, 3, Py_WRAP, NULL); + return Vector_CreatePyObject_wrap(self->v->co, 3, NULL); } static int bpy_bmvert_co_set(BPy_BMVert *self, PyObject *value) @@ -364,7 +365,7 @@ PyDoc_STRVAR(bpy_bmvert_normal_doc, static PyObject *bpy_bmvert_normal_get(BPy_BMVert *self) { BPY_BM_CHECK_OBJ(self); - return Vector_CreatePyObject(self->v->no, 3, Py_WRAP, NULL); + return Vector_CreatePyObject_wrap(self->v->no, 3, NULL); } static int bpy_bmvert_normal_set(BPy_BMVert *self, PyObject *value) @@ -468,7 +469,7 @@ PyDoc_STRVAR(bpy_bmface_normal_doc, static PyObject *bpy_bmface_normal_get(BPy_BMFace *self) { BPY_BM_CHECK_OBJ(self); - return Vector_CreatePyObject(self->f->no, 3, Py_WRAP, NULL); + return Vector_CreatePyObject_wrap(self->f->no, 3, NULL); } static int bpy_bmface_normal_set(BPy_BMFace *self, PyObject *value) @@ -1530,7 +1531,7 @@ static PyObject *bpy_bmedge_calc_tangent(BPy_BMEdge *self, PyObject *args) BPY_BM_CHECK_OBJ(py_loop); /* no need to check if they are from the same mesh or even connected */ BM_edge_calc_face_tangent(self->e, py_loop->l, vec); - return Vector_CreatePyObject(vec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(vec, 3, NULL); } } @@ -1711,7 +1712,7 @@ static PyObject *bpy_bmface_calc_center_mean(BPy_BMFace *self) BPY_BM_CHECK_OBJ(self); BM_face_calc_center_mean(self->f, cent); - return Vector_CreatePyObject(cent, 3, Py_NEW, NULL); + return Vector_CreatePyObject(cent, 3, NULL); } PyDoc_STRVAR(bpy_bmface_calc_center_mean_weighted_doc, @@ -1728,7 +1729,7 @@ static PyObject *bpy_bmface_calc_center_mean_weighted(BPy_BMFace *self) BPY_BM_CHECK_OBJ(self); BM_face_calc_center_mean_weighted(self->f, cent); - return Vector_CreatePyObject(cent, 3, Py_NEW, NULL); + return Vector_CreatePyObject(cent, 3, NULL); } PyDoc_STRVAR(bpy_bmface_calc_center_bounds_doc, @@ -1745,7 +1746,7 @@ static PyObject *bpy_bmface_calc_center_bounds(BPy_BMFace *self) BPY_BM_CHECK_OBJ(self); BM_face_calc_center_bounds(self->f, cent); - return Vector_CreatePyObject(cent, 3, Py_NEW, NULL); + return Vector_CreatePyObject(cent, 3, NULL); } @@ -1849,7 +1850,7 @@ static PyObject *bpy_bmloop_calc_normal(BPy_BMLoop *self) float vec[3]; BPY_BM_CHECK_OBJ(self); BM_loop_calc_face_normal(self->l, vec); - return Vector_CreatePyObject(vec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(vec, 3, NULL); } PyDoc_STRVAR(bpy_bmloop_calc_tangent_doc, @@ -1866,7 +1867,7 @@ static PyObject *bpy_bmloop_calc_tangent(BPy_BMLoop *self) float vec[3]; BPY_BM_CHECK_OBJ(self); BM_loop_calc_face_tangent(self->l, vec); - return Vector_CreatePyObject(vec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(vec, 3, NULL); } /* Vert Seq @@ -2796,7 +2797,6 @@ static PyObject *bpy_bmelemseq_subscript_slice(BPy_BMElemSeq *self, Py_ssize_t s bool ok; PyObject *list; - PyObject *item; BMHeader *ele; BPY_BM_CHECK_OBJ(self); @@ -2821,9 +2821,7 @@ static PyObject *bpy_bmelemseq_subscript_slice(BPy_BMElemSeq *self, Py_ssize_t s /* add items until stop */ while ((ele = BM_iter_step(&iter))) { - item = BPy_BMElem_CreatePyObject(self->bm, ele); - PyList_Append(list, item); - Py_DECREF(item); + PyList_APPEND(list, BPy_BMElem_CreatePyObject(self->bm, ele)); count++; if (count == stop) { diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h index a2c2c312e71..66059a642d1 100644 --- a/source/blender/python/bmesh/bmesh_py_types.h +++ b/source/blender/python/bmesh/bmesh_py_types.h @@ -198,16 +198,17 @@ int bpy_bm_generic_valid_check_source(BMesh *bm_source, const char *error_prefi #define BPY_BM_IS_VALID(obj) (LIKELY((obj)->bm != NULL)) -#define BM_ITER_BPY_BM_SEQ(ele, iter, bpy_bmelemseq) \ - for (ele = BM_iter_new(iter, \ - (bpy_bmelemseq)->bm, \ - (bpy_bmelemseq)->itype, \ - (bpy_bmelemseq)->py_ele ? \ - ((BPy_BMElem *)(bpy_bmelemseq)->py_ele)->ele : \ - NULL \ - ); \ - ele; \ - ele = BM_iter_step(iter)) +#define BM_ITER_BPY_BM_SEQ(ele, iter, bpy_bmelemseq) \ + for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new( \ + iter, \ + (bpy_bmelemseq)->bm, \ + (bpy_bmelemseq)->itype, \ + (bpy_bmelemseq)->py_ele ? \ + ((BPy_BMElem *)(bpy_bmelemseq)->py_ele)->ele : \ + NULL \ + ); \ + ele; \ + BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter)) #ifdef __PY_CAPI_UTILS_H__ diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 6ecb01a8528..bfcd91ac72d 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -42,6 +42,7 @@ #include "bmesh_py_types_meshdata.h" #include "../mathutils/mathutils.h" +#include "../generic/python_utildefines.h" #include "BKE_customdata.h" @@ -483,8 +484,9 @@ static PyObject *bpy_bmlayercollection_items(BPy_BMLayerCollection *self) for (i = 0; tot-- > 0; index++) { item = PyTuple_New(2); - PyTuple_SET_ITEM(item, 0, PyUnicode_FromString(data->layers[index].name)); - PyTuple_SET_ITEM(item, 1, BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index)); + PyTuple_SET_ITEMS(item, + PyUnicode_FromString(data->layers[index].name), + BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index)); PyList_SET_ITEM(ret, i++, item); } @@ -559,7 +561,7 @@ static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject } } - return Py_INCREF(def), def; + return Py_INCREF_RET(def); } static struct PyMethodDef bpy_bmlayeritem_methods[] = { @@ -1014,7 +1016,7 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer) } case CD_SHAPEKEY: { - ret = Vector_CreatePyObject((float *)value, 3, Py_WRAP, NULL); + ret = Vector_CreatePyObject_wrap((float *)value, 3, NULL); break; } case CD_BWEIGHT: diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c index 3512dc76cef..94f38ffdec7 100644 --- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c @@ -45,6 +45,8 @@ #include "bmesh_py_types_meshdata.h" +#include "../generic/python_utildefines.h" + /* Mesh BMTexPoly * ************** */ @@ -150,7 +152,7 @@ PyDoc_STRVAR(bpy_bmloopuv_uv_doc, ); static PyObject *bpy_bmloopuv_uv_get(BPy_BMLoopUV *self, void *UNUSED(closure)) { - return Vector_CreatePyObject(self->data->uv, 2, Py_WRAP, NULL); + return Vector_CreatePyObject_wrap(self->data->uv, 2, NULL); } static int bpy_bmloopuv_uv_set(BPy_BMLoopUV *self, PyObject *value, void *UNUSED(closure)) @@ -263,7 +265,7 @@ PyDoc_STRVAR(bpy_bmvertskin_radius_doc, ); static PyObject *bpy_bmvertskin_radius_get(BPy_BMVertSkin *self, void *UNUSED(closure)) { - return Vector_CreatePyObject(self->data->radius, 2, Py_WRAP, NULL); + return Vector_CreatePyObject_wrap(self->data->radius, 2, NULL); } static int bpy_bmvertskin_radius_set(BPy_BMVertSkin *self, PyObject *value, void *UNUSED(closure)) @@ -369,7 +371,7 @@ PyObject *BPy_BMVertSkin_CreatePyObject(struct MVertSkin *mvertskin) static void mloopcol_to_float(const MLoopCol *mloopcol, float r_col[3]) { - rgb_uchar_to_float(r_col, (unsigned char *)&mloopcol->r); + rgb_uchar_to_float(r_col, (const unsigned char *)&mloopcol->r); } static void mloopcol_from_float(MLoopCol *mloopcol, const float col[3]) @@ -684,10 +686,9 @@ static PyObject *bpy_bmdeformvert_items(BPy_BMDeformVert *self) ret = PyList_New(self->data->totweight); for (i = 0; i < self->data->totweight; i++, dw++) { item = PyTuple_New(2); - - PyTuple_SET_ITEM(item, 0, PyLong_FromLong(dw->def_nr)); - PyTuple_SET_ITEM(item, 1, PyFloat_FromDouble(dw->weight)); - + PyTuple_SET_ITEMS(item, + PyLong_FromLong(dw->def_nr), + PyFloat_FromDouble(dw->weight)); PyList_SET_ITEM(ret, i, item); } @@ -721,7 +722,7 @@ static PyObject *bpy_bmdeformvert_get(BPy_BMDeformVert *self, PyObject *args) return PyFloat_FromDouble(dw->weight); } else { - return Py_INCREF(def), def; + return Py_INCREF_RET(def); } } } diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c index 71ca8440962..7b792e9f08e 100644 --- a/source/blender/python/bmesh/bmesh_py_types_select.c +++ b/source/blender/python/bmesh/bmesh_py_types_select.c @@ -43,11 +43,8 @@ #include "bmesh_py_types.h" #include "bmesh_py_types_select.h" - - #include "../generic/py_capi_utils.h" - -#include "bmesh_py_api.h" /* own include */ +#include "../generic/python_utildefines.h" PyDoc_STRVAR(bpy_bmeditselseq_active_doc, "The last selected element or None (read-only).\n\n:type: :class:`BMVert`, :class:`BMEdge` or :class:`BMFace`" @@ -197,7 +194,6 @@ static PyObject *bpy_bmeditselseq_subscript_slice(BPy_BMEditSelSeq *self, Py_ssi bool ok; PyObject *list; - PyObject *item; BMEditSelection *ese; BPY_BM_CHECK_OBJ(self); @@ -222,9 +218,7 @@ static PyObject *bpy_bmeditselseq_subscript_slice(BPy_BMEditSelSeq *self, Py_ssi /* add items until stop */ while ((ese = ese->next)) { - item = BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head); - PyList_Append(list, item); - Py_DECREF(item); + PyList_APPEND(list, BPy_BMElem_CreatePyObject(self->bm, &ese->ele->head)); count++; if (count == stop) { diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c index 7088036245a..0b667ab9029 100644 --- a/source/blender/python/bmesh/bmesh_py_utils.c +++ b/source/blender/python/bmesh/bmesh_py_utils.c @@ -42,6 +42,8 @@ #include "bmesh_py_types.h" #include "bmesh_py_utils.h" /* own include */ +#include "../generic/python_utildefines.h" + PyDoc_STRVAR(bpy_bm_utils_vert_collapse_edge_doc, ".. method:: vert_collapse_edge(vert, edge)\n" @@ -365,8 +367,9 @@ static PyObject *bpy_bm_utils_edge_split(PyObject *UNUSED(self), PyObject *args) if (v_new && e_new) { PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, BPy_BMEdge_CreatePyObject(bm, e_new)); - PyTuple_SET_ITEM(ret, 1, BPy_BMVert_CreatePyObject(bm, v_new)); + PyTuple_SET_ITEMS(ret, + BPy_BMEdge_CreatePyObject(bm, e_new), + BPy_BMVert_CreatePyObject(bm, v_new)); return ret; } else { @@ -524,8 +527,9 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args, if (f_new && l_new) { PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, BPy_BMFace_CreatePyObject(bm, f_new)); - PyTuple_SET_ITEM(ret, 1, BPy_BMLoop_CreatePyObject(bm, l_new)); + PyTuple_SET_ITEMS(ret, + BPy_BMFace_CreatePyObject(bm, f_new), + BPy_BMLoop_CreatePyObject(bm, l_new)); return ret; } else { diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 655542e320a..ed1ac7ceed9 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -33,6 +33,9 @@ #include "BLI_utildefines.h" +#include "../generic/python_utildefines.h" + + PyDoc_STRVAR(py_blf_position_doc, ".. function:: position(fontid, x, y, z)\n" "\n" @@ -183,8 +186,9 @@ static PyObject *py_blf_dimensions(PyObject *UNUSED(self), PyObject *args) BLF_width_and_height(fontid, text, INT_MAX, &r_width, &r_height); ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(r_width)); - PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(r_height)); + PyTuple_SET_ITEMS(ret, + PyFloat_FromDouble(r_width), + PyFloat_FromDouble(r_height)); return ret; } diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c index 2d19fdb87b3..b0539607bdc 100644 --- a/source/blender/python/generic/bpy_internal_import.c +++ b/source/blender/python/generic/bpy_internal_import.c @@ -265,7 +265,7 @@ PyObject *bpy_text_reimport(PyObject *module, int *found) } /* make into a module */ - return PyImport_ExecCodeModule((char *)name, text->compiled); + return PyImport_ExecCodeModule(name, text->compiled); } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index b6790de8ddf..1f35572a483 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -33,16 +33,17 @@ #include "idprop_py_api.h" - #include "BKE_idprop.h" - #define USE_STRING_COERCE #ifdef USE_STRING_COERCE #include "py_capi_utils.h" #endif +#include "../generic/python_utildefines.h" + + /*********************** ID Property Main Wrapper Stuff ***************/ /* ---------------------------------------------------------------------------- @@ -296,10 +297,10 @@ static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item) } /* returns NULL on success, error string on failure */ -static int idp_sequence_type(PyObject *seq_fast) +static char idp_sequence_type(PyObject *seq_fast) { PyObject *item; - int type = IDP_INT; + char type = IDP_INT; Py_ssize_t i, len = PySequence_Fast_GET_SIZE(seq_fast); for (i = 0; i < len; i++) { @@ -376,7 +377,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, else if (PyUnicode_Check(ob)) { #ifdef USE_STRING_COERCE PyObject *value_coerce = NULL; - val.string.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce); + val.string.str = PyC_UnicodeAsByte(ob, &value_coerce); val.string.subtype = IDP_STRING_SUB_UTF8; prop = IDP_New(IDP_STRING, &val, name); Py_XDECREF(value_coerce); @@ -403,7 +404,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, return false; } - if ((val.array.type = idp_sequence_type(ob_seq_fast)) == -1) { + if ((val.array.type = idp_sequence_type(ob_seq_fast)) == (char)-1) { Py_DECREF(ob_seq_fast); PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays"); return false; @@ -512,7 +513,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, else { IDProperty *prop_exist; - /* avoid freeing when types match incase they are referenced by the UI, see: T37073 + /* avoid freeing when types match in case they are referenced by the UI, see: T37073 * obviously this isn't a complete solution, but helps for common cases. */ prop_exist = IDP_GetPropertyFromGroup(group, prop->name); if ((prop_exist != NULL) && @@ -746,10 +747,9 @@ static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, printf("%s: ID Property Error found and corrected!\n", func); - /*fill rest of list with valid references to None*/ + /* fill rest of list with valid references to None */ for (j = len; j < prop->len; j++) { - Py_INCREF(Py_None); - PyList_SET_ITEM(seq, j, Py_None); + PyList_SET_ITEM(seq, j, Py_INCREF_RET(Py_None)); } /*set correct group length*/ @@ -808,8 +808,9 @@ PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop) for (i = 0, loop = prop->data.group.first; loop; loop = loop->next, i++) { PyObject *item = PyTuple_New(2); - PyTuple_SET_ITEM(item, 0, PyUnicode_FromString(loop->name)); - PyTuple_SET_ITEM(item, 1, BPy_IDGroup_WrapData(id, loop, prop)); + PyTuple_SET_ITEMS(item, + PyUnicode_FromString(loop->name), + BPy_IDGroup_WrapData(id, loop, prop)); PyList_SET_ITEM(seq, i, item); } @@ -1406,8 +1407,9 @@ static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self) if (self->mode == IDPROP_ITER_ITEMS) { ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyUnicode_FromString(cur->name)); - PyTuple_SET_ITEM(ret, 1, BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop)); + PyTuple_SET_ITEMS(ret, + PyUnicode_FromString(cur->name), + BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop)); return ret; } else { diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 36ae30ada22..92ac82508e5 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -37,6 +37,8 @@ #include "py_capi_utils.h" +#include "../generic/python_utildefines.h" + /* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */ #include "BLI_string_utf8.h" @@ -178,6 +180,17 @@ void PyC_Tuple_Fill(PyObject *tuple, PyObject *value) } } +void PyC_List_Fill(PyObject *list, PyObject *value) +{ + unsigned int tot = PyList_GET_SIZE(list); + unsigned int i; + + for (i = 0; i < tot; i++) { + PyList_SET_ITEM(list, i, value); + Py_INCREF(value); + } +} + /* for debugging */ void PyC_ObSpit(const char *name, PyObject *var) { @@ -568,7 +581,7 @@ void PyC_MainModule_Restore(PyObject *main_mod) Py_XDECREF(main_mod); } -/* must be called before Py_Initialize, expects output of BLI_get_folder(BLENDER_PYTHON, NULL) */ +/* must be called before Py_Initialize, expects output of BKE_appdir_folder_id(BLENDER_PYTHON, NULL) */ void PyC_SetHomePath(const char *py_path_bundle) { if (py_path_bundle == NULL) { @@ -664,8 +677,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) PyErr_Print(); PyErr_Clear(); - PyList_SET_ITEM(values, i, Py_None); /* hold user */ - Py_INCREF(Py_None); + PyList_SET_ITEM(values, i, Py_INCREF_RET(Py_None)); /* hold user */ sizes[i] = 0; } diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 559a8e15678..398d7da9179 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -42,6 +42,7 @@ int PyC_AsArray(void *array, PyObject *value, const Py_ssize_t length, PyObject * PyC_FromArray(const void *array, int length, const PyTypeObject *type, const bool is_double, const char *error_prefix); void PyC_Tuple_Fill(PyObject *tuple, PyObject *value); +void PyC_List_Fill(PyObject *list, PyObject *value); /* follow http://www.python.org/dev/peps/pep-0383/ */ PyObject * PyC_UnicodeFromByte(const char *str); diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h new file mode 100644 index 00000000000..f7d3e7a8b4a --- /dev/null +++ b/source/blender/python/generic/python_utildefines.h @@ -0,0 +1,60 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/python_utildefines.h + * \ingroup pygen + * \brief header-only utilities + * \note light addition to Python.h, use py_capi_utils.h for larger features. + */ + +#ifndef __PYTHON_UTILDEFINES_H__ +#define __PYTHON_UTILDEFINES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PyTuple_SET_ITEMS(op_arg, ...) \ +{ \ + PyTupleObject *op = (PyTupleObject *)op_arg; \ + PyObject **ob_items = op->ob_item; \ + CHECK_TYPE_ANY(op_arg, PyObject *, PyTupleObject *); \ + BLI_assert(_VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \ + ARRAY_SET_ITEMS(ob_items, __VA_ARGS__); \ +} (void)0 + +/* wrap Py_INCREF & return the result, + * use sparingly to avoid comma operator or temp var assignment */ +BLI_INLINE PyObject *Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; } + +/* append & transfer ownership to the list, avoids inline Py_DECREF all over (which is quite a large macro) */ +BLI_INLINE int PyList_APPEND(PyObject *op, PyObject *v) +{ + int ret = PyList_Append(op, v); + Py_DecRef(v); + return ret; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __PYTHON_UTILDEFINES_H__ */ + diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 134e718bce5..ec3c017a7ed 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -31,10 +31,9 @@ #include <Python.h> #include "BLI_utildefines.h" -#include "BLI_path_util.h" #include "BLI_string.h" -#include "BKE_main.h" +#include "BKE_appdir.h" #include "BKE_global.h" /* XXX, G.main only */ #include "BKE_blender.h" #include "BKE_bpath.h" @@ -52,15 +51,10 @@ #include "bpy_utils_units.h" #include "../generic/py_capi_utils.h" - -#include "MEM_guardedalloc.h" +#include "../generic/python_utildefines.h" /* external util modules */ #include "../generic/idprop_py_api.h" -#include "../generic/bgl.h" -#include "../generic/blf_py_api.h" -#include "../generic/blf_py_api.h" -#include "../mathutils/mathutils.h" #ifdef WITH_FREESTYLE # include "BPy_Freestyle.h" @@ -82,11 +76,11 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self)) PyObject *item; const char *path; - path = BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, NULL); + path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, NULL); item = PyC_UnicodeFromByte(path ? path : ""); BLI_assert(item != NULL); PyTuple_SET_ITEM(ret, 0, item); - path = BLI_get_folder(BLENDER_USER_SCRIPTS, NULL); + path = BKE_appdir_folder_id(BLENDER_USER_SCRIPTS, NULL); item = PyC_UnicodeFromByte(path ? path : ""); BLI_assert(item != NULL); PyTuple_SET_ITEM(ret, 1, item); @@ -96,10 +90,7 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self)) static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src) { - PyObject *list = (PyObject *)userdata; - PyObject *item = PyC_UnicodeFromByte(path_src); - PyList_Append(list, item); - Py_DECREF(item); + PyList_APPEND((PyObject *)userdata, PyC_UnicodeFromByte(path_src)); return false; /* never edits the path */ } @@ -168,11 +159,11 @@ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObj return NULL; } - /* same logic as BLI_get_folder_create(), but best leave it up to the script author to create */ - path = BLI_get_folder(folder_id, subdir); + /* same logic as BKE_appdir_folder_id_create(), but best leave it up to the script author to create */ + path = BKE_appdir_folder_id(folder_id, subdir); if (!path) - path = BLI_get_user_folder_notest(folder_id, subdir); + path = BKE_appdir_folder_id_user_notest(folder_id, subdir); return PyC_UnicodeFromByte(path ? path : ""); } @@ -211,7 +202,7 @@ static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObj return NULL; } - path = BLI_get_folder_version(folder_id, (major * 100) + minor, false); + path = BKE_appdir_folder_id_version(folder_id, (major * 100) + minor, false); return PyC_UnicodeFromByte(path ? path : ""); } @@ -296,7 +287,7 @@ void BPy_init_modules(void) PyObject *mod; /* Needs to be first since this dir is needed for future modules */ - const char * const modpath = BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, "modules"); + const char * const modpath = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "modules"); if (modpath) { // printf("bpy: found module path '%s'.\n", modpath); PyObject *sys_path = PySys_GetObject("path"); /* borrow */ diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 16cdd44ce38..678fd62ae89 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -44,13 +44,13 @@ #include "bpy_driver.h" #include "BLI_utildefines.h" -#include "BLI_path_util.h" +#include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_global.h" -#include "structseq.h" #include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" #ifdef BUILD_DATE extern char build_date[]; @@ -135,7 +135,7 @@ static PyObject *make_app_info(void) SetStrItem(STRINGIFY(BLENDER_VERSION_CHAR)); SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE)); - SetStrItem(BLI_program_path()); + SetStrItem(BKE_appdir_program_path()); SetObjItem(PyBool_FromLong(G.background)); /* build info, use bytes since we can't assume _any_ encoding: @@ -250,7 +250,7 @@ PyDoc_STRVAR(bpy_app_tempdir_doc, ); static PyObject *bpy_app_tempdir_get(PyObject *UNUSED(self), void *UNUSED(closure)) { - return PyC_UnicodeFromByte(BLI_temp_dir_session()); + return PyC_UnicodeFromByte(BKE_tempdir_session()); } PyDoc_STRVAR(bpy_app_driver_dict_doc, @@ -265,8 +265,7 @@ static PyObject *bpy_app_driver_dict_get(PyObject *UNUSED(self), void *UNUSED(cl } } - Py_INCREF(bpy_pydriver_Dict); - return bpy_pydriver_Dict; + return Py_INCREF_RET(bpy_pydriver_Dict); } static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void *UNUSED(closure)) diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 44da322efc0..6a8b0b065c2 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -37,6 +37,8 @@ #include "bpy_rna.h" #include "bpy_app_handlers.h" +#include "../generic/python_utildefines.h" + #include "BPY_extern.h" void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg); @@ -44,23 +46,24 @@ void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg); static PyTypeObject BlenderAppCbType; static PyStructSequence_Field app_cb_info_fields[] = { - {(char *)"frame_change_pre", (char *)"Callback list - on frame change for playback and rendering (before)"}, - {(char *)"frame_change_post", (char *)"Callback list - on frame change for playback and rendering (after)"}, - {(char *)"render_pre", (char *)"Callback list - on render (before)"}, - {(char *)"render_post", (char *)"Callback list - on render (after)"}, - {(char *)"render_stats", (char *)"Callback list - on printing render statistics"}, - {(char *)"render_init", (char *)"Callback list - on initialization of a render job"}, - {(char *)"render_complete", (char *)"Callback list - on completion of render job"}, - {(char *)"render_cancel", (char *)"Callback list - on canceling a render job"}, - {(char *)"load_pre", (char *)"Callback list - on loading a new blend file (before)"}, - {(char *)"load_post", (char *)"Callback list - on loading a new blend file (after)"}, - {(char *)"save_pre", (char *)"Callback list - on saving a blend file (before)"}, - {(char *)"save_post", (char *)"Callback list - on saving a blend file (after)"}, - {(char *)"scene_update_pre", (char *)"Callback list - on updating the scenes data (before)"}, - {(char *)"scene_update_post", (char *)"Callback list - on updating the scenes data (after)"}, - {(char *)"game_pre", (char *)"Callback list - on starting the game engine"}, - {(char *)"game_post", (char *)"Callback list - on ending the game engine"}, - {(char *)"version_update", (char *)"Callback list - on ending the versioning code"}, + {(char *)"frame_change_pre", (char *)"on frame change for playback and rendering (before)"}, + {(char *)"frame_change_post", (char *)"on frame change for playback and rendering (after)"}, + {(char *)"render_pre", (char *)"on render (before)"}, + {(char *)"render_post", (char *)"on render (after)"}, + {(char *)"render_write", (char *)"on writing a render frame (directly after the frame is written)"}, + {(char *)"render_stats", (char *)"on printing render statistics"}, + {(char *)"render_init", (char *)"on initialization of a render job"}, + {(char *)"render_complete", (char *)"on completion of render job"}, + {(char *)"render_cancel", (char *)"on canceling a render job"}, + {(char *)"load_pre", (char *)"on loading a new blend file (before)"}, + {(char *)"load_post", (char *)"on loading a new blend file (after)"}, + {(char *)"save_pre", (char *)"on saving a blend file (before)"}, + {(char *)"save_post", (char *)"on saving a blend file (after)"}, + {(char *)"scene_update_pre", (char *)"on updating the scenes data (before)"}, + {(char *)"scene_update_post", (char *)"on updating the scenes data (after)"}, + {(char *)"game_pre", (char *)"on starting the game engine"}, + {(char *)"game_post", (char *)"on ending the game engine"}, + {(char *)"version_update", (char *)"on ending the versioning code"}, /* sets the permanent tag */ # define APP_CB_OTHER_FIELDS 1 @@ -71,7 +74,7 @@ static PyStructSequence_Field app_cb_info_fields[] = { static PyStructSequence_Desc app_cb_info_desc = { (char *)"bpy.app.handlers", /* name */ - (char *)"This module contains callbacks", /* doc */ + (char *)"This module contains callback lists", /* doc */ app_cb_info_fields, /* fields */ ARRAY_SIZE(app_cb_info_fields) - 1 }; @@ -305,8 +308,7 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *ar PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&id_ptr)); } else { - PyTuple_SET_ITEM(args, 0, Py_None); - Py_INCREF(Py_None); + PyTuple_SET_ITEM(args, 0, Py_INCREF_RET(Py_None)); } /* Iterate the list and run the callbacks diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c index 0114e8e65e4..1a56c0f7c59 100644 --- a/source/blender/python/intern/bpy_app_translations.c +++ b/source/blender/python/intern/bpy_app_translations.c @@ -44,8 +44,8 @@ #include "BLF_translation.h" #include "RNA_types.h" -#include "RNA_access.h" +#include "../generic/python_utildefines.h" typedef struct { @@ -242,12 +242,9 @@ static void _build_translations_cache(PyObject *py_messages, const char *locale) } /* Clean up! */ - if (language) - MEM_freeN(language); - if (language_country) - MEM_freeN(language_country); - if (language_variant) - MEM_freeN(language_variant); + MEM_SAFE_FREE(language); + MEM_SAFE_FREE(language_country); + MEM_SAFE_FREE(language_variant); } const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid) @@ -410,7 +407,7 @@ static PyObject *app_translations_contexts_make(void) } #define SetObjString(item) PyStructSequence_SET_ITEM(translations_contexts, pos++, PyUnicode_FromString((item))) -#define SetObjNone() Py_INCREF(Py_None); PyStructSequence_SET_ITEM(translations_contexts, pos++, Py_None) +#define SetObjNone() PyStructSequence_SET_ITEM(translations_contexts, pos++, Py_INCREF_RET(Py_None)) for (ctxt = _contexts; ctxt->c_id; ctxt++) { if (ctxt->value) { @@ -520,9 +517,7 @@ static PyObject *_py_pgettext(PyObject *args, PyObject *kw, const char *(*_pgett return NULL; } - Py_INCREF(msgid); - - return msgid; + return Py_INCREF_RET(msgid); #endif } @@ -632,6 +627,7 @@ PyDoc_STRVAR(app_translations_locale_explode_doc, ); static PyObject *app_translations_locale_explode(BlenderAppTranslations *UNUSED(self), PyObject *args, PyObject *kw) { + PyObject *ret_tuple; static const char *kwlist[] = {"locale", NULL}; const char *locale; char *language, *country, *variant, *language_country, *language_variant; @@ -642,7 +638,15 @@ static PyObject *app_translations_locale_explode(BlenderAppTranslations *UNUSED( BLF_locale_explode(locale, &language, &country, &variant, &language_country, &language_variant); - return Py_BuildValue("sssss", language, country, variant, language_country, language_variant); + ret_tuple = Py_BuildValue("sssss", language, country, variant, language_country, language_variant); + + MEM_SAFE_FREE(language); + MEM_SAFE_FREE(country); + MEM_SAFE_FREE(variant); + MEM_SAFE_FREE(language_country); + MEM_SAFE_FREE(language_variant); + + return ret_tuple; } static PyMethodDef app_translations_methods[] = { diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index d46c95a25b8..5b4db89a41a 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -63,6 +63,7 @@ #include "DNA_text_types.h" +#include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_text.h" #include "BKE_main.h" @@ -243,11 +244,11 @@ void BPY_python_start(int argc, const char **argv) { #ifndef WITH_PYTHON_MODULE PyThreadState *py_tstate = NULL; - const char *py_path_bundle = BLI_get_folder(BLENDER_SYSTEM_PYTHON, NULL); + const char *py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL); /* not essential but nice to set our name */ static wchar_t program_path_wchar[FILE_MAX]; /* python holds a reference */ - BLI_strncpy_wchar_from_utf8(program_path_wchar, BLI_program_path(), ARRAY_SIZE(program_path_wchar)); + BLI_strncpy_wchar_from_utf8(program_path_wchar, BKE_appdir_program_path(), ARRAY_SIZE(program_path_wchar)); Py_SetProgramName(program_path_wchar); /* must run before python initializes */ diff --git a/source/blender/python/intern/bpy_library.c b/source/blender/python/intern/bpy_library.c index 3d7d08024c7..3b95b99a0a1 100644 --- a/source/blender/python/intern/bpy_library.c +++ b/source/blender/python/intern/bpy_library.c @@ -53,6 +53,8 @@ #include "bpy_util.h" #include "bpy_library.h" +#include "../generic/python_utildefines.h" + /* nifty feature. swap out strings for RNA data */ #define USE_RNA_DATABLOCKS @@ -274,10 +276,9 @@ static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args)) /* return pair */ ret = PyTuple_New(2); - - PyTuple_SET_ITEM(ret, 0, (PyObject *)self_from); - - PyTuple_SET_ITEM(ret, 1, (PyObject *)self); + PyTuple_SET_ITEMS(ret, + (PyObject *)self_from, + (PyObject *)self); Py_INCREF(self); BKE_reports_clear(&reports); @@ -362,8 +363,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* just warn for now */ /* err = -1; */ #ifdef USE_RNA_DATABLOCKS - item = Py_None; - Py_INCREF(item); + item = Py_INCREF_RET(Py_None); #endif } @@ -375,8 +375,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) PyErr_Clear(); #ifdef USE_RNA_DATABLOCKS - item = Py_None; - Py_INCREF(item); + item = Py_INCREF_RET(Py_None); #endif } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 86282f251c3..aad47d14b7c 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -44,6 +44,7 @@ #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */ #include "bpy_util.h" #include "../generic/bpy_internal_import.h" +#include "../generic/python_utildefines.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -127,9 +128,8 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) /* restore with original context dict, probably NULL but need this for nested operator calls */ Py_XDECREF(context_dict); CTX_py_dict_set(C, (void *)context_dict_back); - - Py_INCREF(ret); - return ret; + + return Py_INCREF_RET(ret); } static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index b0232a4211c..b536e91bca8 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -64,6 +64,7 @@ static EnumPropertyItem property_flag_items[] = { {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""}, {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""}, {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to eachother", ""}, + {PROP_TEXTEDIT_UPDATE, "TEXTEDIT_UPDATE", 0, "Update on every keystroke in textedit 'mode'", ""}, {0, NULL, 0, NULL, NULL}}; #define BPY_PROPDEF_OPTIONS_DOC \ diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index f6e97d6a2d8..592150239be 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -76,10 +76,7 @@ #include "../generic/idprop_py_api.h" /* for IDprop lookups */ #include "../generic/py_capi_utils.h" - -#ifdef WITH_INTERNATIONAL -# include "BLF_translation.h" -#endif +#include "../generic/python_utildefines.h" #define USE_PEDANTIC_WRITE #define USE_MATHUTILS @@ -641,7 +638,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) case PROP_ALL_VECTOR_SUBTYPES: if (len >= 2 && len <= 4) { if (is_thick) { - ret = Vector_CreatePyObject(NULL, len, Py_NEW, NULL); + ret = Vector_CreatePyObject(NULL, len, NULL); RNA_property_float_get_array(ptr, prop, ((VectorObject *)ret)->vec); } else { @@ -654,7 +651,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) case PROP_MATRIX: if (len == 16) { if (is_thick) { - ret = Matrix_CreatePyObject(NULL, 4, 4, Py_NEW, NULL); + ret = Matrix_CreatePyObject(NULL, 4, 4, NULL); RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix); } else { @@ -665,7 +662,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) } else if (len == 9) { if (is_thick) { - ret = Matrix_CreatePyObject(NULL, 3, 3, Py_NEW, NULL); + ret = Matrix_CreatePyObject(NULL, 3, 3, NULL); RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix); } else { @@ -683,7 +680,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) PropertyRNA *prop_eul_order = NULL; short order = pyrna_rotation_euler_order_get(ptr, &prop_eul_order, EULER_ORDER_XYZ); - ret = Euler_CreatePyObject(NULL, order, Py_NEW, NULL); /* TODO, get order from RNA */ + ret = Euler_CreatePyObject(NULL, order, NULL); /* TODO, get order from RNA */ RNA_property_float_get_array(ptr, prop, ((EulerObject *)ret)->eul); } else { @@ -695,7 +692,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) } else if (len == 4) { if (is_thick) { - ret = Quaternion_CreatePyObject(NULL, Py_NEW, NULL); + ret = Quaternion_CreatePyObject(NULL, NULL); RNA_property_float_get_array(ptr, prop, ((QuaternionObject *)ret)->quat); } else { @@ -709,7 +706,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) case PROP_COLOR_GAMMA: if (len == 3) { /* color */ if (is_thick) { - ret = Color_CreatePyObject(NULL, Py_NEW, NULL); + ret = Color_CreatePyObject(NULL, NULL); RNA_property_float_get_array(ptr, prop, ((ColorObject *)ret)->col); } else { @@ -809,7 +806,7 @@ static PyObject *pyrna_struct_richcmp(PyObject *a, PyObject *b, int op) return NULL; } - return Py_INCREF(res), res; + return Py_INCREF_RET(res); } static PyObject *pyrna_prop_richcmp(PyObject *a, PyObject *b, int op) @@ -839,7 +836,7 @@ static PyObject *pyrna_prop_richcmp(PyObject *a, PyObject *b, int op) return NULL; } - return Py_INCREF(res), res; + return Py_INCREF_RET(res); } /*----------------------repr--------------------------------------------*/ @@ -2305,8 +2302,7 @@ static PyObject *pyrna_prop_collection_subscript_slice(BPy_PropertyRNA *self, Py RNA_property_collection_next(&rna_macro_iter)) { item = pyrna_struct_CreatePyObject(&rna_macro_iter.ptr); - PyList_Append(list, item); - Py_DECREF(item); + PyList_APPEND(list, item); count++; if (count == stop) { @@ -3430,7 +3426,6 @@ static void pyrna_dir_members_py(PyObject *list, PyObject *self) static void pyrna_dir_members_rna(PyObject *list, PointerRNA *ptr) { - PyObject *pystring; const char *idname; /* for looping over attrs and funcs */ @@ -3446,10 +3441,7 @@ static void pyrna_dir_members_rna(PyObject *list, PointerRNA *ptr) FunctionRNA *func = itemptr.data; if (RNA_function_defined(func)) { idname = RNA_function_identifier(itemptr.data); - - pystring = PyUnicode_FromString(idname); - PyList_Append(list, pystring); - Py_DECREF(pystring); + PyList_APPEND(list, PyUnicode_FromString(idname)); } } RNA_PROP_END; @@ -3469,9 +3461,7 @@ static void pyrna_dir_members_rna(PyObject *list, PointerRNA *ptr) nameptr = RNA_struct_name_get_alloc(&itemptr, name, sizeof(name), &namelen); if (nameptr) { - pystring = PyUnicode_FromStringAndSize(nameptr, namelen); - PyList_Append(list, pystring); - Py_DECREF(pystring); + PyList_APPEND(list, PyUnicode_FromStringAndSize(nameptr, namelen)); if (name != nameptr) { MEM_freeN(nameptr); @@ -3486,7 +3476,6 @@ static void pyrna_dir_members_rna(PyObject *list, PointerRNA *ptr) static PyObject *pyrna_struct_dir(BPy_StructRNA *self) { PyObject *ret; - PyObject *pystring; PYRNA_STRUCT_CHECK_OBJ(self); @@ -3505,9 +3494,7 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self) LinkData *link; for (link = lb.first; link; link = link->next) { - pystring = PyUnicode_FromString(link->data); - PyList_Append(ret, pystring); - Py_DECREF(pystring); + PyList_APPEND(ret, PyUnicode_FromString(link->data)); } BLI_freelistN(&lb); @@ -3587,14 +3574,11 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname) case CTX_DATA_TYPE_COLLECTION: { CollectionPointerLink *link; - PyObject *linkptr; ret = PyList_New(0); for (link = newlb.first; link; link = link->next) { - linkptr = pyrna_struct_CreatePyObject(&link->ptr); - PyList_Append(ret, linkptr); - Py_DECREF(linkptr); + PyList_APPEND(ret, pyrna_struct_CreatePyObject(&link->ptr)); } break; } @@ -4101,7 +4085,6 @@ PyDoc_STRVAR(pyrna_prop_collection_keys_doc, static PyObject *pyrna_prop_collection_keys(BPy_PropertyRNA *self) { PyObject *ret = PyList_New(0); - PyObject *item; char name[256], *nameptr; int namelen; @@ -4110,11 +4093,7 @@ static PyObject *pyrna_prop_collection_keys(BPy_PropertyRNA *self) nameptr = RNA_struct_name_get_alloc(&itemptr, name, sizeof(name), &namelen); if (nameptr) { - /* add to python list */ - item = PyUnicode_FromStringAndSize(nameptr, namelen); - PyList_Append(ret, item); - Py_DECREF(item); - /* done */ + PyList_APPEND(ret, PyUnicode_FromStringAndSize(nameptr, namelen)); if (name != nameptr) { MEM_freeN(nameptr); @@ -4160,8 +4139,7 @@ static PyObject *pyrna_prop_collection_items(BPy_PropertyRNA *self) } PyTuple_SET_ITEM(item, 1, pyrna_struct_CreatePyObject(&itemptr)); - PyList_Append(ret, item); - Py_DECREF(item); + PyList_APPEND(ret, item); i++; } @@ -4227,7 +4205,7 @@ static PyObject *pyrna_struct_get(BPy_StructRNA *self, PyObject *args) } } - return Py_INCREF(def), def; + return Py_INCREF_RET(def); } PyDoc_STRVAR(pyrna_struct_as_pointer_doc, @@ -4289,7 +4267,7 @@ static PyObject *pyrna_prop_collection_get(BPy_PropertyRNA *self, PyObject *args Py_TYPE(key_ob)->tp_name); } - return Py_INCREF(def), def; + return Py_INCREF_RET(def); } PyDoc_STRVAR(pyrna_prop_collection_find_doc, @@ -4802,8 +4780,7 @@ static PyObject *pyrna_prop_new(PyTypeObject *type, PyObject *args, PyObject *UN return NULL; if (type == Py_TYPE(base)) { - Py_INCREF(base); - return (PyObject *)base; + return Py_INCREF_RET((PyObject *)base); } else if (PyType_IsSubtype(type, &pyrna_prop_Type)) { BPy_PropertyRNA *ret = (BPy_PropertyRNA *) type->tp_alloc(type, 0); @@ -4855,15 +4832,15 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat switch (RNA_property_subtype(prop)) { #ifdef USE_MATHUTILS case PROP_ALL_VECTOR_SUBTYPES: - ret = Vector_CreatePyObject(data, len, Py_NEW, NULL); + ret = Vector_CreatePyObject(data, len, NULL); break; case PROP_MATRIX: if (len == 16) { - ret = Matrix_CreatePyObject(data, 4, 4, Py_NEW, NULL); + ret = Matrix_CreatePyObject(data, 4, 4, NULL); break; } else if (len == 9) { - ret = Matrix_CreatePyObject(data, 3, 3, Py_NEW, NULL); + ret = Matrix_CreatePyObject(data, 3, 3, NULL); break; } /* fall-through */ @@ -4971,14 +4948,11 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat { ListBase *lb = (ListBase *)data; CollectionPointerLink *link; - PyObject *linkptr; ret = PyList_New(0); for (link = lb->first; link; link = link->next) { - linkptr = pyrna_struct_CreatePyObject(&link->ptr); - PyList_Append(ret, linkptr); - Py_DECREF(linkptr); + PyList_APPEND(ret, pyrna_struct_CreatePyObject(&link->ptr)); } break; @@ -5142,9 +5116,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject #ifdef DEBUG_STRING_FREE if (item) { if (PyUnicode_Check(item)) { - item = PyUnicode_FromString(_PyUnicode_AsString(item)); - PyList_Append(string_free_ls, item); - Py_DECREF(item); + PyList_APPEND(string_free_ls, PyUnicode_FromString(_PyUnicode_AsString(item))); } } #endif @@ -6287,7 +6259,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna) /* arg[1] (bases=...) */ PyTuple_SET_ITEM(args, 1, item = PyTuple_New(1)); - PyTuple_SET_ITEM(item, 0, py_base); Py_INCREF(py_base); + PyTuple_SET_ITEM(item, 0, Py_INCREF_RET(py_base)); /* arg[2] (dict=...) */ @@ -6601,7 +6573,6 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) { PyObject *list; #if 0 - PyObject *name; PyMethodDef *meth; #endif @@ -6609,9 +6580,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) #if 0 /* for now only contains __dir__ */ for (meth = pyrna_basetype_methods; meth->ml_name; meth++) { - name = PyUnicode_FromString(meth->ml_name); - PyList_Append(list, name); - Py_DECREF(name); + PyList_APPEND(list, PyUnicode_FromString(meth->ml_name)); } #endif return list; @@ -6622,7 +6591,6 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) { PyObject *ret = PyList_New(0); - PyObject *item; RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop) { @@ -6634,9 +6602,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) } else { /* add to python list */ - item = PyUnicode_FromString(RNA_struct_identifier(srna)); - PyList_Append(ret, item); - Py_DECREF(item); + PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna))); } } RNA_PROP_END; diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index ed51ba5bd1f..ced7d6a5c1c 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -53,6 +53,8 @@ #include "bpy_util.h" #include "bpy_rna_anim.h" +#include "../generic/python_utildefines.h" + /* for keyframes and drivers */ static int pyrna_struct_anim_args_parse( PointerRNA *ptr, const char *error_prefix, const char *path, @@ -329,16 +331,13 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) FCurve *fcu; PointerRNA tptr; - PyObject *item; if (index == -1) { /* all, use a list */ int i = 0; ret = PyList_New(0); while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) { RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr); - item = pyrna_struct_CreatePyObject(&tptr); - PyList_Append(ret, item); - Py_DECREF(item); + PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr)); } } else { diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c index cdbd57bcebe..a6df8f54cc3 100644 --- a/source/blender/python/intern/bpy_utils_units.c +++ b/source/blender/python/intern/bpy_utils_units.c @@ -35,9 +35,7 @@ #include "BLI_utildefines.h" #include "BLI_string.h" -#include "BLI_ghash.h" -#include "BPY_extern.h" #include "bpy_utils_units.h" #include "../generic/py_capi_utils.h" diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c index 1002293ee0a..e4580e8035b 100644 --- a/source/blender/python/intern/gpu.c +++ b/source/blender/python/intern/gpu.c @@ -40,7 +40,6 @@ #include <Python.h> #include "DNA_scene_types.h" -#include "DNA_image_types.h" #include "DNA_material_types.h" #include "DNA_ID.h" #include "DNA_customdata_types.h" diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 349f8483fb0..6fe8dc3866b 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -31,6 +31,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/python_utildefines.h" + #ifndef MATH_STANDALONE # include "BLI_dynstr.h" #endif @@ -69,8 +71,11 @@ static int mathutils_array_parse_fast(float *array, /* helper functionm returns length of the 'value', -1 on error */ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix) { + const int flag = array_max; int size; + array_max &= ~MU_ARRAY_FLAGS; + #if 1 /* approx 6x speedup for mathutils types */ if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) || @@ -82,6 +87,10 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject * return -1; } + if (flag & MU_ARRAY_SPILL) { + CLAMP_MAX(size, array_max); + } + if (size > array_max || size < array_min) { if (array_max == array_min) { PyErr_Format(PyExc_ValueError, @@ -97,7 +106,6 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject * } memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float)); - return size; } else #endif @@ -112,6 +120,10 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject * size = PySequence_Fast_GET_SIZE(value_fast); + if (flag & MU_ARRAY_SPILL) { + CLAMP_MAX(size, array_max); + } + if (size > array_max || size < array_min) { if (array_max == array_min) { PyErr_Format(PyExc_ValueError, @@ -127,8 +139,19 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject * return -1; } - return mathutils_array_parse_fast(array, size, value_fast, error_prefix); + size = mathutils_array_parse_fast(array, size, value_fast, error_prefix); } + + if (size != -1) { + if (flag & MU_ARRAY_ZERO) { + int size_left = array_max - size; + if (size_left) { + memset(&array[size], 0, sizeof(float) * size_left); + } + } + } + + return size; } /* on error, -1 is returned and no allocation is made */ @@ -196,6 +219,7 @@ int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, c int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix) { PyObject *value_fast = NULL; + const int array_dim_flag = array_dim; int i, size; /* non list/tuple cases */ @@ -209,12 +233,14 @@ int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, if (size != 0) { float *fp; + array_dim &= ~MU_ARRAY_FLAGS; + fp = *array = PyMem_Malloc(size * array_dim * sizeof(float)); for (i = 0; i < size; i++, fp += array_dim) { PyObject *item = PySequence_Fast_GET_ITEM(value, i); - if (mathutils_array_parse(fp, array_dim, array_dim, item, error_prefix) == -1) { + if (mathutils_array_parse(fp, array_dim, array_dim_flag, item, error_prefix) == -1) { PyMem_Free(*array); *array = NULL; size = -1; @@ -420,14 +446,13 @@ char BaseMathObject_owner_doc[] = "The item this is wrapping or None (read-only PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure)) { PyObject *ret = self->cb_user ? self->cb_user : Py_None; - Py_INCREF(ret); - return ret; + return Py_INCREF_RET(ret); } char BaseMathObject_is_wrapped_doc[] = "True when this object wraps external data (read-only).\n\n:type: boolean"; PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closure)) { - return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1 : 0); + return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_WRAP) != 0); } int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg) @@ -445,7 +470,7 @@ int BaseMathObject_clear(BaseMathObject *self) void BaseMathObject_dealloc(BaseMathObject *self) { /* only free non wrapped */ - if (self->wrapped != Py_WRAP) { + if ((self->flag & BASE_MATH_FLAG_IS_WRAP) == 0) { PyMem_Free(self->data); } diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index eb25d9bff07..296b8cf9559 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -29,11 +29,23 @@ /* Can cast different mathutils types to this, use for generic funcs */ +#include "BLI_compiler_attrs.h" + struct DynStr; extern char BaseMathObject_is_wrapped_doc[]; extern char BaseMathObject_owner_doc[]; +#define BASE_MATH_NEW(struct_name, root_type, base_type) \ + (struct_name *)((base_type ? (base_type)->tp_alloc(base_type, 0) : _PyObject_GC_New(&(root_type)))); + + +/* BaseMathObject.flag */ +enum { + BASE_MATH_FLAG_IS_WRAP = (1 << 0), +}; +#define BASE_MATH_FLAG_DEFAULT 0 + #define BASE_MATH_MEMBERS(_data) \ PyObject_VAR_HEAD \ float *_data; /* array of data (alias), wrapped status depends on wrapped status */ \ @@ -42,7 +54,7 @@ extern char BaseMathObject_owner_doc[]; unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ \ unsigned char cb_subtype; /* subtype: location, rotation... \ * to avoid defining many new functions for every attribute of the same type */ \ - unsigned char wrapped /* wrapped data type? */ \ + unsigned char flag /* wrapped data type? */ \ typedef struct { BASE_MATH_MEMBERS(data); @@ -67,9 +79,6 @@ PyMODINIT_FUNC PyInit_mathutils(void); int EXPP_FloatsAreEqual(float A, float B, int floatSteps); int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps); -#define Py_NEW 1 -#define Py_WRAP 2 - typedef struct Mathutils_Callback Mathutils_Callback; typedef int (*BaseMathCheckFunc)(BaseMathObject *); /* checks the user is still valid */ @@ -109,6 +118,14 @@ int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, c int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix); int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix); +/* zero remaining unused elements of the array */ +#define MU_ARRAY_ZERO (1 << 30) +/* ignore larger py sequences than requested (just use first elements), + * handy when using 3d vectors as 2d */ +#define MU_ARRAY_SPILL (1 << 31) + +#define MU_ARRAY_FLAGS (MU_ARRAY_ZERO | MU_ARRAY_SPILL) + int column_vector_multiplication(float rvec[4], VectorObject *vec, MatrixObject *mat); #ifndef MATH_STANDALONE diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c index aee2b9e9711..8426038f2d4 100644 --- a/source/blender/python/mathutils/mathutils_Color.c +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -32,6 +32,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/python_utildefines.h" + #ifndef MATH_STANDALONE # include "BLI_dynstr.h" #endif @@ -64,7 +66,7 @@ static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds) "more than a single arg given"); return NULL; } - return Color_CreatePyObject(col, Py_NEW, type); + return Color_CreatePyObject(col, type); } /* -----------------------------METHODS---------------------------- */ @@ -107,7 +109,7 @@ static PyObject *Color_copy(ColorObject *self) if (BaseMath_ReadCallback(self) == -1) return NULL; - return Color_CreatePyObject(self->col, Py_NEW, Py_TYPE(self)); + return Color_CreatePyObject(self->col, Py_TYPE(self)); } static PyObject *Color_deepcopy(ColorObject *self, PyObject *args) { @@ -187,7 +189,7 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op) return NULL; } - return Py_INCREF(res), res; + return Py_INCREF_RET(res); } /* ---------------------SEQUENCE PROTOCOLS------------------------ */ @@ -411,7 +413,7 @@ static PyObject *Color_add(PyObject *v1, PyObject *v2) add_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE); - return Color_CreatePyObject(col, Py_NEW, Py_TYPE(v1)); + return Color_CreatePyObject(col, Py_TYPE(v1)); } /* addition in-place: obj += obj */ @@ -460,7 +462,7 @@ static PyObject *Color_sub(PyObject *v1, PyObject *v2) sub_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE); - return Color_CreatePyObject(col, Py_NEW, Py_TYPE(v1)); + return Color_CreatePyObject(col, Py_TYPE(v1)); } /* subtraction in-place: obj -= obj */ @@ -492,7 +494,7 @@ static PyObject *color_mul_float(ColorObject *color, const float scalar) { float tcol[COLOR_SIZE]; mul_vn_vn_fl(tcol, color->col, COLOR_SIZE, scalar); - return Color_CreatePyObject(tcol, Py_NEW, Py_TYPE(color)); + return Color_CreatePyObject(tcol, Py_TYPE(color)); } @@ -639,7 +641,7 @@ static PyObject *Color_neg(ColorObject *self) return NULL; negate_vn_vn(tcol, self->col, COLOR_SIZE); - return Color_CreatePyObject(tcol, Py_NEW, Py_TYPE(self)); + return Color_CreatePyObject(tcol, Py_TYPE(self)); } @@ -753,9 +755,10 @@ static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure)) rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2])); ret = PyTuple_New(3); - PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(hsv[0])); - PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(hsv[1])); - PyTuple_SET_ITEM(ret, 2, PyFloat_FromDouble(hsv[2])); + PyTuple_SET_ITEMS(ret, + PyFloat_FromDouble(hsv[0]), + PyFloat_FromDouble(hsv[1]), + PyFloat_FromDouble(hsv[2])); return ret; } @@ -862,40 +865,60 @@ PyTypeObject color_Type = { NULL, /* tp_weaklist */ NULL /* tp_del */ }; -/* ------------------------Color_CreatePyObject (internal)------------- */ -/* creates a new color object */ -/* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - * (i.e. it was allocated elsewhere by MEM_mallocN()) - * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - * (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *Color_CreatePyObject(float col[3], int type, PyTypeObject *base_type) + +PyObject *Color_CreatePyObject( + const float col[3], + PyTypeObject *base_type) { ColorObject *self; + float *col_alloc; - self = base_type ? (ColorObject *)base_type->tp_alloc(base_type, 0) : - (ColorObject *)PyObject_GC_New(ColorObject, &color_Type); + col_alloc = PyMem_Malloc(COLOR_SIZE * sizeof(float)); + if (UNLIKELY(col_alloc == NULL)) { + PyErr_SetString(PyExc_MemoryError, + "Color(): " + "problem allocating data"); + return NULL; + } + self = BASE_MATH_NEW(ColorObject, color_Type, base_type); if (self) { + self->col = col_alloc; + /* init callbacks as NULL */ self->cb_user = NULL; self->cb_type = self->cb_subtype = 0; - if (type == Py_WRAP) { - self->col = col; - self->wrapped = Py_WRAP; - } - else if (type == Py_NEW) { - self->col = PyMem_Malloc(COLOR_SIZE * sizeof(float)); - if (col) - copy_v3_v3(self->col, col); - else - zero_v3(self->col); - - self->wrapped = Py_NEW; - } - else { - Py_FatalError("Color(): invalid type!"); - } + /* NEW */ + if (col) + copy_v3_v3(self->col, col); + else + zero_v3(self->col); + + self->flag = BASE_MATH_FLAG_DEFAULT; + } + else { + PyMem_Free(col_alloc); + } + + return (PyObject *)self; +} + +PyObject *Color_CreatePyObject_wrap( + float col[3], + PyTypeObject *base_type) +{ + ColorObject *self; + + self = BASE_MATH_NEW(ColorObject, color_Type, base_type); + if (self) { + /* init callbacks as NULL */ + self->cb_user = NULL; + self->cb_type = self->cb_subtype = 0; + + /* WRAP */ + self->col = col; + self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP; } return (PyObject *)self; @@ -904,7 +927,7 @@ PyObject *Color_CreatePyObject(float col[3], int type, PyTypeObject *base_type) PyObject *Color_CreatePyObject_cb(PyObject *cb_user, unsigned char cb_type, unsigned char cb_subtype) { - ColorObject *self = (ColorObject *)Color_CreatePyObject(NULL, Py_NEW, NULL); + ColorObject *self = (ColorObject *)Color_CreatePyObject(NULL, NULL); if (self) { Py_INCREF(cb_user); self->cb_user = cb_user; diff --git a/source/blender/python/mathutils/mathutils_Color.h b/source/blender/python/mathutils/mathutils_Color.h index 193d30a2b6f..1290f73da62 100644 --- a/source/blender/python/mathutils/mathutils_Color.h +++ b/source/blender/python/mathutils/mathutils_Color.h @@ -42,8 +42,17 @@ typedef struct { * blender (stored in blend_data). This is an either/or struct not both*/ /* prototypes */ -PyObject *Color_CreatePyObject(float col[3], int type, PyTypeObject *base_type); -PyObject *Color_CreatePyObject_cb(PyObject *cb_user, - unsigned char cb_type, unsigned char cb_subtype); +PyObject *Color_CreatePyObject( + const float col[3], + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT; +PyObject *Color_CreatePyObject_wrap( + float col[3], + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +PyObject *Color_CreatePyObject_cb( + PyObject *cb_user, + unsigned char cb_type, unsigned char cb_subtype + ) ATTR_WARN_UNUSED_RESULT; #endif /* __MATHUTILS_COLOR_H__ */ diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index f6d124938a4..9c0ced39403 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -31,6 +31,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/python_utildefines.h" #ifndef MATH_STANDALONE # include "BLI_dynstr.h" @@ -70,7 +71,7 @@ static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; break; } - return Euler_CreatePyObject(eul, order, Py_NEW, type); + return Euler_CreatePyObject(eul, order, type); } /* internal use, assume read callback is done */ @@ -150,7 +151,7 @@ static PyObject *Euler_to_quaternion(EulerObject *self) eulO_to_quat(quat, self->eul, self->order); - return Quaternion_CreatePyObject(quat, Py_NEW, NULL); + return Quaternion_CreatePyObject(quat, NULL); } /* return a matrix representation of the euler */ @@ -171,7 +172,7 @@ static PyObject *Euler_to_matrix(EulerObject *self) eulO_to_mat3((float (*)[3])mat, self->eul, self->order); - return Matrix_CreatePyObject(mat, 3, 3, Py_NEW, NULL); + return Matrix_CreatePyObject(mat, 3, 3, NULL); } PyDoc_STRVAR(Euler_zero_doc, @@ -233,7 +234,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args) PyDoc_STRVAR(Euler_rotate_doc, ".. method:: rotate(other)\n" "\n" -" Rotates the euler a by another mathutils value.\n" +" Rotates the euler by another mathutils value.\n" "\n" " :arg other: rotation component of mathutils value\n" " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" @@ -304,7 +305,7 @@ static PyObject *Euler_copy(EulerObject *self) if (BaseMath_ReadCallback(self) == -1) return NULL; - return Euler_CreatePyObject(self->eul, self->order, Py_NEW, Py_TYPE(self)); + return Euler_CreatePyObject(self->eul, self->order, Py_TYPE(self)); } static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args) { @@ -382,7 +383,7 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op) return NULL; } - return Py_INCREF(res), res; + return Py_INCREF_RET(res); } /* ---------------------SEQUENCE PROTOCOLS------------------------ */ @@ -710,53 +711,74 @@ PyTypeObject euler_Type = { NULL, /* tp_weaklist */ NULL /* tp_del */ }; -/* ------------------------Euler_CreatePyObject (internal)------------- */ -/* creates a new euler object */ -/* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - * (i.e. it was allocated elsewhere by MEM_mallocN()) - * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - * (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *Euler_CreatePyObject(float eul[3], const short order, int type, PyTypeObject *base_type) + + +PyObject *Euler_CreatePyObject( + const float eul[3], const short order, + PyTypeObject *base_type) { EulerObject *self; + float *eul_alloc; - self = base_type ? (EulerObject *)base_type->tp_alloc(base_type, 0) : - (EulerObject *)PyObject_GC_New(EulerObject, &euler_Type); + eul_alloc = PyMem_Malloc(EULER_SIZE * sizeof(float)); + if (UNLIKELY(eul_alloc == NULL)) { + PyErr_SetString(PyExc_MemoryError, + "Euler(): " + "problem allocating data"); + return NULL; + } + self = BASE_MATH_NEW(EulerObject, euler_Type, base_type); if (self) { + self->eul = eul_alloc; + /* init callbacks as NULL */ self->cb_user = NULL; self->cb_type = self->cb_subtype = 0; - if (type == Py_WRAP) { - self->eul = eul; - self->wrapped = Py_WRAP; - } - else if (type == Py_NEW) { - self->eul = PyMem_Malloc(EULER_SIZE * sizeof(float)); - if (eul) { - copy_v3_v3(self->eul, eul); - } - else { - zero_v3(self->eul); - } - - self->wrapped = Py_NEW; + if (eul) { + copy_v3_v3(self->eul, eul); } else { - Py_FatalError("Euler(): invalid type!"); + zero_v3(self->eul); } + self->flag = BASE_MATH_FLAG_DEFAULT; + self->order = order; + } + else { + PyMem_Free(eul_alloc); + } + + return (PyObject *)self; +} + +PyObject *Euler_CreatePyObject_wrap( + float eul[3], const short order, + PyTypeObject *base_type) +{ + EulerObject *self; + + self = BASE_MATH_NEW(EulerObject, euler_Type, base_type); + if (self) { + /* init callbacks as NULL */ + self->cb_user = NULL; + self->cb_type = self->cb_subtype = 0; + + self->eul = eul; + self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP; + self->order = order; } return (PyObject *)self; } -PyObject *Euler_CreatePyObject_cb(PyObject *cb_user, const short order, - unsigned char cb_type, unsigned char cb_subtype) +PyObject *Euler_CreatePyObject_cb( + PyObject *cb_user, const short order, + unsigned char cb_type, unsigned char cb_subtype) { - EulerObject *self = (EulerObject *)Euler_CreatePyObject(NULL, order, Py_NEW, NULL); + EulerObject *self = (EulerObject *)Euler_CreatePyObject(NULL, order, NULL); if (self) { Py_INCREF(cb_user); self->cb_user = cb_user; diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h index 62fb83ef234..744f39faed1 100644 --- a/source/blender/python/mathutils/mathutils_Euler.h +++ b/source/blender/python/mathutils/mathutils_Euler.h @@ -43,9 +43,18 @@ typedef struct { * blender (stored in blend_data). This is an either/or struct not both */ /* prototypes */ -PyObject *Euler_CreatePyObject(float eul[3], const short order, int type, PyTypeObject *base_type); -PyObject *Euler_CreatePyObject_cb(PyObject *cb_user, const short order, - unsigned char cb_type, unsigned char cb_subtype); +PyObject *Euler_CreatePyObject( + const float eul[3], const short order, + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT; +PyObject *Euler_CreatePyObject_wrap( + float eul[3], const short order, + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +PyObject *Euler_CreatePyObject_cb( + PyObject *cb_user, const short order, + unsigned char cb_type, unsigned char cb_subtype + ) ATTR_WARN_UNUSED_RESULT; short euler_order_from_string(const char *str, const char *error_prefix); diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 282f29b4934..4706c09176e 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -32,6 +32,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/python_utildefines.h" + #ifndef MATH_STANDALONE # include "BLI_string.h" # include "BLI_dynstr.h" @@ -344,7 +346,7 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) switch (PyTuple_GET_SIZE(args)) { case 0: - return Matrix_CreatePyObject(NULL, 4, 4, Py_NEW, type); + return Matrix_CreatePyObject(NULL, 4, 4, type); case 1: { PyObject *arg = PyTuple_GET_ITEM(args, 0); @@ -363,7 +365,7 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (num_col >= 2 && num_col <= 4) { /* sane row & col size, new matrix and assign as slice */ - PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, type); + PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, type); if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) { return matrix; } @@ -444,7 +446,7 @@ static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args) return NULL; } - return Matrix_CreatePyObject(NULL, matSize, matSize, Py_NEW, (PyTypeObject *)cls); + return Matrix_CreatePyObject(NULL, matSize, matSize, (PyTypeObject *)cls); } PyDoc_STRVAR(C_Matrix_Rotation_doc, @@ -535,7 +537,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args) matrix_3x3_as_4x4(mat); } /* pass to matrix creation */ - return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); + return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls); } @@ -558,7 +560,7 @@ static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value) if (mathutils_array_parse(mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1) return NULL; - return Matrix_CreatePyObject(&mat[0][0], 4, 4, Py_NEW, (PyTypeObject *)cls); + return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls); } /* ----------------------------------mathutils.Matrix.Scale() ------------- */ /* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */ @@ -650,7 +652,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args) matrix_3x3_as_4x4(mat); } /* pass to matrix creation */ - return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); + return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls); } /* ----------------------------------mathutils.Matrix.OrthoProjection() --- */ /* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */ @@ -771,7 +773,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args) matrix_3x3_as_4x4(mat); } /* pass to matrix creation */ - return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); + return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls); } PyDoc_STRVAR(C_Matrix_Shear_doc, @@ -874,7 +876,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args) matrix_3x3_as_4x4(mat); } /* pass to matrix creation */ - return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); + return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls); } void matrix_as_3x3(float mat[3][3], MatrixObject *self) @@ -1078,7 +1080,7 @@ static PyObject *Matrix_to_quaternion(MatrixObject *self) mat4_to_quat(quat, (float (*)[4])self->matrix); } - return Quaternion_CreatePyObject(quat, Py_NEW, NULL); + return Quaternion_CreatePyObject(quat, NULL); } /*---------------------------matrix.toEuler() --------------------*/ @@ -1152,7 +1154,7 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args) else mat3_to_eulO(eul, order, mat); } - return Euler_CreatePyObject(eul, order, Py_NEW, NULL); + return Euler_CreatePyObject(eul, order, NULL); } PyDoc_STRVAR(Matrix_resize_4x4_doc, @@ -1165,7 +1167,7 @@ static PyObject *Matrix_resize_4x4(MatrixObject *self) float mat[4][4]; int col; - if (self->wrapped == Py_WRAP) { + if (self->flag & BASE_MATH_FLAG_IS_WRAP) { PyErr_SetString(PyExc_ValueError, "Matrix.resize_4x4(): " "cannot resize wrapped data - make a copy and resize that"); @@ -1214,12 +1216,12 @@ static PyObject *Matrix_to_4x4(MatrixObject *self) return NULL; if (self->num_row == 4 && self->num_col == 4) { - return Matrix_CreatePyObject(self->matrix, 4, 4, Py_NEW, Py_TYPE(self)); + return Matrix_CreatePyObject(self->matrix, 4, 4, Py_TYPE(self)); } else if (self->num_row == 3 && self->num_col == 3) { float mat[4][4]; copy_m4_m3(mat, (float (*)[3])self->matrix); - return Matrix_CreatePyObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self)); + return Matrix_CreatePyObject((float *)mat, 4, 4, Py_TYPE(self)); } /* TODO, 2x2 matrix */ @@ -1252,15 +1254,15 @@ static PyObject *Matrix_to_3x3(MatrixObject *self) matrix_as_3x3(mat, self); - return Matrix_CreatePyObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self)); + return Matrix_CreatePyObject((float *)mat, 3, 3, Py_TYPE(self)); } PyDoc_STRVAR(Matrix_to_translation_doc, ".. method:: to_translation()\n" "\n" -" Return a the translation part of a 4 row matrix.\n" +" Return the translation part of a 4 row matrix.\n" "\n" -" :return: Return a the translation of a matrix.\n" +" :return: Return the translation of a matrix.\n" " :rtype: :class:`Vector`\n" ); static PyObject *Matrix_to_translation(MatrixObject *self) @@ -1275,15 +1277,15 @@ static PyObject *Matrix_to_translation(MatrixObject *self) return NULL; } - return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, Py_NEW, NULL); + return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, NULL); } PyDoc_STRVAR(Matrix_to_scale_doc, ".. method:: to_scale()\n" "\n" -" Return a the scale part of a 3x3 or 4x4 matrix.\n" +" Return the scale part of a 3x3 or 4x4 matrix.\n" "\n" -" :return: Return a the scale of a matrix.\n" +" :return: Return the scale of a matrix.\n" " :rtype: :class:`Vector`\n" "\n" " .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n" @@ -1310,7 +1312,7 @@ static PyObject *Matrix_to_scale(MatrixObject *self) /* compatible mat4_to_loc_rot_size */ mat3_to_rot_size(rot, size, mat); - return Vector_CreatePyObject(size, 3, Py_NEW, NULL); + return Vector_CreatePyObject(size, 3, NULL); } /*---------------------------matrix.invert() ---------------------*/ @@ -1589,7 +1591,7 @@ static PyObject *Matrix_adjugated(MatrixObject *self) PyDoc_STRVAR(Matrix_rotate_doc, ".. method:: rotate(other)\n" "\n" -" Rotates the matrix a by another mathutils value.\n" +" Rotates the matrix by another mathutils value.\n" "\n" " :arg other: rotation component of mathutils value\n" " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" @@ -1653,10 +1655,10 @@ static PyObject *Matrix_decompose(MatrixObject *self) mat3_to_quat(quat, rot); ret = PyTuple_New(3); - PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(loc, 3, Py_NEW, NULL)); - PyTuple_SET_ITEM(ret, 1, Quaternion_CreatePyObject(quat, Py_NEW, NULL)); - PyTuple_SET_ITEM(ret, 2, Vector_CreatePyObject(size, 3, Py_NEW, NULL)); - + PyTuple_SET_ITEMS(ret, + Vector_CreatePyObject(loc, 3, NULL), + Quaternion_CreatePyObject(quat, NULL), + Vector_CreatePyObject(size, 3, NULL)); return ret; } @@ -1706,7 +1708,7 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args) return NULL; } - return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_NEW, Py_TYPE(self)); + return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_TYPE(self)); } /*---------------------------matrix.determinant() ----------------*/ @@ -1715,7 +1717,7 @@ PyDoc_STRVAR(Matrix_determinant_doc, "\n" " Return the determinant of a matrix.\n" "\n" -" :return: Return a the determinant of a matrix.\n" +" :return: Return the determinant of a matrix.\n" " :rtype: float\n" "\n" " .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n" @@ -1836,7 +1838,6 @@ PyDoc_STRVAR(Matrix_zero_doc, "\n" " Set all the matrix values to zero.\n" "\n" -" :return: an instance of itself\n" " :rtype: :class:`Matrix`\n" ); static PyObject *Matrix_zero(MatrixObject *self) @@ -1847,8 +1848,24 @@ static PyObject *Matrix_zero(MatrixObject *self) return NULL; Py_RETURN_NONE; + } /*---------------------------matrix.identity(() ------------------*/ +static void matrix_identity_internal(MatrixObject *self) +{ + BLI_assert((self->num_col == self->num_row) && (self->num_row <= 4)); + + if (self->num_col == 2) { + unit_m2((float (*)[2])self->matrix); + } + else if (self->num_col == 3) { + unit_m3((float (*)[3])self->matrix); + } + else { + unit_m4((float (*)[4])self->matrix); + } +} + PyDoc_STRVAR(Matrix_identity_doc, ".. method:: identity()\n" "\n" @@ -1871,15 +1888,7 @@ static PyObject *Matrix_identity(MatrixObject *self) return NULL; } - if (self->num_col == 2) { - unit_m2((float (*)[2])self->matrix); - } - else if (self->num_col == 3) { - unit_m3((float (*)[3])self->matrix); - } - else { - unit_m4((float (*)[4])self->matrix); - } + matrix_identity_internal(self); if (BaseMath_WriteCallback(self) == -1) return NULL; @@ -1891,7 +1900,7 @@ static PyObject *Matrix_identity(MatrixObject *self) static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix) { - return Matrix_CreatePyObject((float *)matrix, self->num_col, self->num_row, Py_NEW, Py_TYPE(self)); + return Matrix_CreatePyObject((float *)matrix, self->num_col, self->num_row, Py_TYPE(self)); } PyDoc_STRVAR(Matrix_copy_doc, @@ -2025,7 +2034,7 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op) return NULL; } - return Py_INCREF(res), res; + return Py_INCREF_RET(res); } /*---------------------SEQUENCE PROTOCOLS------------------------ @@ -2233,7 +2242,7 @@ static PyObject *Matrix_add(PyObject *m1, PyObject *m2) add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row); - return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1)); + return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1)); } /*------------------------obj - obj------------------------------ * subtraction */ @@ -2265,7 +2274,7 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2) sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row); - return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1)); + return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1)); } /*------------------------obj * obj------------------------------ * multiplication */ @@ -2273,7 +2282,7 @@ static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar) { float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; mul_vn_vn_fl(tmat, mat->matrix, mat->num_col * mat->num_row, scalar); - return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_NEW, Py_TYPE(mat)); + return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_TYPE(mat)); } static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) @@ -2317,7 +2326,7 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) } } - return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1)); + return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1)); } else if (mat2) { /*FLOAT/INT * MATRIX */ @@ -2343,7 +2352,7 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) vec_size = mat1->num_row; } - return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(m2)); + return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(m2)); } /*FLOAT/INT * MATRIX */ else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) { @@ -2762,15 +2771,13 @@ PyTypeObject matrix_Type = { NULL /*tp_del*/ }; -/* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - * (i.e. it was allocated elsewhere by MEM_mallocN()) - * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - * (i.e. it must be created here with PyMEM_malloc()) */ -PyObject *Matrix_CreatePyObject(float *mat, - const unsigned short num_col, const unsigned short num_row, - int type, PyTypeObject *base_type) +PyObject *Matrix_CreatePyObject( + const float *mat, + const unsigned short num_col, const unsigned short num_row, + PyTypeObject *base_type) { MatrixObject *self; + float *mat_alloc; /* matrix objects can be any 2-4row x 2-4col matrix */ if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) { @@ -2780,10 +2787,17 @@ PyObject *Matrix_CreatePyObject(float *mat, return NULL; } - self = base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) : - (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type); + mat_alloc = PyMem_Malloc(num_col * num_row * sizeof(float)); + if (UNLIKELY(mat_alloc == NULL)) { + PyErr_SetString(PyExc_MemoryError, + "Matrix(): " + "problem allocating data"); + return NULL; + } + self = BASE_MATH_NEW(MatrixObject, matrix_Type, base_type); if (self) { + self->matrix = mat_alloc; self->num_col = num_col; self->num_row = num_row; @@ -2791,37 +2805,52 @@ PyObject *Matrix_CreatePyObject(float *mat, self->cb_user = NULL; self->cb_type = self->cb_subtype = 0; - if (type == Py_WRAP) { - self->matrix = mat; - self->wrapped = Py_WRAP; + if (mat) { /*if a float array passed*/ + memcpy(self->matrix, mat, num_col * num_row * sizeof(float)); } - else if (type == Py_NEW) { - self->matrix = PyMem_Malloc(num_col * num_row * sizeof(float)); - if (self->matrix == NULL) { /*allocation failure*/ - PyErr_SetString(PyExc_MemoryError, - "Matrix(): " - "problem allocating pointer space"); - return NULL; - } - - if (mat) { /*if a float array passed*/ - memcpy(self->matrix, mat, num_col * num_row * sizeof(float)); - } - else if (num_col == num_row) { - /* or if no arguments are passed return identity matrix for square matrices */ - PyObject *ret_dummy = Matrix_identity(self); - Py_DECREF(ret_dummy); - } - else { - /* otherwise zero everything */ - memset(self->matrix, 0, num_col * num_row * sizeof(float)); - } - self->wrapped = Py_NEW; + else if (num_col == num_row) { + /* or if no arguments are passed return identity matrix for square matrices */ + matrix_identity_internal(self); } else { - Py_FatalError("Matrix(): invalid type!"); - return NULL; + /* otherwise zero everything */ + memset(self->matrix, 0, num_col * num_row * sizeof(float)); } + self->flag = BASE_MATH_FLAG_DEFAULT; + } + else { + PyMem_Free(mat_alloc); + } + + return (PyObject *)self; +} + +PyObject *Matrix_CreatePyObject_wrap( + float *mat, + const unsigned short num_col, const unsigned short num_row, + PyTypeObject *base_type) +{ + MatrixObject *self; + + /* matrix objects can be any 2-4row x 2-4col matrix */ + if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) { + PyErr_SetString(PyExc_RuntimeError, + "Matrix(): " + "row and column sizes must be between 2 and 4"); + return NULL; + } + + self = BASE_MATH_NEW(MatrixObject, matrix_Type, base_type); + if (self) { + self->num_col = num_col; + self->num_row = num_row; + + /* init callbacks as NULL */ + self->cb_user = NULL; + self->cb_type = self->cb_subtype = 0; + + self->matrix = mat; + self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP; } return (PyObject *) self; } @@ -2830,7 +2859,7 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user, const unsigned short num_col, const unsigned short num_row, unsigned char cb_type, unsigned char cb_subtype) { - MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, NULL); + MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, NULL); if (self) { Py_INCREF(cb_user); self->cb_user = cb_user; diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index f94af9e540e..9ae5a4bd61d 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -61,12 +61,21 @@ typedef struct { * blender (stored in blend_data). This is an either/or struct not both */ /* prototypes */ -PyObject *Matrix_CreatePyObject(float *mat, - const unsigned short num_col, const unsigned short num_row, - int type, PyTypeObject *base_type); -PyObject *Matrix_CreatePyObject_cb(PyObject *user, - const unsigned short num_col, const unsigned short num_row, - unsigned char cb_type, unsigned char cb_subtype); +PyObject *Matrix_CreatePyObject( + const float *mat, + const unsigned short num_col, const unsigned short num_row, + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT; +PyObject *Matrix_CreatePyObject_wrap( + float *mat, + const unsigned short num_col, const unsigned short num_row, + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +PyObject *Matrix_CreatePyObject_cb( + PyObject *user, + const unsigned short num_col, const unsigned short num_row, + unsigned char cb_type, unsigned char cb_subtype + ) ATTR_WARN_UNUSED_RESULT; extern unsigned char mathutils_matrix_row_cb_index; /* default */ extern unsigned char mathutils_matrix_col_cb_index; diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index ae3476f5802..d422634a496 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -32,6 +32,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/python_utildefines.h" + #ifndef MATH_STANDALONE # include "BLI_dynstr.h" #endif @@ -121,7 +123,7 @@ static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args) else quat_to_eulO(eul, order, tquat); } - return Euler_CreatePyObject(eul, order, Py_NEW, NULL); + return Euler_CreatePyObject(eul, order, NULL); } PyDoc_STRVAR(Quaternion_to_matrix_doc, @@ -140,7 +142,7 @@ static PyObject *Quaternion_to_matrix(QuaternionObject *self) return NULL; quat_to_mat3((float (*)[3])mat, self->quat); - return Matrix_CreatePyObject(mat, 3, 3, Py_NEW, NULL); + return Matrix_CreatePyObject(mat, 3, 3, NULL); } PyDoc_STRVAR(Quaternion_to_axis_angle_doc, @@ -169,8 +171,9 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self) quat__axis_angle_sanitize(axis, &angle); ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(axis, 3, Py_NEW, NULL)); - PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(angle)); + PyTuple_SET_ITEMS(ret, + Vector_CreatePyObject(axis, 3, NULL), + PyFloat_FromDouble(angle)); return ret; } @@ -198,7 +201,7 @@ static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value) } mul_qt_qtqt(quat, self->quat, tquat); - return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self)); + return Quaternion_CreatePyObject(quat, Py_TYPE(self)); } PyDoc_STRVAR(Quaternion_dot_doc, @@ -252,7 +255,7 @@ static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject rotation_between_quats_to_quat(quat, self->quat, tquat); - return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self)); + return Quaternion_CreatePyObject(quat, Py_TYPE(self)); } PyDoc_STRVAR(Quaternion_slerp_doc, @@ -297,13 +300,13 @@ static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args) interp_qt_qtqt(quat, self->quat, tquat, fac); - return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self)); + return Quaternion_CreatePyObject(quat, Py_TYPE(self)); } PyDoc_STRVAR(Quaternion_rotate_doc, ".. method:: rotate(other)\n" "\n" -" Rotates the quaternion a by another mathutils value.\n" +" Rotates the quaternion by another mathutils value.\n" "\n" " :arg other: rotation component of mathutils value\n" " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" @@ -393,7 +396,6 @@ PyDoc_STRVAR(Quaternion_identity_doc, "\n" " Set the quaternion to an identity quaternion.\n" "\n" -" :return: an instance of itself.\n" " :rtype: :class:`Quaternion`\n" ); static PyObject *Quaternion_identity(QuaternionObject *self) @@ -412,7 +414,6 @@ PyDoc_STRVAR(Quaternion_negate_doc, "\n" " Set the quaternion to its negative.\n" "\n" -" :return: an instance of itself.\n" " :rtype: :class:`Quaternion`\n" ); static PyObject *Quaternion_negate(QuaternionObject *self) @@ -470,7 +471,7 @@ static PyObject *Quaternion_copy(QuaternionObject *self) if (BaseMath_ReadCallback(self) == -1) return NULL; - return Quaternion_CreatePyObject(self->quat, Py_NEW, Py_TYPE(self)); + return Quaternion_CreatePyObject(self->quat, Py_TYPE(self)); } static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args) { @@ -546,7 +547,7 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op) return NULL; } - return Py_INCREF(res), res; + return Py_INCREF_RET(res); } /* ---------------------SEQUENCE PROTOCOLS------------------------ */ @@ -750,7 +751,7 @@ static PyObject *Quaternion_add(PyObject *q1, PyObject *q2) return NULL; add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f); - return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1)); + return Quaternion_CreatePyObject(quat, Py_TYPE(q1)); } /* ------------------------obj - obj------------------------------ */ /* subtraction */ @@ -778,7 +779,7 @@ static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2) quat[x] = quat1->quat[x] - quat2->quat[x]; } - return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1)); + return Quaternion_CreatePyObject(quat, Py_TYPE(q1)); } static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar) @@ -786,7 +787,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar) float tquat[4]; copy_qt_qt(tquat, quat->quat); mul_qt_fl(tquat, scalar); - return Quaternion_CreatePyObject(tquat, Py_NEW, Py_TYPE(quat)); + return Quaternion_CreatePyObject(tquat, Py_TYPE(quat)); } /*------------------------obj * obj------------------------------ @@ -809,7 +810,7 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) if (quat1 && quat2) { /* QUAT * QUAT (cross product) */ mul_qt_qtqt(quat, quat1->quat, quat2->quat); - return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1)); + return Quaternion_CreatePyObject(quat, Py_TYPE(q1)); } /* the only case this can happen (for a supported type is "FLOAT * QUAT") */ else if (quat2) { /* FLOAT * QUAT */ @@ -837,7 +838,7 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) copy_v3_v3(tvec, vec2->vec); mul_qt_v3(quat1->quat, tvec); - return Vector_CreatePyObject(tvec, 3, Py_NEW, Py_TYPE(vec2)); + return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec2)); } /* QUAT * FLOAT */ else if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) { @@ -865,7 +866,7 @@ static PyObject *Quaternion_neg(QuaternionObject *self) return NULL; negate_v4_v4(tquat, self->quat); - return Quaternion_CreatePyObject(tquat, Py_NEW, Py_TYPE(self)); + return Quaternion_CreatePyObject(tquat, Py_TYPE(self)); } @@ -1023,7 +1024,7 @@ static PyObject *Quaternion_axis_vector_get(QuaternionObject *self, void *UNUSED quat__axis_angle_sanitize(axis, NULL); - return Vector_CreatePyObject(axis, 3, Py_NEW, NULL); + return Vector_CreatePyObject(axis, 3, NULL); } static int Quaternion_axis_vector_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure)) @@ -1089,7 +1090,7 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw /* PyArg_ParseTuple assures no more than 2 */ } } - return Quaternion_CreatePyObject(quat, Py_NEW, type); + return Quaternion_CreatePyObject(quat, type); } static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self) @@ -1240,41 +1241,60 @@ PyTypeObject quaternion_Type = { NULL, /* tp_weaklist */ NULL, /* tp_del */ }; -/* ------------------------Quaternion_CreatePyObject (internal)------------- */ -/* creates a new quaternion object */ -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - * (i.e. it was allocated elsewhere by MEM_mallocN()) - * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - * (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *Quaternion_CreatePyObject(float quat[4], int type, PyTypeObject *base_type) + +PyObject *Quaternion_CreatePyObject( + const float quat[4], + PyTypeObject *base_type) { QuaternionObject *self; + float *quat_alloc; - self = base_type ? (QuaternionObject *)base_type->tp_alloc(base_type, 0) : - (QuaternionObject *)PyObject_GC_New(QuaternionObject, &quaternion_Type); + quat_alloc = PyMem_Malloc(QUAT_SIZE * sizeof(float)); + if (UNLIKELY(quat_alloc == NULL)) { + PyErr_SetString(PyExc_MemoryError, + "Quaternion(): " + "problem allocating data"); + return NULL; + } + self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type); if (self) { + self->quat = quat_alloc; /* init callbacks as NULL */ self->cb_user = NULL; self->cb_type = self->cb_subtype = 0; - if (type == Py_WRAP) { - self->quat = quat; - self->wrapped = Py_WRAP; - } - else if (type == Py_NEW) { - self->quat = PyMem_Malloc(QUAT_SIZE * sizeof(float)); - if (!quat) { /* new empty */ - unit_qt(self->quat); - } - else { - copy_qt_qt(self->quat, quat); - } - self->wrapped = Py_NEW; + /* NEW */ + if (!quat) { /* new empty */ + unit_qt(self->quat); } else { - Py_FatalError("Quaternion(): invalid type!"); + copy_qt_qt(self->quat, quat); } + self->flag = BASE_MATH_FLAG_DEFAULT; + } + else { + PyMem_Free(quat_alloc); + } + + return (PyObject *)self; +} + +PyObject *Quaternion_CreatePyObject_wrap( + float quat[4], + PyTypeObject *base_type) +{ + QuaternionObject *self; + + self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type); + if (self) { + /* init callbacks as NULL */ + self->cb_user = NULL; + self->cb_type = self->cb_subtype = 0; + + /* WRAP */ + self->quat = quat; + self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP; } return (PyObject *) self; } @@ -1282,7 +1302,7 @@ PyObject *Quaternion_CreatePyObject(float quat[4], int type, PyTypeObject *base_ PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, unsigned char cb_type, unsigned char cb_subtype) { - QuaternionObject *self = (QuaternionObject *)Quaternion_CreatePyObject(NULL, Py_NEW, NULL); + QuaternionObject *self = (QuaternionObject *)Quaternion_CreatePyObject(NULL, NULL); if (self) { Py_INCREF(cb_user); self->cb_user = cb_user; diff --git a/source/blender/python/mathutils/mathutils_Quaternion.h b/source/blender/python/mathutils/mathutils_Quaternion.h index 36036c6d3fa..66ee3362906 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.h +++ b/source/blender/python/mathutils/mathutils_Quaternion.h @@ -40,8 +40,17 @@ typedef struct { * blender (stored in blend_data). This is an either/or struct not both */ /* prototypes */ -PyObject *Quaternion_CreatePyObject(float quat[4], int type, PyTypeObject *base_type); -PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, - unsigned char cb_type, unsigned char cb_subtype); +PyObject *Quaternion_CreatePyObject( + const float quat[4], + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT; +PyObject *Quaternion_CreatePyObject_wrap( + float quat[4], + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +PyObject *Quaternion_CreatePyObject_cb( + PyObject *cb_user, + unsigned char cb_type, unsigned char cb_subtype + ) ATTR_WARN_UNUSED_RESULT; #endif /* __MATHUTILS_QUATERNION_H__ */ diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 15a9860be0a..167fb5bcf3d 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -387,7 +387,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value) { int size; - if (self->wrapped == Py_WRAP) { + if (self->flag & BASE_MATH_FLAG_IS_WRAP) { PyErr_SetString(PyExc_TypeError, "Vector.resize(): " "cannot resize wrapped data - only python vectors"); @@ -475,7 +475,7 @@ PyDoc_STRVAR(Vector_resize_2d_doc, ); static PyObject *Vector_resize_2d(VectorObject *self) { - if (self->wrapped == Py_WRAP) { + if (self->flag & BASE_MATH_FLAG_IS_WRAP) { PyErr_SetString(PyExc_TypeError, "Vector.resize_2d(): " "cannot resize wrapped data - only python vectors"); @@ -507,7 +507,7 @@ PyDoc_STRVAR(Vector_resize_3d_doc, ); static PyObject *Vector_resize_3d(VectorObject *self) { - if (self->wrapped == Py_WRAP) { + if (self->flag & BASE_MATH_FLAG_IS_WRAP) { PyErr_SetString(PyExc_TypeError, "Vector.resize_3d(): " "cannot resize wrapped data - only python vectors"); @@ -542,7 +542,7 @@ PyDoc_STRVAR(Vector_resize_4d_doc, ); static PyObject *Vector_resize_4d(VectorObject *self) { - if (self->wrapped == Py_WRAP) { + if (self->flag & BASE_MATH_FLAG_IS_WRAP) { PyErr_SetString(PyExc_TypeError, "Vector.resize_4d(): " "cannot resize wrapped data - only python vectors"); @@ -586,7 +586,7 @@ static PyObject *Vector_to_2d(VectorObject *self) if (BaseMath_ReadCallback(self) == -1) return NULL; - return Vector_CreatePyObject(self->vec, 2, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(self->vec, 2, Py_TYPE(self)); } PyDoc_STRVAR(Vector_to_3d_doc, ".. method:: to_3d()\n" @@ -604,7 +604,7 @@ static PyObject *Vector_to_3d(VectorObject *self) return NULL; memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 3)); - return Vector_CreatePyObject(tvec, 3, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(tvec, 3, Py_TYPE(self)); } PyDoc_STRVAR(Vector_to_4d_doc, ".. method:: to_4d()\n" @@ -622,7 +622,7 @@ static PyObject *Vector_to_4d(VectorObject *self) return NULL; memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 4)); - return Vector_CreatePyObject(tvec, 4, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(tvec, 4, Py_TYPE(self)); } PyDoc_STRVAR(Vector_to_tuple_doc, @@ -797,7 +797,7 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args) vec_to_quat(quat, vec, track, up); - return Quaternion_CreatePyObject(quat, Py_NEW, NULL); + return Quaternion_CreatePyObject(quat, NULL); } PyDoc_STRVAR(Vector_orthogonal_doc, @@ -829,7 +829,7 @@ static PyObject *Vector_orthogonal(VectorObject *self) else ortho_v2_v2(vec, self->vec); - return Vector_CreatePyObject(vec, self->size, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(vec, self->size, Py_TYPE(self)); } @@ -877,7 +877,7 @@ static PyObject *Vector_reflect(VectorObject *self, PyObject *value) normalize_v3(mirror); reflect_v3_v3v3(reflect, vec, mirror); - return Vector_CreatePyObject(reflect, self->size, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(reflect, self->size, Py_TYPE(self)); } PyDoc_STRVAR(Vector_cross_doc, @@ -910,7 +910,7 @@ static PyObject *Vector_cross(VectorObject *self, PyObject *value) return NULL; if (self->size == 3) { - ret = Vector_CreatePyObject(NULL, 3, Py_NEW, Py_TYPE(self)); + ret = Vector_CreatePyObject(NULL, 3, Py_TYPE(self)); cross_v3_v3v3(((VectorObject *)ret)->vec, self->vec, tvec); } else { @@ -1102,7 +1102,7 @@ static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value) rotation_between_vecs_to_quat(quat, vec_a, vec_b); - return Quaternion_CreatePyObject(quat, Py_NEW, NULL); + return Quaternion_CreatePyObject(quat, NULL); } PyDoc_STRVAR(Vector_project_doc, @@ -1148,7 +1148,7 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value) for (x = 0; x < size; x++) { vec[x] = (float)dot * tvec[x]; } - return Vector_CreatePyObject(vec, size, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(vec, size, Py_TYPE(self)); } PyDoc_STRVAR(Vector_lerp_doc, @@ -1287,7 +1287,7 @@ static PyObject *Vector_slerp(VectorObject *self, PyObject *args) ret_vec[x] = (w[0] * self_vec[x]) + (w[1] * other_vec[x]); } - return Vector_CreatePyObject(ret_vec, size, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(ret_vec, size, Py_TYPE(self)); } PyDoc_STRVAR(Vector_rotate_doc, @@ -1336,7 +1336,7 @@ static PyObject *Vector_copy(VectorObject *self) if (BaseMath_ReadCallback(self) == -1) return NULL; - return Vector_CreatePyObject(self->vec, self->size, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(self->vec, self->size, Py_TYPE(self)); } static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args) { @@ -1540,8 +1540,7 @@ static PyObject *Vector_add(PyObject *v1, PyObject *v2) } vec = PyMem_Malloc(vec1->size * sizeof(float)); - - if (vec == NULL) { /*allocation failure*/ + if (vec == NULL) { PyErr_SetString(PyExc_MemoryError, "Vector(): " "problem allocating pointer space"); @@ -1612,8 +1611,7 @@ static PyObject *Vector_sub(PyObject *v1, PyObject *v2) } vec = PyMem_Malloc(vec1->size * sizeof(float)); - - if (vec == NULL) { /*allocation failure*/ + if (vec == NULL) { PyErr_SetString(PyExc_MemoryError, "Vector(): " "problem allocating pointer space"); @@ -1705,8 +1703,7 @@ int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, static PyObject *vector_mul_float(VectorObject *vec, const float scalar) { float *tvec = PyMem_Malloc(vec->size * sizeof(float)); - - if (tvec == NULL) { /*allocation failure*/ + if (tvec == NULL) { PyErr_SetString(PyExc_MemoryError, "vec * float: " "problem allocating pointer space"); @@ -1765,7 +1762,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) vec_size = ((MatrixObject *)v2)->num_col; } - return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(vec1)); + return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(vec1)); } else if (QuaternionObject_Check(v2)) { /* VEC * QUAT */ @@ -1791,7 +1788,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) copy_v3_v3(tvec, vec1->vec); mul_qt_v3(quat2->quat, tvec); - return Vector_CreatePyObject(tvec, 3, Py_NEW, Py_TYPE(vec1)); + return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec1)); #endif /* ------ to be removed ------*/ } @@ -1923,7 +1920,7 @@ static PyObject *Vector_div(PyObject *v1, PyObject *v2) vec = PyMem_Malloc(vec1->size * sizeof(float)); - if (vec == NULL) { /*allocation failure*/ + if (vec == NULL) { PyErr_SetString(PyExc_MemoryError, "vec / value: " "problem allocating pointer space"); @@ -2308,7 +2305,7 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) axis_to++; } - return Vector_CreatePyObject(vec, axis_to, Py_NEW, Py_TYPE(self)); + return Vector_CreatePyObject(vec, axis_to, Py_TYPE(self)); } /* Set the items of this vector using a swizzle. @@ -2994,15 +2991,12 @@ PyTypeObject vector_Type = { NULL }; -/*------------------------Vector_CreatePyObject (internal)------------- - * creates a new vector object - * pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - * (i.e. it was allocated elsewhere by MEM_mallocN()) - * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - * (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTypeObject *base_type) +PyObject *Vector_CreatePyObject( + const float *vec, const int size, + PyTypeObject *base_type) { VectorObject *self; + float *vec_alloc; if (size < 2) { PyErr_SetString(PyExc_RuntimeError, @@ -3010,44 +3004,72 @@ PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTy return NULL; } - self = base_type ? (VectorObject *)base_type->tp_alloc(base_type, 0) : - (VectorObject *)PyObject_GC_New(VectorObject, &vector_Type); + vec_alloc = PyMem_Malloc(size * sizeof(float)); + if (UNLIKELY(vec_alloc == NULL)) { + PyErr_SetString(PyExc_MemoryError, + "Vector(): " + "problem allocating data"); + return NULL; + } + self = BASE_MATH_NEW(VectorObject, vector_Type, base_type); if (self) { + self->vec = vec_alloc; self->size = size; /* init callbacks as NULL */ self->cb_user = NULL; self->cb_type = self->cb_subtype = 0; - if (type == Py_WRAP) { - self->vec = vec; - self->wrapped = Py_WRAP; + if (vec) { + memcpy(self->vec, vec, size * sizeof(float)); } - else if (type == Py_NEW) { - self->vec = PyMem_Malloc(size * sizeof(float)); - if (vec) { - memcpy(self->vec, vec, size * sizeof(float)); + else { /* new empty */ + fill_vn_fl(self->vec, size, 0.0f); + if (size == 4) { /* do the homogeneous thing */ + self->vec[3] = 1.0f; } - else { /* new empty */ - fill_vn_fl(self->vec, size, 0.0f); - if (size == 4) { /* do the homogeneous thing */ - self->vec[3] = 1.0f; - } - } - self->wrapped = Py_NEW; - } - else { - Py_FatalError("Vector(): invalid type!"); } + self->flag = BASE_MATH_FLAG_DEFAULT; + } + else { + PyMem_Free(vec_alloc); + } + + return (PyObject *)self; +} + +PyObject *Vector_CreatePyObject_wrap( + float *vec, const int size, + PyTypeObject *base_type) +{ + VectorObject *self; + + if (size < 2) { + PyErr_SetString(PyExc_RuntimeError, + "Vector(): invalid size"); + return NULL; + } + + self = BASE_MATH_NEW(VectorObject, vector_Type, base_type); + if (self) { + self->size = size; + + /* init callbacks as NULL */ + self->cb_user = NULL; + self->cb_type = self->cb_subtype = 0; + + self->vec = vec; + self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP; } return (PyObject *) self; } -PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, unsigned char cb_type, unsigned char cb_subtype) +PyObject *Vector_CreatePyObject_cb( + PyObject *cb_user, int size, + unsigned char cb_type, unsigned char cb_subtype) { - float dummy[4] = {0.0, 0.0, 0.0, 0.0}; /* dummy init vector, callbacks will be used on access */ - VectorObject *self = (VectorObject *)Vector_CreatePyObject(dummy, size, Py_NEW, NULL); + VectorObject *self = (VectorObject *)Vector_CreatePyObject(NULL, size, NULL); if (self) { Py_INCREF(cb_user); self->cb_user = cb_user; @@ -3059,11 +3081,15 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, unsigned char cb return (PyObject *)self; } -PyObject *Vector_CreatePyObject_alloc(const float *vec, const int size, PyTypeObject *base_type) +PyObject *Vector_CreatePyObject_alloc( + float *vec, const int size, + PyTypeObject *base_type) { - VectorObject *vect_ob; - vect_ob = (VectorObject *)Vector_CreatePyObject((float *)vec, size, Py_WRAP, base_type); - vect_ob->wrapped = Py_NEW; + VectorObject *self; + self = (VectorObject *)Vector_CreatePyObject_wrap(vec, size, base_type); + if (self) { + self->flag = BASE_MATH_FLAG_DEFAULT; + } - return (PyObject *)vect_ob; + return (PyObject *)self; } diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h index 2074270670a..74ca3336f4b 100644 --- a/source/blender/python/mathutils/mathutils_Vector.h +++ b/source/blender/python/mathutils/mathutils_Vector.h @@ -34,13 +34,25 @@ extern PyTypeObject vector_Type; typedef struct { BASE_MATH_MEMBERS(vec); - int size; /* vec size 2,3 or 4 */ + int size; /* vec size 2 or more */ } VectorObject; /*prototypes*/ -PyObject *Vector_CreatePyObject(float *vec, const int size, const int type, PyTypeObject *base_type); -PyObject *Vector_CreatePyObject_cb(PyObject *user, int size, - unsigned char cb_type, unsigned char subtype); -PyObject *Vector_CreatePyObject_alloc(const float *vec, const int size, PyTypeObject *base_type); +PyObject *Vector_CreatePyObject( + const float *vec, const int size, + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT; +PyObject *Vector_CreatePyObject_wrap( + float *vec, const int size, + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +PyObject *Vector_CreatePyObject_cb( + PyObject *user, int size, + unsigned char cb_type, unsigned char subtype + ) ATTR_WARN_UNUSED_RESULT; +PyObject *Vector_CreatePyObject_alloc( + float *vec, const int size, + PyTypeObject *base_type + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); #endif /* __MATHUTILS_VECTOR_H__ */ diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 0f0ffe9fec5..b496ee1fbf6 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -42,6 +42,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/python_utildefines.h" /*-------------------------DOC STRINGS ---------------------------*/ PyDoc_STRVAR(M_Geometry_doc, @@ -72,48 +73,37 @@ PyDoc_STRVAR(M_Geometry_intersect_ray_tri_doc, ); static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args) { - VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; - float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; + const char *error_prefix = "intersect_ray_tri"; + PyObject *py_ray, *py_ray_off, *py_tri[3]; + float dir[3], orig[3], tri[3][3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; float det, inv_det, u, v, t; int clip = 1; + int i; - if (!PyArg_ParseTuple(args, - "O!O!O!O!O!|i:intersect_ray_tri", - &vector_Type, &vec1, - &vector_Type, &vec2, - &vector_Type, &vec3, - &vector_Type, &ray, - &vector_Type, &ray_off, &clip)) + if (!PyArg_ParseTuple( + args, "OOOOO|i:intersect_ray_tri", + UNPACK3_EX(&, py_tri, ), &py_ray, &py_ray_off, &clip)) { return NULL; } - if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { - PyErr_SetString(PyExc_ValueError, - "only 3D vectors for all parameters"); - return NULL; - } - if (BaseMath_ReadCallback(vec1) == -1 || - BaseMath_ReadCallback(vec2) == -1 || - BaseMath_ReadCallback(vec3) == -1 || - BaseMath_ReadCallback(ray) == -1 || - BaseMath_ReadCallback(ray_off) == -1) + if (((mathutils_array_parse(dir, 3, 3, py_ray, error_prefix) != -1) && + (mathutils_array_parse(orig, 3, 3, py_ray_off, error_prefix) != -1)) == 0) { return NULL; } - copy_v3_v3(v1, vec1->vec); - copy_v3_v3(v2, vec2->vec); - copy_v3_v3(v3, vec3->vec); + for (i = 0; i < ARRAY_SIZE(tri); i++) { + if (mathutils_array_parse(tri[i], 2, 2 | MU_ARRAY_SPILL, py_tri[i], error_prefix) == -1) { + return NULL; + } + } - copy_v3_v3(dir, ray->vec); normalize_v3(dir); - copy_v3_v3(orig, ray_off->vec); - /* find vectors for two edges sharing v1 */ - sub_v3_v3v3(e1, v2, v1); - sub_v3_v3v3(e2, v3, v1); + sub_v3_v3v3(e1, tri[1], tri[0]); + sub_v3_v3v3(e2, tri[2], tri[0]); /* begin calculating determinant - also used to calculated U parameter */ cross_v3_v3v3(pvec, dir, e2); @@ -128,7 +118,7 @@ static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject * inv_det = 1.0f / det; /* calculate distance from v1 to ray origin */ - sub_v3_v3v3(tvec, orig, v1); + sub_v3_v3v3(tvec, orig, tri[0]); /* calculate U parameter and test bounds */ u = dot_v3v3(tvec, pvec) * inv_det; @@ -157,7 +147,7 @@ static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject * mul_v3_fl(dir, t); add_v3_v3v3(pvec, orig, dir); - return Vector_CreatePyObject(pvec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(pvec, 3, NULL); } /* Line-Line intersection using algorithm from mathworld.wolfram.com */ @@ -179,82 +169,49 @@ PyDoc_STRVAR(M_Geometry_intersect_line_line_doc, ); static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject *args) { + const char *error_prefix = "intersect_line_line"; PyObject *tuple; - VectorObject *vec1, *vec2, *vec3, *vec4; - float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3]; - - if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line", - &vector_Type, &vec1, - &vector_Type, &vec2, - &vector_Type, &vec3, - &vector_Type, &vec4)) + PyObject *py_lines[4]; + float lines[4][3], i1[3], i2[3]; + int len; + int result; + + if (!PyArg_ParseTuple( + args, "OOOO:intersect_line_line", + UNPACK4_EX(&, py_lines, ))) { return NULL; } - if (vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) { - PyErr_SetString(PyExc_ValueError, - "vectors must be of the same size"); - return NULL; - } - - if (BaseMath_ReadCallback(vec1) == -1 || - BaseMath_ReadCallback(vec2) == -1 || - BaseMath_ReadCallback(vec3) == -1 || - BaseMath_ReadCallback(vec4) == -1) + if ((((len = mathutils_array_parse(lines[0], 2, 3, py_lines[0], error_prefix)) != -1) && + (mathutils_array_parse(lines[1], len, len, py_lines[1], error_prefix) != -1) && + (mathutils_array_parse(lines[2], len, len, py_lines[2], error_prefix) != -1) && + (mathutils_array_parse(lines[3], len, len, py_lines[3], error_prefix) != -1)) == 0) { return NULL; } - if (vec1->size == 3 || vec1->size == 2) { - int result; - - if (vec1->size == 3) { - copy_v3_v3(v1, vec1->vec); - copy_v3_v3(v2, vec2->vec); - copy_v3_v3(v3, vec3->vec); - copy_v3_v3(v4, vec4->vec); - } - else { - v1[0] = vec1->vec[0]; - v1[1] = vec1->vec[1]; - v1[2] = 0.0f; - - v2[0] = vec2->vec[0]; - v2[1] = vec2->vec[1]; - v2[2] = 0.0f; - - v3[0] = vec3->vec[0]; - v3[1] = vec3->vec[1]; - v3[2] = 0.0f; - - v4[0] = vec4->vec[0]; - v4[1] = vec4->vec[1]; - v4[2] = 0.0f; - } + if (len == 2) { + lines[0][2] = lines[1][2] = lines[2][2] = lines[3][2] = 0.0f; + } - result = isect_line_line_v3(v1, v2, v3, v4, i1, i2); - /* The return-code isnt exposed, - * this way we can check know how close the lines are. */ - if (result == 1) { - closest_to_line_v3(i2, i1, v3, v4); - } + result = isect_line_line_v3(UNPACK4(lines), i1, i2); + /* The return-code isnt exposed, + * this way we can check know how close the lines are. */ + if (result == 1) { + closest_to_line_v3(i2, i1, lines[2], lines[3]); + } - if (result == 0) { - /* colinear */ - Py_RETURN_NONE; - } - else { - tuple = PyTuple_New(2); - PyTuple_SET_ITEM(tuple, 0, Vector_CreatePyObject(i1, vec1->size, Py_NEW, NULL)); - PyTuple_SET_ITEM(tuple, 1, Vector_CreatePyObject(i2, vec1->size, Py_NEW, NULL)); - return tuple; - } + if (result == 0) { + /* colinear */ + Py_RETURN_NONE; } else { - PyErr_SetString(PyExc_ValueError, - "2D/3D vectors only"); - return NULL; + tuple = PyTuple_New(2); + PyTuple_SET_ITEMS(tuple, + Vector_CreatePyObject(i1, len, NULL), + Vector_CreatePyObject(i2, len, NULL)); + return tuple; } } @@ -277,31 +234,30 @@ PyDoc_STRVAR(M_Geometry_intersect_sphere_sphere_2d_doc, ); static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), PyObject *args) { + const char *error_prefix = "intersect_sphere_sphere_2d"; PyObject *ret; - VectorObject *vec_a, *vec_b; - const float *v_a, *v_b; + PyObject *py_v_a, *py_v_b; + float v_a[2], v_b[2]; float rad_a, rad_b; float v_ab[2]; float dist; - if (!PyArg_ParseTuple(args, "O!fO!f:intersect_sphere_sphere_2d", - &vector_Type, &vec_a, &rad_a, - &vector_Type, &vec_b, &rad_b)) + if (!PyArg_ParseTuple( + args, "OfOf:intersect_sphere_sphere_2d", + &py_v_a, &rad_a, + &py_v_b, &rad_b)) { return NULL; } - if (BaseMath_ReadCallback(vec_a) == -1 || - BaseMath_ReadCallback(vec_b) == -1) + if (((mathutils_array_parse(v_a, 2, 2, py_v_a, error_prefix) != -1) && + (mathutils_array_parse(v_b, 2, 2, py_v_b, error_prefix) != -1)) == 0) { return NULL; } ret = PyTuple_New(2); - v_a = vec_a->vec; - v_b = vec_b->vec; - sub_v2_v2v2(v_ab, v_b, v_a); dist = len_v2(v_ab); @@ -313,8 +269,9 @@ static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), P (dist < FLT_EPSILON)) { /* out of range */ - PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); - PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); + PyTuple_SET_ITEMS(ret, + Py_INCREF_RET(Py_None), + Py_INCREF_RET(Py_None)); } else { const float dist_delta = ((rad_a * rad_a) - (rad_b * rad_b) + (dist * dist)) / (2.0f * dist); @@ -331,94 +288,51 @@ static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), P i2[0] = i_cent[0] - h * v_ab[1] / dist; i2[1] = i_cent[1] + h * v_ab[0] / dist; - PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(i1, 2, Py_NEW, NULL)); - PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(i2, 2, Py_NEW, NULL)); + PyTuple_SET_ITEMS(ret, + Vector_CreatePyObject(i1, 2, NULL), + Vector_CreatePyObject(i2, 2, NULL)); } return ret; } PyDoc_STRVAR(M_Geometry_normal_doc, -".. function:: normal(v1, v2, v3, v4=None)\n" +".. function:: normal(vectors)\n" "\n" -" Returns the normal of the 3D tri or quad.\n" +" Returns the normal of a 3D polygon.\n" "\n" -" :arg v1: Point1\n" -" :type v1: :class:`mathutils.Vector`\n" -" :arg v2: Point2\n" -" :type v2: :class:`mathutils.Vector`\n" -" :arg v3: Point3\n" -" :type v3: :class:`mathutils.Vector`\n" -" :arg v4: Point4 (optional)\n" -" :type v4: :class:`mathutils.Vector`\n" +" :arg vectors: Vectors to calculate normals with\n" +" :type vectors: sequence of 3 or more 3d vector\n" " :rtype: :class:`mathutils.Vector`\n" ); static PyObject *M_Geometry_normal(PyObject *UNUSED(self), PyObject *args) { - VectorObject *vec1, *vec2, *vec3, *vec4; + float (*coords)[3]; + int coords_len; float n[3]; + PyObject *ret = NULL; - if (PyTuple_GET_SIZE(args) == 3) { - if (!PyArg_ParseTuple(args, "O!O!O!:normal", - &vector_Type, &vec1, - &vector_Type, &vec2, - &vector_Type, &vec3)) - { - return NULL; - } - - if (vec1->size != vec2->size || vec1->size != vec3->size) { - PyErr_SetString(PyExc_ValueError, - "vectors must be of the same size"); - return NULL; - } - if (vec1->size < 3) { - PyErr_SetString(PyExc_ValueError, - "2D vectors unsupported"); - return NULL; - } - - if (BaseMath_ReadCallback(vec1) == -1 || - BaseMath_ReadCallback(vec2) == -1 || - BaseMath_ReadCallback(vec3) == -1) - { - return NULL; - } - - normal_tri_v3(n, vec1->vec, vec2->vec, vec3->vec); + /* use */ + if (PyTuple_GET_SIZE(args) == 1) { + args = PyTuple_GET_ITEM(args, 0); } - else { - if (!PyArg_ParseTuple(args, "O!O!O!O!:normal", - &vector_Type, &vec1, - &vector_Type, &vec2, - &vector_Type, &vec3, - &vector_Type, &vec4)) - { - return NULL; - } - if (vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) { - PyErr_SetString(PyExc_ValueError, - "vectors must be of the same size"); - return NULL; - } - if (vec1->size < 3) { - PyErr_SetString(PyExc_ValueError, - "2D vectors unsupported"); - return NULL; - } - if (BaseMath_ReadCallback(vec1) == -1 || - BaseMath_ReadCallback(vec2) == -1 || - BaseMath_ReadCallback(vec3) == -1 || - BaseMath_ReadCallback(vec4) == -1) - { - return NULL; - } + if ((coords_len = mathutils_array_parse_alloc_v((float **)&coords, 3 | MU_ARRAY_SPILL, args, "normal")) == -1) { + return NULL; + } - normal_quad_v3(n, vec1->vec, vec2->vec, vec3->vec, vec4->vec); + if (coords_len < 3) { + PyErr_SetString(PyExc_ValueError, + "Expected 3 or more vectors"); + goto finally; } - return Vector_CreatePyObject(n, 3, Py_NEW, NULL); + normal_poly_v3(n, (const float (*)[3])coords, coords_len); + ret = Vector_CreatePyObject(n, 3, NULL); + +finally: + PyMem_Free(coords); + return ret; } /* --------------------------------- AREA FUNCTIONS-------------------- */ @@ -438,40 +352,26 @@ PyDoc_STRVAR(M_Geometry_area_tri_doc, ); static PyObject *M_Geometry_area_tri(PyObject *UNUSED(self), PyObject *args) { - VectorObject *vec1, *vec2, *vec3; - - if (!PyArg_ParseTuple(args, "O!O!O!:area_tri", - &vector_Type, &vec1, - &vector_Type, &vec2, - &vector_Type, &vec3)) + const char *error_prefix = "area_tri"; + PyObject *py_tri[3]; + float tri[3][3]; + int len; + + if (!PyArg_ParseTuple( + args, "OOO:area_tri", + UNPACK3_EX(&, py_tri, ))) { return NULL; } - if (vec1->size != vec2->size || vec1->size != vec3->size) { - PyErr_SetString(PyExc_ValueError, - "vectors must be of the same size"); - return NULL; - } - - if (BaseMath_ReadCallback(vec1) == -1 || - BaseMath_ReadCallback(vec2) == -1 || - BaseMath_ReadCallback(vec3) == -1) + if ((((len = mathutils_array_parse(tri[0], 2, 3, py_tri[0], error_prefix)) != -1) && + (mathutils_array_parse(tri[1], len, len, py_tri[1], error_prefix) != -1) && + (mathutils_array_parse(tri[2], len, len, py_tri[2], error_prefix) != -1)) == 0) { return NULL; } - if (vec1->size == 3) { - return PyFloat_FromDouble(area_tri_v3(vec1->vec, vec2->vec, vec3->vec)); - } - else if (vec1->size == 2) { - return PyFloat_FromDouble(area_tri_v2(vec1->vec, vec2->vec, vec3->vec)); - } - else { - PyErr_SetString(PyExc_ValueError, - "only 2D,3D vectors are supported"); - return NULL; - } + return PyFloat_FromDouble((len == 3 ? area_tri_v3 : area_tri_v2)(UNPACK3(tri))); } PyDoc_STRVAR(M_Geometry_volume_tetrahedron_doc, @@ -491,33 +391,25 @@ PyDoc_STRVAR(M_Geometry_volume_tetrahedron_doc, ); static PyObject *M_Geometry_volume_tetrahedron(PyObject *UNUSED(self), PyObject *args) { - VectorObject *vec1, *vec2, *vec3, *vec4; + const char *error_prefix = "volume_tetrahedron"; + PyObject *py_tet[4]; + float tet[4][3]; + int i; - if (!PyArg_ParseTuple(args, "O!O!O!O!:volume_tetrahedron", - &vector_Type, &vec1, - &vector_Type, &vec2, - &vector_Type, &vec3, - &vector_Type, &vec4)) + if (!PyArg_ParseTuple( + args, "OOOO:volume_tetrahedron", + UNPACK4_EX(&, py_tet, ))) { return NULL; } - if (vec1->size < 3 || vec2->size < 3 || vec3->size < 3 || vec4->size < 3) { - PyErr_SetString(PyExc_ValueError, - "geometry.volume_tetrahedron(...): " - " can't use 2D Vectors"); - return NULL; - } - - if (BaseMath_ReadCallback(vec1) == -1 || - BaseMath_ReadCallback(vec2) == -1 || - BaseMath_ReadCallback(vec3) == -1 || - BaseMath_ReadCallback(vec4) == -1) - { - return NULL; + for (i = 0; i < ARRAY_SIZE(tet); i++) { + if (mathutils_array_parse(tet[i], 3, 3 | MU_ARRAY_SPILL, py_tet[i], error_prefix) == -1) { + return NULL; + } } - return PyFloat_FromDouble(volume_tetrahedron_v3(vec1->vec, vec2->vec, vec3->vec, vec4->vec)); + return PyFloat_FromDouble(volume_tetrahedron_v3(UNPACK4(tet))); } PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc, @@ -538,27 +430,27 @@ PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc, ); static PyObject *M_Geometry_intersect_line_line_2d(PyObject *UNUSED(self), PyObject *args) { - VectorObject *line_a1, *line_a2, *line_b1, *line_b2; + const char *error_prefix = "intersect_line_line_2d"; + PyObject *py_lines[4]; + float lines[4][2]; float vi[2]; - if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line_2d", - &vector_Type, &line_a1, - &vector_Type, &line_a2, - &vector_Type, &line_b1, - &vector_Type, &line_b2)) + int i; + + if (!PyArg_ParseTuple( + args, "OOOO:intersect_line_line_2d", + UNPACK4_EX(&, py_lines, ))) { return NULL; } - - if (BaseMath_ReadCallback(line_a1) == -1 || - BaseMath_ReadCallback(line_a2) == -1 || - BaseMath_ReadCallback(line_b1) == -1 || - BaseMath_ReadCallback(line_b2) == -1) - { - return NULL; + + for (i = 0; i < ARRAY_SIZE(lines); i++) { + if (mathutils_array_parse(lines[i], 2, 2 | MU_ARRAY_SPILL, py_lines[i], error_prefix) == -1) { + return NULL; + } } - if (isect_seg_seg_v2_point(line_a1->vec, line_a2->vec, line_b1->vec, line_b2->vec, vi) == 1) { - return Vector_CreatePyObject(vi, 2, Py_NEW, NULL); + if (isect_seg_seg_v2_point(UNPACK4(lines), vi) == 1) { + return Vector_CreatePyObject(vi, 2, NULL); } else { Py_RETURN_NONE; @@ -585,38 +477,31 @@ PyDoc_STRVAR(M_Geometry_intersect_line_plane_doc, ); static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObject *args) { - VectorObject *line_a, *line_b, *plane_co, *plane_no; + const char *error_prefix = "intersect_line_plane"; + PyObject *py_line_a, *py_line_b, *py_plane_co, *py_plane_no; + float line_a[3], line_b[3], plane_co[3], plane_no[3]; float isect[3]; int no_flip = false; - if (!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_line_plane", - &vector_Type, &line_a, - &vector_Type, &line_b, - &vector_Type, &plane_co, - &vector_Type, &plane_no, - &no_flip)) + if (!PyArg_ParseTuple( + args, "OOOO|i:intersect_line_plane", + &py_line_a, &py_line_b, &py_plane_co, &py_plane_no, + &no_flip)) { return NULL; } - if (BaseMath_ReadCallback(line_a) == -1 || - BaseMath_ReadCallback(line_b) == -1 || - BaseMath_ReadCallback(plane_co) == -1 || - BaseMath_ReadCallback(plane_no) == -1) + if (((mathutils_array_parse(line_a, 3, 3 | MU_ARRAY_SPILL, py_line_a, error_prefix) != -1) && + (mathutils_array_parse(line_b, 3, 3 | MU_ARRAY_SPILL, py_line_b, error_prefix) != -1) && + (mathutils_array_parse(plane_co, 3, 3 | MU_ARRAY_SPILL, py_plane_co, error_prefix) != -1) && + (mathutils_array_parse(plane_no, 3, 3 | MU_ARRAY_SPILL, py_plane_no, error_prefix) != -1)) == 0) { return NULL; } - if (ELEM(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { - PyErr_SetString(PyExc_ValueError, - "geometry.intersect_line_plane(...): " - " can't use 2D Vectors"); - return NULL; - } - /* TODO: implements no_flip */ - if (isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec) == 1) { - return Vector_CreatePyObject(isect, 3, Py_NEW, NULL); + if (isect_line_plane_v3(isect, line_a, line_b, plane_co, plane_no) == 1) { + return Vector_CreatePyObject(isect, 3, NULL); } else { Py_RETURN_NONE; @@ -641,68 +526,59 @@ PyDoc_STRVAR(M_Geometry_intersect_plane_plane_doc, ); static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObject *args) { + const char *error_prefix = "intersect_plane_plane"; PyObject *ret, *ret_co, *ret_no; - VectorObject *plane_a_co, *plane_a_no, *plane_b_co, *plane_b_no; + PyObject *py_plane_a_co, *py_plane_a_no, *py_plane_b_co, *py_plane_b_no; + float plane_a_co[3], plane_a_no[3], plane_b_co[3], plane_b_no[3]; float isect_co[3]; float isect_no[3]; - if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_plane_plane", - &vector_Type, &plane_a_co, - &vector_Type, &plane_a_no, - &vector_Type, &plane_b_co, - &vector_Type, &plane_b_no)) + if (!PyArg_ParseTuple( + args, "OOOO:intersect_plane_plane", + &py_plane_a_co, &py_plane_a_no, &py_plane_b_co, &py_plane_b_no)) { return NULL; } - if (BaseMath_ReadCallback(plane_a_co) == -1 || - BaseMath_ReadCallback(plane_a_no) == -1 || - BaseMath_ReadCallback(plane_b_co) == -1 || - BaseMath_ReadCallback(plane_b_no) == -1) + if (((mathutils_array_parse(plane_a_co, 3, 3 | MU_ARRAY_SPILL, py_plane_a_co, error_prefix) != -1) && + (mathutils_array_parse(plane_a_no, 3, 3 | MU_ARRAY_SPILL, py_plane_a_no, error_prefix) != -1) && + (mathutils_array_parse(plane_b_co, 3, 3 | MU_ARRAY_SPILL, py_plane_b_co, error_prefix) != -1) && + (mathutils_array_parse(plane_b_no, 3, 3 | MU_ARRAY_SPILL, py_plane_b_no, error_prefix) != -1)) == 0) { return NULL; } - if (ELEM(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) { - PyErr_SetString(PyExc_ValueError, - "geometry.intersect_plane_plane(...): " - " can't use 2D Vectors"); - return NULL; - } - if (isect_plane_plane_v3(isect_co, isect_no, - plane_a_co->vec, plane_a_no->vec, - plane_b_co->vec, plane_b_no->vec)) + plane_a_co, plane_a_no, + plane_b_co, plane_b_no)) { normalize_v3(isect_no); - ret_co = Vector_CreatePyObject(isect_co, 3, Py_NEW, NULL); - ret_no = Vector_CreatePyObject(isect_no, 3, Py_NEW, NULL); + ret_co = Vector_CreatePyObject(isect_co, 3, NULL); + ret_no = Vector_CreatePyObject(isect_no, 3, NULL); } else { - ret_co = Py_None; - ret_no = Py_None; - - Py_INCREF(ret_co); - Py_INCREF(ret_no); + ret_co = Py_INCREF_RET(Py_None); + ret_no = Py_INCREF_RET(Py_None); } ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, ret_co); - PyTuple_SET_ITEM(ret, 1, ret_no); + PyTuple_SET_ITEMS(ret, + ret_co, + ret_no); return ret; } PyDoc_STRVAR(M_Geometry_intersect_line_sphere_doc, ".. function:: intersect_line_sphere(line_a, line_b, sphere_co, sphere_radius, clip=True)\n" "\n" -" Takes a lines (as 2 vectors), a sphere as a point and a radius and\n" +" Takes a line (as 2 points) and a sphere (as a point and a radius) and\n" " returns the intersection\n" "\n" -" :arg line_a: First point of the first line\n" +" :arg line_a: First point of the line\n" " :type line_a: :class:`mathutils.Vector`\n" -" :arg line_b: Second point of the first line\n" +" :arg line_b: Second point of the line\n" " :type line_b: :class:`mathutils.Vector`\n" " :arg sphere_co: The center of the sphere\n" " :type sphere_co: :class:`mathutils.Vector`\n" @@ -713,35 +589,28 @@ PyDoc_STRVAR(M_Geometry_intersect_line_sphere_doc, ); static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObject *args) { - VectorObject *line_a, *line_b, *sphere_co; + const char *error_prefix = "intersect_line_sphere"; + PyObject *py_line_a, *py_line_b, *py_sphere_co; + float line_a[3], line_b[3], sphere_co[3]; float sphere_radius; int clip = true; float isect_a[3]; float isect_b[3]; - if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere", - &vector_Type, &line_a, - &vector_Type, &line_b, - &vector_Type, &sphere_co, - &sphere_radius, &clip)) + if (!PyArg_ParseTuple( + args, "OOOf|i:intersect_line_sphere", + &py_line_a, &py_line_b, &py_sphere_co, &sphere_radius, &clip)) { return NULL; } - if (BaseMath_ReadCallback(line_a) == -1 || - BaseMath_ReadCallback(line_b) == -1 || - BaseMath_ReadCallback(sphere_co) == -1) + if (((mathutils_array_parse(line_a, 3, 3 | MU_ARRAY_SPILL, py_line_a, error_prefix) != -1) && + (mathutils_array_parse(line_b, 3, 3 | MU_ARRAY_SPILL, py_line_b, error_prefix) != -1) && + (mathutils_array_parse(sphere_co, 3, 3 | MU_ARRAY_SPILL, py_sphere_co, error_prefix) != -1)) == 0) { return NULL; } - - if (ELEM(2, line_a->size, line_b->size, sphere_co->size)) { - PyErr_SetString(PyExc_ValueError, - "geometry.intersect_line_sphere(...): " - " can't use 2D Vectors"); - return NULL; - } else { bool use_a = true; bool use_b = true; @@ -749,14 +618,14 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje PyObject *ret = PyTuple_New(2); - switch (isect_line_sphere_v3(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) { + switch (isect_line_sphere_v3(line_a, line_b, sphere_co, sphere_radius, isect_a, isect_b)) { case 1: - if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; + if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; use_b = false; break; case 2: - if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; - if (!(!clip || (((lambda = line_point_factor_v3(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false; + if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; + if (!(!clip || (((lambda = line_point_factor_v3(isect_b, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false; break; default: use_a = false; @@ -764,11 +633,9 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje break; } - if (use_a) { PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_a, 3, Py_NEW, NULL)); } - else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); } - - if (use_b) { PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_b, 3, Py_NEW, NULL)); } - else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); } + PyTuple_SET_ITEMS(ret, + use_a ? Vector_CreatePyObject(isect_a, 3, NULL) : Py_INCREF_RET(Py_None), + use_b ? Vector_CreatePyObject(isect_b, 3, NULL) : Py_INCREF_RET(Py_None)); return ret; } @@ -778,12 +645,12 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje PyDoc_STRVAR(M_Geometry_intersect_line_sphere_2d_doc, ".. function:: intersect_line_sphere_2d(line_a, line_b, sphere_co, sphere_radius, clip=True)\n" "\n" -" Takes a lines (as 2 vectors), a sphere as a point and a radius and\n" +" Takes a line (as 2 points) and a sphere (as a point and a radius) and\n" " returns the intersection\n" "\n" -" :arg line_a: First point of the first line\n" +" :arg line_a: First point of the line\n" " :type line_a: :class:`mathutils.Vector`\n" -" :arg line_b: Second point of the first line\n" +" :arg line_b: Second point of the line\n" " :type line_b: :class:`mathutils.Vector`\n" " :arg sphere_co: The center of the sphere\n" " :type sphere_co: :class:`mathutils.Vector`\n" @@ -794,25 +661,25 @@ PyDoc_STRVAR(M_Geometry_intersect_line_sphere_2d_doc, ); static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyObject *args) { - VectorObject *line_a, *line_b, *sphere_co; + const char *error_prefix = "intersect_line_sphere_2d"; + PyObject *py_line_a, *py_line_b, *py_sphere_co; + float line_a[2], line_b[2], sphere_co[2]; float sphere_radius; int clip = true; float isect_a[2]; float isect_b[2]; - if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere_2d", - &vector_Type, &line_a, - &vector_Type, &line_b, - &vector_Type, &sphere_co, - &sphere_radius, &clip)) + if (!PyArg_ParseTuple( + args, "OOOf|i:intersect_line_sphere_2d", + &py_line_a, &py_line_b, &py_sphere_co, &sphere_radius, &clip)) { return NULL; } - if (BaseMath_ReadCallback(line_a) == -1 || - BaseMath_ReadCallback(line_b) == -1 || - BaseMath_ReadCallback(sphere_co) == -1) + if (((mathutils_array_parse(line_a, 2, 2 | MU_ARRAY_SPILL, py_line_a, error_prefix) != -1) && + (mathutils_array_parse(line_b, 2, 2 | MU_ARRAY_SPILL, py_line_b, error_prefix) != -1) && + (mathutils_array_parse(sphere_co, 2, 2 | MU_ARRAY_SPILL, py_sphere_co, error_prefix) != -1)) == 0) { return NULL; } @@ -823,14 +690,14 @@ static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyO PyObject *ret = PyTuple_New(2); - switch (isect_line_sphere_v2(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) { + switch (isect_line_sphere_v2(line_a, line_b, sphere_co, sphere_radius, isect_a, isect_b)) { case 1: - if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; + if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; use_b = false; break; case 2: - if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; - if (!(!clip || (((lambda = line_point_factor_v2(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false; + if (!(!clip || (((lambda = line_point_factor_v2(isect_a, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_a = false; + if (!(!clip || (((lambda = line_point_factor_v2(isect_b, line_a, line_b)) >= 0.0f) && (lambda <= 1.0f)))) use_b = false; break; default: use_a = false; @@ -838,11 +705,9 @@ static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyO break; } - if (use_a) { PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(isect_a, 2, Py_NEW, NULL)); } - else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); } - - if (use_b) { PyTuple_SET_ITEM(ret, 1, Vector_CreatePyObject(isect_b, 2, Py_NEW, NULL)); } - else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); } + PyTuple_SET_ITEMS(ret, + use_a ? Vector_CreatePyObject(isect_a, 2, NULL) : Py_INCREF_RET(Py_None), + use_b ? Vector_CreatePyObject(isect_b, 2, NULL) : Py_INCREF_RET(Py_None)); return ret; } @@ -863,43 +728,35 @@ PyDoc_STRVAR(M_Geometry_intersect_point_line_doc, ); static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObject *args) { - VectorObject *pt, *line_1, *line_2; - float pt_in[3], pt_out[3], l1[3], l2[3]; + const char *error_prefix = "intersect_point_line"; + PyObject *py_pt, *py_line_a, *py_line_b; + float pt[3], pt_out[3], line_a[3], line_b[3]; float lambda; PyObject *ret; int size = 2; - if (!PyArg_ParseTuple(args, "O!O!O!:intersect_point_line", - &vector_Type, &pt, - &vector_Type, &line_1, - &vector_Type, &line_2)) + if (!PyArg_ParseTuple( + args, "OOO:intersect_point_line", + &py_pt, &py_line_a, &py_line_b)) { return NULL; } - if (BaseMath_ReadCallback(pt) == -1 || - BaseMath_ReadCallback(line_1) == -1 || - BaseMath_ReadCallback(line_2) == -1) + /* accept 2d verts */ + if ((((size = mathutils_array_parse(pt, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_pt, error_prefix)) != -1) && + (mathutils_array_parse(line_a, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_line_a, error_prefix) != -1) && + (mathutils_array_parse(line_b, 3, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_line_b, error_prefix) != -1)) == 0) { return NULL; } - /* accept 2d verts */ - if (pt->size >= 3) { copy_v3_v3(pt_in, pt->vec); size = 3; } - else { copy_v2_v2(pt_in, pt->vec); pt_in[2] = 0.0f; } - - if (line_1->size >= 3) { copy_v3_v3(l1, line_1->vec); size = 3; } - else { copy_v2_v2(l1, line_1->vec); l1[2] = 0.0f; } - - if (line_2->size >= 3) { copy_v3_v3(l2, line_2->vec); size = 3; } - else { copy_v2_v2(l2, line_2->vec); l2[2] = 0.0f; } - /* do the calculation */ - lambda = closest_to_line_v3(pt_out, pt_in, l1, l2); + lambda = closest_to_line_v3(pt_out, pt, line_a, line_b); ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(pt_out, size, Py_NEW, NULL)); - PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(lambda)); + PyTuple_SET_ITEMS(ret, + Vector_CreatePyObject(pt_out, size, NULL), + PyFloat_FromDouble(lambda)); return ret; } @@ -921,38 +778,30 @@ PyDoc_STRVAR(M_Geometry_intersect_point_tri_doc, ); static PyObject *M_Geometry_intersect_point_tri(PyObject *UNUSED(self), PyObject *args) { - VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; + const char *error_prefix = "intersect_point_tri"; + PyObject *py_pt, *py_tri[3]; + float pt[3], tri[3][3]; float vi[3]; + int i; - if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri", - &vector_Type, &pt_vec, - &vector_Type, &tri_p1, - &vector_Type, &tri_p2, - &vector_Type, &tri_p3)) + if (!PyArg_ParseTuple( + args, "OOOO:intersect_point_tri", + &py_pt, UNPACK3_EX(&, py_tri, ))) { return NULL; } - if (BaseMath_ReadCallback(pt_vec) == -1 || - BaseMath_ReadCallback(tri_p1) == -1 || - BaseMath_ReadCallback(tri_p2) == -1 || - BaseMath_ReadCallback(tri_p3) == -1) - { + if (mathutils_array_parse(pt, 3, 3 | MU_ARRAY_SPILL, py_pt, error_prefix) == -1) { return NULL; } - - if (pt_vec->size < 3 || - tri_p1->size < 3 || - tri_p2->size < 3 || - tri_p3->size < 3) - { - PyErr_SetString(PyExc_ValueError, - "One of more of the vector arguments wasn't a 3D vector"); - return NULL; + for (i = 0; i < ARRAY_SIZE(tri); i++) { + if (mathutils_array_parse(tri[i], 3, 3 | MU_ARRAY_SPILL, py_tri[i], error_prefix) == -1) { + return NULL; + } } - if (isect_point_tri_v3(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec, vi)) { - return Vector_CreatePyObject(vi, 3, Py_NEW, NULL); + if (isect_point_tri_v3(pt, UNPACK3(tri), vi)) { + return Vector_CreatePyObject(vi, 3, NULL); } else { Py_RETURN_NONE; @@ -976,26 +825,28 @@ PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc, ); static PyObject *M_Geometry_intersect_point_tri_2d(PyObject *UNUSED(self), PyObject *args) { - VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; - - if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri_2d", - &vector_Type, &pt_vec, - &vector_Type, &tri_p1, - &vector_Type, &tri_p2, - &vector_Type, &tri_p3)) + const char *error_prefix = "intersect_point_tri_2d"; + PyObject *py_pt, *py_tri[3]; + float pt[2], tri[3][2]; + int i; + + if (!PyArg_ParseTuple( + args, "OOOO:intersect_point_tri_2d", + &py_pt, UNPACK3_EX(&, py_tri, ))) { return NULL; } - - if (BaseMath_ReadCallback(pt_vec) == -1 || - BaseMath_ReadCallback(tri_p1) == -1 || - BaseMath_ReadCallback(tri_p2) == -1 || - BaseMath_ReadCallback(tri_p3) == -1) - { + + if (mathutils_array_parse(pt, 2, 2 | MU_ARRAY_SPILL, py_pt, error_prefix) == -1) { return NULL; } + for (i = 0; i < ARRAY_SIZE(tri); i++) { + if (mathutils_array_parse(tri[i], 2, 2 | MU_ARRAY_SPILL, py_tri[i], error_prefix) == -1) { + return NULL; + } + } - return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec)); + return PyLong_FromLong(isect_point_tri_v2(pt, UNPACK3(tri))); } PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc, @@ -1019,28 +870,28 @@ PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc, ); static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyObject *args) { - VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4; + const char *error_prefix = "intersect_point_quad_2d"; + PyObject *py_pt, *py_quad[4]; + float pt[2], quad[4][2]; + int i; - if (!PyArg_ParseTuple(args, "O!O!O!O!O!:intersect_point_quad_2d", - &vector_Type, &pt_vec, - &vector_Type, &quad_p1, - &vector_Type, &quad_p2, - &vector_Type, &quad_p3, - &vector_Type, &quad_p4)) + if (!PyArg_ParseTuple( + args, "OOOOO:intersect_point_quad_2d", + &py_pt, UNPACK4_EX(&, py_quad, ))) { return NULL; } - if (BaseMath_ReadCallback(pt_vec) == -1 || - BaseMath_ReadCallback(quad_p1) == -1 || - BaseMath_ReadCallback(quad_p2) == -1 || - BaseMath_ReadCallback(quad_p3) == -1 || - BaseMath_ReadCallback(quad_p4) == -1) - { + if (mathutils_array_parse(pt, 2, 2 | MU_ARRAY_SPILL, py_pt, error_prefix) == -1) { return NULL; } + for (i = 0; i < ARRAY_SIZE(quad); i++) { + if (mathutils_array_parse(quad[i], 2, 2 | MU_ARRAY_SPILL, py_quad[i], error_prefix) == -1) { + return NULL; + } + } - return PyLong_FromLong(isect_point_quad_v2(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec)); + return PyLong_FromLong(isect_point_quad_v2(pt, UNPACK4(quad))); } PyDoc_STRVAR(M_Geometry_distance_point_to_plane_doc, @@ -1059,35 +910,27 @@ PyDoc_STRVAR(M_Geometry_distance_point_to_plane_doc, ); static PyObject *M_Geometry_distance_point_to_plane(PyObject *UNUSED(self), PyObject *args) { - VectorObject *pt, *plane_co, *plane_no; + const char *error_prefix = "distance_point_to_plane"; + PyObject *py_pt, *py_plane_co, *py_plane_no; + float pt[3], plane_co[3], plane_no[3]; float plane[4]; - if (!PyArg_ParseTuple(args, "O!O!O!:distance_point_to_plane", - &vector_Type, &pt, - &vector_Type, &plane_co, - &vector_Type, &plane_no)) - { - return NULL; - } - - if (pt->size != 3 || - plane_co->size != 3 || - plane_no->size != 3) + if (!PyArg_ParseTuple( + args, "OOO:distance_point_to_plane", + &py_pt, &py_plane_co, &py_plane_no)) { - PyErr_SetString(PyExc_ValueError, - "One of more of the vector arguments wasn't a 3D vector"); return NULL; } - if (BaseMath_ReadCallback(pt) == -1 || - BaseMath_ReadCallback(plane_co) == -1 || - BaseMath_ReadCallback(plane_no) == -1) + if (((mathutils_array_parse(pt, 3, 3 | MU_ARRAY_SPILL, py_pt, error_prefix) != -1) && + (mathutils_array_parse(plane_co, 3, 3 | MU_ARRAY_SPILL, py_plane_co, error_prefix) != -1) && + (mathutils_array_parse(plane_no, 3, 3 | MU_ARRAY_SPILL, py_plane_no, error_prefix) != -1)) == 0) { return NULL; } - plane_from_point_normal_v3(plane, plane_co->vec, plane_no->vec); - return PyFloat_FromDouble(dist_signed_to_plane_v3(pt->vec, plane)); + plane_from_point_normal_v3(plane, plane_co, plane_no); + return PyFloat_FromDouble(dist_signed_to_plane_v3(pt, plane)); } PyDoc_STRVAR(M_Geometry_barycentric_transform_doc, @@ -1114,53 +957,37 @@ PyDoc_STRVAR(M_Geometry_barycentric_transform_doc, ); static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObject *args) { - VectorObject *vec_pt; - VectorObject *vec_t1_tar, *vec_t2_tar, *vec_t3_tar; - VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src; - float vec[3]; - - if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!::barycentric_transform", - &vector_Type, &vec_pt, - &vector_Type, &vec_t1_src, - &vector_Type, &vec_t2_src, - &vector_Type, &vec_t3_src, - &vector_Type, &vec_t1_tar, - &vector_Type, &vec_t2_tar, - &vector_Type, &vec_t3_tar)) - { - return NULL; - } + const char *error_prefix = "barycentric_transform"; + PyObject *py_pt_src, *py_tri_src[3], *py_tri_dst[3]; + float pt_src[3], pt_dst[3], tri_src[3][3], tri_dst[3][3]; + int i; - if (vec_pt->size != 3 || - vec_t1_src->size != 3 || - vec_t2_src->size != 3 || - vec_t3_src->size != 3 || - vec_t1_tar->size != 3 || - vec_t2_tar->size != 3 || - vec_t3_tar->size != 3) + if (!PyArg_ParseTuple( + args, "OOOOOOO:barycentric_transform", + &py_pt_src, + UNPACK3_EX(&, py_tri_src, ), + UNPACK3_EX(&, py_tri_dst, ))) { - PyErr_SetString(PyExc_ValueError, - "One of more of the vector arguments wasn't a 3D vector"); return NULL; } - if (BaseMath_ReadCallback(vec_pt) == -1 || - BaseMath_ReadCallback(vec_t1_src) == -1 || - BaseMath_ReadCallback(vec_t2_src) == -1 || - BaseMath_ReadCallback(vec_t3_src) == -1 || - BaseMath_ReadCallback(vec_t1_tar) == -1 || - BaseMath_ReadCallback(vec_t2_tar) == -1 || - BaseMath_ReadCallback(vec_t3_tar) == -1) - { + if (mathutils_array_parse(pt_src, 2, 2 | MU_ARRAY_SPILL, py_pt_src, error_prefix) == -1) { return NULL; } + for (i = 0; i < ARRAY_SIZE(tri_src); i++) { + if (((mathutils_array_parse(tri_src[i], 3, 3 | MU_ARRAY_SPILL, py_tri_src[i], error_prefix) != -1) && + (mathutils_array_parse(tri_dst[i], 3, 3 | MU_ARRAY_SPILL, py_tri_dst[i], error_prefix) != -1)) == 0) + { + return NULL; + } + } transform_point_by_tri_v3( - vec, vec_pt->vec, - vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec, - vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec); + pt_dst, pt_src, + UNPACK3(tri_dst), + UNPACK3(tri_src)); - return Vector_CreatePyObject(vec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(pt_dst, 3, NULL); } PyDoc_STRVAR(M_Geometry_points_in_planes_doc, @@ -1180,8 +1007,9 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a float (*planes)[4]; unsigned int planes_len; - if (!PyArg_ParseTuple(args, "O:points_in_planes", - &py_planes)) + if (!PyArg_ParseTuple( + args, "O:points_in_planes", + &py_planes)) { return NULL; } @@ -1233,10 +1061,7 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a if (l == len) { /* ok */ /* python */ - PyObject *item = Vector_CreatePyObject(potentialVertex, 3, Py_NEW, NULL); - PyList_Append(py_verts, item); - Py_DECREF(item); - + PyList_APPEND(py_verts, Vector_CreatePyObject(potentialVertex, 3, NULL)); planes_used[i] = planes_used[j] = planes_used[k] = true; } } @@ -1252,17 +1077,16 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a /* now make a list of used planes */ for (i = 0; i < len; i++) { if (planes_used[i]) { - PyObject *item = PyLong_FromLong(i); - PyList_Append(py_plane_index, item); - Py_DECREF(item); + PyList_APPEND(py_plane_index, PyLong_FromLong(i)); } } PyMem_Free(planes_used); { PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, py_verts); - PyTuple_SET_ITEM(ret, 1, py_plane_index); + PyTuple_SET_ITEMS(ret, + py_verts, + py_plane_index); return ret; } } @@ -1290,58 +1114,45 @@ PyDoc_STRVAR(M_Geometry_interpolate_bezier_doc, ); static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject *args) { - VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2; + const char *error_prefix = "interpolate_bezier"; + PyObject *py_data[4]; + float data[4][4] = {{0.0f}}; int resolu; - int dims; + int dims = 0; int i; float *coord_array, *fp; PyObject *list; - float k1[4] = {0.0, 0.0, 0.0, 0.0}; - float h1[4] = {0.0, 0.0, 0.0, 0.0}; - float k2[4] = {0.0, 0.0, 0.0, 0.0}; - float h2[4] = {0.0, 0.0, 0.0, 0.0}; - - - if (!PyArg_ParseTuple(args, "O!O!O!O!i:interpolate_bezier", - &vector_Type, &vec_k1, - &vector_Type, &vec_h1, - &vector_Type, &vec_h2, - &vector_Type, &vec_k2, &resolu)) + if (!PyArg_ParseTuple( + args, "OOOOi:interpolate_bezier", + UNPACK4_EX(&, py_data, ), &resolu)) { return NULL; } + for (i = 0; i < 4; i++) { + int dims_tmp; + if ((((dims_tmp = mathutils_array_parse(data[i], 2, 2 | MU_ARRAY_SPILL, py_data[i], error_prefix)) == -1))) { + return NULL; + } + dims = max_ii(dims, dims_tmp); + } + if (resolu <= 1) { PyErr_SetString(PyExc_ValueError, "resolution must be 2 or over"); return NULL; } - if (BaseMath_ReadCallback(vec_k1) == -1 || - BaseMath_ReadCallback(vec_h1) == -1 || - BaseMath_ReadCallback(vec_k2) == -1 || - BaseMath_ReadCallback(vec_h2) == -1) - { - return NULL; - } - - dims = max_iiii(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size); - - for (i = 0; i < vec_k1->size; i++) k1[i] = vec_k1->vec[i]; - for (i = 0; i < vec_h1->size; i++) h1[i] = vec_h1->vec[i]; - for (i = 0; i < vec_k2->size; i++) k2[i] = vec_k2->vec[i]; - for (i = 0; i < vec_h2->size; i++) h2[i] = vec_h2->vec[i]; - - coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier"); + coord_array = MEM_callocN(dims * (resolu) * sizeof(float), error_prefix); for (i = 0; i < dims; i++) { - BKE_curve_forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array + i, resolu - 1, sizeof(float) * dims); + BKE_curve_forward_diff_bezier(UNPACK4_EX(, data, [i]), coord_array + i, resolu - 1, sizeof(float) * dims); } list = PyList_New(resolu); fp = coord_array; for (i = 0; i < resolu; i++, fp = fp + dims) { - PyList_SET_ITEM(list, i, Vector_CreatePyObject(fp, dims, Py_NEW, NULL)); + PyList_SET_ITEM(list, i, Vector_CreatePyObject(fp, dims, NULL)); } MEM_freeN(coord_array); return list; @@ -1581,8 +1392,9 @@ static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlis } ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(tot_width)); - PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(tot_height)); + PyTuple_SET_ITEMS(ret, + PyFloat_FromDouble(tot_width), + PyFloat_FromDouble(tot_height)); return ret; } diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c index 519778aea7d..199c2e02da4 100644 --- a/source/blender/python/mathutils/mathutils_kdtree.c +++ b/source/blender/python/mathutils/mathutils_kdtree.c @@ -35,6 +35,7 @@ #include "BLI_kdtree.h" #include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" #include "mathutils.h" #include "mathutils_kdtree.h" /* own include */ @@ -58,9 +59,10 @@ static void kdtree_nearest_to_py_tuple(const KDTreeNearest *nearest, PyObject *p BLI_assert(nearest->index >= 0); BLI_assert(PyTuple_GET_SIZE(py_retval) == 3); - PyTuple_SET_ITEM(py_retval, 0, Vector_CreatePyObject((float *)nearest->co, 3, Py_NEW, NULL)); - PyTuple_SET_ITEM(py_retval, 1, PyLong_FromLong(nearest->index)); - PyTuple_SET_ITEM(py_retval, 2, PyFloat_FromDouble(nearest->dist)); + PyTuple_SET_ITEMS(py_retval, + Vector_CreatePyObject((float *)nearest->co, 3, NULL), + PyLong_FromLong(nearest->index), + PyFloat_FromDouble(nearest->dist)); } static PyObject *kdtree_nearest_to_py(const KDTreeNearest *nearest) @@ -126,7 +128,7 @@ static void PyKDTree__tp_dealloc(PyKDTree *self) } PyDoc_STRVAR(py_kdtree_insert_doc, -".. method:: insert(index, co)\n" +".. method:: insert(co, index)\n" "\n" " Insert a point into the KDTree.\n" "\n" @@ -171,6 +173,10 @@ PyDoc_STRVAR(py_kdtree_balance_doc, ".. method:: balance()\n" "\n" " Balance the tree.\n" +"\n" +".. note::\n" +"\n" +" This builds the entire tree, avoid calling after each insertion.\n" ); static PyObject *py_kdtree_balance(PyKDTree *self) { diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c index 8dfa7904300..f0449c23dcd 100644 --- a/source/blender/python/mathutils/mathutils_noise.c +++ b/source/blender/python/mathutils/mathutils_noise.c @@ -34,8 +34,6 @@ #include <Python.h> -#include "structseq.h" - #include "BLI_math.h" #include "BLI_noise.h" #include "BLI_utildefines.h" @@ -311,7 +309,7 @@ static PyObject *M_Noise_random_unit_vector(PyObject *UNUSED(self), PyObject *ar norm = normalize_vn(vec, size); } - return Vector_CreatePyObject(vec, size, Py_NEW, NULL); + return Vector_CreatePyObject(vec, size, NULL); } /* This is dumb, most people will want a unit vector anyway, since this doesn't have uniform distribution over a sphere*/ #if 0 @@ -340,7 +338,7 @@ static PyObject *M_Noise_random_vector(PyObject *UNUSED(self), PyObject *args) rand_vn(vec, size); - return Vector_CreatePyObject(vec, size, Py_NEW, NULL); + return Vector_CreatePyObject(vec, size, NULL); } #endif @@ -414,7 +412,7 @@ static PyObject *M_Noise_noise_vector(PyObject *UNUSED(self), PyObject *args) noise_vector(vec[0], vec[1], vec[2], nb, r_vec); - return Vector_CreatePyObject(r_vec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(r_vec, 3, NULL); } PyDoc_STRVAR(M_Noise_turbulence_doc, @@ -486,7 +484,7 @@ static PyObject *M_Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *arg return NULL; vTurb(vec[0], vec[1], vec[2], oct, hd, nb, as, fs, r_vec); - return Vector_CreatePyObject(r_vec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(r_vec, 3, NULL); } /* F. Kenton Musgrave's fractal functions */ @@ -738,7 +736,7 @@ static PyObject *M_Noise_voronoi(PyObject *UNUSED(self), PyObject *args) voronoi(vec[0], vec[1], vec[2], da, pa, me, dtype); for (i = 0; i < 4; i++) { - PyList_SET_ITEM(list, i, Vector_CreatePyObject(pa + 3 * i, 3, Py_NEW, NULL)); + PyList_SET_ITEM(list, i, Vector_CreatePyObject(pa + 3 * i, 3, NULL)); } return Py_BuildValue("[[ffff]O]", da[0], da[1], da[2], da[3], list); @@ -790,7 +788,7 @@ static PyObject *M_Noise_cell_vector(PyObject *UNUSED(self), PyObject *args) return NULL; cellNoiseV(vec[0], vec[1], vec[2], r_vec); - return Vector_CreatePyObject(r_vec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(r_vec, 3, NULL); } static PyMethodDef M_Noise_methods[] = { diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript index 7f459444a39..ebd131082e4 100644 --- a/source/blender/render/SConscript +++ b/source/blender/render/SConscript @@ -38,7 +38,6 @@ incs = [ '../blenkernel', '../blenlib', '../imbuf', - '../include', '../makesdna', '../makesrna', '../../../intern/mikktspace', diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 4b0473f7483..5edf970c129 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -144,6 +144,7 @@ void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char void RE_engine_update_progress(RenderEngine *engine, float progress); void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak); void RE_engine_report(RenderEngine *engine, int type, const char *msg); +void RE_engine_set_error_message(RenderEngine *engine, const char *msg); int RE_engine_render(struct Render *re, int do_all); diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 61795c2c173..d1b6673c792 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -144,7 +144,7 @@ typedef struct RenderResult { /* render info text */ char *text; - + char *error; } RenderResult; diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h index 9c0835af56f..3607e66a237 100644 --- a/source/blender/render/intern/include/rayintersection.h +++ b/source/blender/render/intern/include/rayintersection.h @@ -121,7 +121,7 @@ typedef struct Isect { /* arbitrary, but can't use e.g. FLT_MAX because of precision issues */ #define RE_RAYTRACE_MAXDIST 1e15f -#define RE_RAYTRACE_EPSILON -FLT_EPSILON +#define RE_RAYTRACE_EPSILON 0.0f #ifdef __cplusplus } diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c index 9b22c7d8bad..4aa2f4e919e 100644 --- a/source/blender/render/intern/source/bake.c +++ b/source/blender/render/intern/source/bake.c @@ -54,8 +54,6 @@ #include "IMB_imbuf.h" #include "IMB_colormanagement.h" -#include "RE_bake.h" - /* local include */ #include "rayintersection.h" #include "rayobject.h" @@ -374,8 +372,8 @@ static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, bs->vcol->b = col[2]; } else { - const char *imcol = (char *)(bs->rect + bs->rectx * y + x); - copy_v4_v4_char((char *)imcol, (char *)col); + char *imcol = (char *)(bs->rect + bs->rectx * y + x); + copy_v4_v4_char(imcol, (char *)col); } } if (bs->rect_mask) { diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index c732aa4664b..35878f664ea 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -82,9 +82,7 @@ #include "BKE_particle.h" #include "BKE_scene.h" - #include "PIL_time.h" -#include "IMB_imbuf_types.h" #include "envmap.h" #include "occlusion.h" @@ -103,8 +101,6 @@ #include "zbuf.h" #include "sunsky.h" -#include "RE_render_ext.h" - /* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */ /* or for checking vertex normal flips */ #define FLT_EPSILON10 1.19209290e-06F @@ -2725,12 +2721,13 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) vlr->v4= NULL; /* to prevent float accuracy issues, we calculate normal in local object space (not world) */ - if (area_tri_v3(co3, co2, co1)>FLT_EPSILON) { - if (negative_scale) - normal_tri_v3(tmp, co1, co2, co3); - else - normal_tri_v3(tmp, co3, co2, co1); - add_v3_v3(n, tmp); + if (normal_tri_v3(tmp, co1, co2, co3) > FLT_EPSILON) { + if (negative_scale == false) { + add_v3_v3(n, tmp); + } + else { + sub_v3_v3(n, tmp); + } } vlr->mat= matar[ dl->col ]; @@ -5138,8 +5135,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; re->lights.first= re->lights.last= NULL; re->lampren.first= re->lampren.last= NULL; - - slurph_opt= 0; + re->i.partsdone = false; /* signal now in use for previewrender */ /* in localview, lamps are using normal layers, objects only local bits */ @@ -5201,8 +5197,6 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l re->i.totlamp= re->totlamp; re->stats_draw(re->sdh, &re->i); } - - slurph_opt= 1; } void RE_Database_Preprocess(Render *re) @@ -5242,7 +5236,7 @@ void RE_Database_Preprocess(Render *re) } if (!re->test_break(re->tbh)) - project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1); + project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1); /* Occlusion */ if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh)) @@ -5320,8 +5314,6 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0; re->lights.first= re->lights.last= NULL; - - slurph_opt= 0; /* in localview, lamps are using normal layers, objects only local bits */ if (re->lay & 0xFF000000) @@ -5342,7 +5334,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la database_init_objects(re, lay, 0, 0, NULL, timeoffset); if (!re->test_break(re->tbh)) - project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1); + project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1); /* do this in end, particles for example need cfra */ scene->r.cfra -= timeoffset; diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 06be00a5a5e..c3c70067836 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -55,14 +55,10 @@ /* this module */ #include "render_types.h" -#include "renderpipeline.h" #include "envmap.h" -#include "rendercore.h" #include "renderdatabase.h" #include "texture.h" #include "zbuf.h" -#include "initrender.h" - /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 54f142184e1..23ca376535e 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -46,9 +46,6 @@ #include "BKE_report.h" #include "BKE_scene.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - #include "RNA_access.h" #ifdef WITH_PYTHON @@ -358,6 +355,19 @@ void RE_engine_report(RenderEngine *engine, int type, const char *msg) BKE_report(engine->reports, type, msg); } +void RE_engine_set_error_message(RenderEngine *engine, const char *msg) +{ + Render *re = engine->re; + if (re != NULL) { + RenderResult *rr = RE_AcquireResultRead(re); + if (rr->error != NULL) { + MEM_freeN(rr->error); + } + rr->error = BLI_strdup(msg); + RE_ReleaseResult(re); + } +} + void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r) { RenderPart *pa; diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 2787ce99b13..833d1a75559 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -50,12 +50,10 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "BKE_main.h" #include "BKE_image.h" #include "RE_render_ext.h" -#include "renderpipeline.h" #include "render_types.h" #include "texture.h" diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 4bb5dc154a6..b5b75f47193 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -36,8 +36,6 @@ #include "MEM_guardedalloc.h" -#include "PIL_time.h" - #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_jitter.h" @@ -48,12 +46,8 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" - #include "BKE_camera.h" -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" - #ifdef WITH_QUICKTIME #include "quicktime_export.h" #endif @@ -62,10 +56,6 @@ #include "renderpipeline.h" #include "render_types.h" -#include "rendercore.h" -#include "pixelshading.h" -#include "zbuf.h" - /* Own includes */ #include "initrender.h" diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index 0c6341fe9e5..f55dde588cb 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -56,9 +56,7 @@ #include "render_types.h" #include "rendercore.h" #include "renderdatabase.h" -#include "pixelshading.h" #include "shading.h" -#include "zbuf.h" /* ------------------------- Declarations --------------------------- */ diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index cb812013ac9..0c17d2dd15d 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -90,7 +90,6 @@ #include "renderdatabase.h" #include "rendercore.h" #include "initrender.h" -#include "shadbuf.h" #include "pixelblending.h" #include "zbuf.h" @@ -2380,6 +2379,7 @@ static void do_render_seq(Render *re) RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */ int cfra = re->r.cfra; SeqRenderData context; + int re_x, re_y; re->i.cfra = cfra; @@ -2393,14 +2393,19 @@ static void do_render_seq(Render *re) if ((re->r.mode & R_BORDER) && (re->r.mode & R_CROP) == 0) { /* if border rendering is used and cropping is disabled, final buffer should * be as large as the whole frame */ - context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene, - re->winx, re->winy, 100); + re_x = re->winx; + re_y = re->winy; } else { - context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene, - re->result->rectx, re->result->recty, 100); + re_x = re->result->rectx; + re_y = re->result->recty; } + BKE_sequencer_new_render_data( + re->eval_ctx, re->main, re->scene, + re_x, re_y, 100, + &context); + out = BKE_sequencer_give_ibuf(&context, cfra, 0); if (out) { @@ -2808,6 +2813,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr } BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + if (write_still) { + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); + } } BLI_callback_exec(re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE); @@ -3005,6 +3013,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (G.is_break == false) { BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); } } else { @@ -3088,6 +3097,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (G.is_break == false) { BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); } } } diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c index 460a6814f07..32fb196e1f3 100644 --- a/source/blender/render/intern/source/pixelblending.c +++ b/source/blender/render/intern/source/pixelblending.c @@ -38,7 +38,6 @@ /* own includes */ #include "render_types.h" -#include "renderpipeline.h" #include "pixelblending.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c index 014df802a78..ac4a7dbdccd 100644 --- a/source/blender/render/intern/source/pixelshading.c +++ b/source/blender/render/intern/source/pixelshading.c @@ -36,8 +36,6 @@ #include "BLI_utildefines.h" /* External modules: */ -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "DNA_group_types.h" #include "DNA_material_types.h" @@ -51,14 +49,11 @@ /* own module */ #include "render_types.h" -#include "renderpipeline.h" #include "renderdatabase.h" #include "texture.h" -#include "pixelblending.h" #include "rendercore.h" #include "shadbuf.h" #include "pixelshading.h" -#include "shading.h" #include "sunsky.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index ac2e85a33b3..ff23e3788ab 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -55,7 +55,6 @@ #include "DNA_particle_types.h" #include "render_types.h" -#include "renderdatabase.h" #include "texture.h" #include "pointdensity.h" diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 54fb3b8d8a3..3575b78f95f 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -27,7 +27,6 @@ * \ingroup render */ - #include <stdio.h> #include <math.h> #include <string.h> @@ -50,25 +49,18 @@ #include "BKE_node.h" - -#include "PIL_time.h" - #include "render_result.h" #include "render_types.h" -#include "renderpipeline.h" #include "rendercore.h" #include "renderdatabase.h" -#include "pixelblending.h" #include "pixelshading.h" #include "shading.h" -#include "texture.h" #include "volumetric.h" #include "rayintersection.h" #include "rayobject.h" #include "raycounter.h" - #define RAY_TRA 1 #define RAY_INSIDE 2 @@ -1562,7 +1554,7 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr) } if (shi->combinedflag & SCE_PASS_REFLECT) { - /* values in shr->spec can be greater then 1.0. + /* values in shr->spec can be greater than 1.0. * In this case the mircol uses a zero blending factor, so ignoring it is ok. * Fixes bug #18837 - when the spec is higher then 1.0, * diff can become a negative color - Campbell */ diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 08a82d026a0..de87fb200ae 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -35,13 +35,13 @@ #include "MEM_guardedalloc.h" +#include "BKE_appdir.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" #include "BLI_hash_md5.h" #include "BLI_path_util.h" #include "BLI_rect.h" #include "BLI_string.h" -#include "BLI_system.h" #include "BLI_threads.h" #include "BKE_image.h" @@ -94,6 +94,8 @@ void render_result_free(RenderResult *res) MEM_freeN(res->rectf); if (res->text) MEM_freeN(res->text); + if (res->error) + MEM_freeN(res->error); MEM_freeN(res); } @@ -1072,7 +1074,7 @@ void render_result_exr_file_path(Scene *scene, const char *layname, int sample, BLI_snprintf(name, sizeof(name), "%s_%s_%s%d.exr", fi, scene->id.name + 2, layname, sample); } - BLI_make_file_string("/", filepath, BLI_temp_dir_session(), name); + BLI_make_file_string("/", filepath, BKE_tempdir_session(), name); } /* only for temp buffer, makes exact copy of render result */ @@ -1163,14 +1165,14 @@ static void render_result_exr_file_cache_path(Scene *sce, const char *root, char BLI_hash_md5_buffer(G.main->name, strlen(G.main->name), path_digest); } else { - BLI_strncpy(dirname, BLI_temp_dir_base(), sizeof(dirname)); + BLI_strncpy(dirname, BKE_tempdir_base(), sizeof(dirname)); BLI_strncpy(filename, "UNSAVED", sizeof(filename)); } BLI_hash_md5_to_hexdigest(path_digest, path_hexdigest); /* Default to *non-volatile* tmp dir. */ if (*root == '\0') { - root = BLI_temp_dir_base(); + root = BKE_tempdir_base(); } BLI_snprintf(filename_full, sizeof(filename_full), "cached_RR_%s_%s_%s.exr", diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 1a8ab60d4d0..b1e00c4a451 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -48,7 +48,6 @@ #include "DNA_node_types.h" #include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "IMB_colormanagement.h" #include "BKE_image.h" @@ -68,9 +67,7 @@ #include "envmap.h" #include "pointdensity.h" #include "voxeldata.h" -#include "renderpipeline.h" #include "render_types.h" -#include "rendercore.h" #include "shading.h" #include "texture.h" #include "texture_ocean.h" @@ -3053,7 +3050,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h switch (mtex->texco) { case TEXCO_ANGMAP: /* only works with texture being "real" */ - /* use saacos(), fixes bug [#22398], float precision caused lo[2] to be slightly less then -1.0 */ + /* use saacos(), fixes bug [#22398], float precision caused lo[2] to be slightly less than -1.0 */ if (lo[0] || lo[1]) { /* check for zero case [#24807] */ fact= (1.0f/(float)M_PI)*saacos(lo[2])/(sqrtf(lo[0]*lo[0] + lo[1]*lo[1])); tempvec[0]= lo[0]*fact; diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index a67140c6334..5b054005bac 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -50,15 +50,7 @@ #include "DNA_material_types.h" #include "DNA_group_types.h" -#include "BKE_main.h" - -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" -#include "IMB_colormanagement.h" - /* local include */ -#include "rayintersection.h" -#include "rayobject.h" #include "renderpipeline.h" #include "render_result.h" #include "render_types.h" @@ -71,8 +63,6 @@ #include "sss.h" #include "zbuf.h" -#include "PIL_time.h" - /* own include */ #include "rendercore.h" diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 803da070e15..cafdbe2b488 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -78,11 +78,8 @@ #include "rayintersection.h" #include "rayobject.h" -#include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" -#include "texture.h" -#include "strand.h" #include "zbuf.h" /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 9d83ff1d7e8..0bd4815fb73 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -50,7 +50,6 @@ #include "PIL_time.h" -#include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" #include "rendercore.h" diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 7aca6b9ac87..01055d87a38 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -46,11 +46,9 @@ /* local include */ #include "raycounter.h" -#include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" #include "rendercore.h" -#include "shadbuf.h" #include "shading.h" #include "strand.h" #include "texture.h" diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index f909c585561..93e8c6a275a 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -47,9 +47,7 @@ /* local include */ #include "occlusion.h" -#include "renderpipeline.h" #include "render_types.h" -#include "pixelblending.h" #include "rendercore.h" #include "shadbuf.h" #include "sss.h" diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c index 7e9003aaee7..8ea3a753283 100644 --- a/source/blender/render/intern/source/sss.c +++ b/source/blender/render/intern/source/sss.c @@ -57,7 +57,6 @@ #include "BLF_translation.h" -#include "PIL_time.h" #include "DNA_material_types.h" @@ -68,11 +67,7 @@ /* this module */ #include "render_types.h" -#include "rendercore.h" -#include "renderdatabase.h" -#include "shading.h" #include "sss.h" -#include "zbuf.h" /* Generic Multiple Scattering API */ diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 485680da76f..6b52d4aa419 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -47,11 +47,8 @@ #include "render_types.h" -#include "initrender.h" #include "rendercore.h" #include "renderdatabase.h" -#include "renderpipeline.h" -#include "pixelblending.h" #include "shading.h" #include "strand.h" #include "zbuf.h" diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c index 1836b3f48a7..6078989f9f6 100644 --- a/source/blender/render/intern/source/sunsky.c +++ b/source/blender/render/intern/source/sunsky.c @@ -299,8 +299,7 @@ void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_ float theta, phi; float v[3]; - copy_v3_v3(v, (float *)varg); - normalize_v3(v); + normalize_v3_v3(v, varg); if (v[2] < 0.001f) { v[2] = 0.001f; diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c index 55f4bf3794d..5261374b34d 100644 --- a/source/blender/render/intern/source/texture_ocean.c +++ b/source/blender/render/intern/source/texture_ocean.c @@ -56,8 +56,6 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - /* ***** actual texture sampling ***** */ int ocean_texture(Tex *tex, const float texvec[2], TexResult *texres) { diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 072f4192ccc..69a1317cf7d 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -67,7 +67,6 @@ #include "render_types.h" -#include "renderdatabase.h" #include "texture.h" #include "voxeldata.h" diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 87e546ef24e..7e8f0e3e9fc 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -63,12 +63,10 @@ #include "pixelblending.h" #include "render_result.h" #include "render_types.h" -#include "renderpipeline.h" #include "renderdatabase.h" #include "rendercore.h" #include "shadbuf.h" #include "shading.h" -#include "sss.h" #include "strand.h" /* own includes */ @@ -2065,8 +2063,6 @@ static void zmask_rect(int *rectz, int *rectp, int xs, int ys, int neg) } - - /* ***************** ZBUFFER MAIN ROUTINES **************** */ void zbuffer_solid(RenderPart *pa, RenderLayer *rl, void(*fillfunc)(RenderPart *, ZSpan *, int, void *), void *data) diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 088bddc8a76..78b5d499644 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -130,10 +130,10 @@ if(WITH_BUILDINFO) add_definitions(-DWITH_BUILDINFO) endif() -if(WIN322) - list(APPEND INC - ../../../intern/utfconv - ) +if(WIN32) + if(WITH_INPUT_IME) + add_definitions(-DWITH_INPUT_IME) + endif() endif() if(WITH_COMPOSITOR) diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript index b93192d5067..a6f64f7cdae 100644 --- a/source/blender/windowmanager/SConscript +++ b/source/blender/windowmanager/SConscript @@ -65,11 +65,14 @@ if env['WITH_BF_COLLADA']: if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] - incs += ' ../../intern/utfconv' if env['BF_BUILDINFO']: defs.append('WITH_BUILDINFO') +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'): + if env['WITH_BF_IME']: + defs.append('WITH_INPUT_IME') + if env['WITH_BF_INTERNATIONAL']: defs.append('WITH_INTERNATIONAL') diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 19d7f37d144..b1692e44ad0 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -268,6 +268,7 @@ void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname); wmOperator *WM_operator_last_redo(const struct bContext *C); +ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, const short idcode); bool WM_operator_last_properties_init(struct wmOperator *op); bool WM_operator_last_properties_store(struct wmOperator *op); @@ -398,6 +399,7 @@ enum { WM_JOB_TYPE_CLIP_SOLVE_CAMERA, WM_JOB_TYPE_CLIP_PREFETCH, WM_JOB_TYPE_SEQ_BUILD_PROXY, + WM_JOB_TYPE_SEQ_BUILD_PREVIEW, /* add as needed, screencast, seq proxy build * if having hard coded values is a problem */ }; @@ -461,6 +463,10 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4 float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]); bool WM_event_is_tablet(const struct wmEvent *event); +#ifdef WITH_INPUT_IME +bool WM_event_is_ime_switch(const struct wmEvent *event); +#endif + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index ff252f0fc20..e64b1152252 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -169,7 +169,7 @@ enum { #define KM_OSKEY2 128 /* KM_MOD_ flags for wmKeyMapItem and wmEvent.alt/shift/oskey/ctrl */ -/* note that KM_ANY and false are used with these defines too */ +/* note that KM_ANY and KM_NOTHING are used with these defines too */ #define KM_MOD_FIRST 1 #define KM_MOD_SECOND 2 @@ -324,6 +324,9 @@ typedef struct wmNotifier { #define ND_NLA_ACTCHANGE (74<<16) #define ND_FCURVES_ORDER (75<<16) + /* NC_GPENCIL */ +#define ND_GPENCIL_EDITMODE (85<<16) + /* NC_GEOM Geometry */ /* Mesh, Curve, MetaBall, Armature, .. */ #define ND_SELECT (90<<16) @@ -554,9 +557,7 @@ typedef struct wmOperatorType { /* pointer to modal keymap, do not free! */ struct wmKeyMap *modalkeymap; - /* only used for operators defined with python - * use to store pointers to python functions */ - void *pyop_data; + /* python needs the operator type as well */ int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT; /* RNA integration */ @@ -567,6 +568,24 @@ typedef struct wmOperatorType { } wmOperatorType; +#ifdef WITH_INPUT_IME +/* *********** Input Method Editor (IME) *********** */ + +/* similar to GHOST_TEventImeData */ +typedef struct wmIMEData { + size_t result_len, composite_len; + + char *str_result; /* utf8 encoding */ + char *str_composite; /* utf8 encoding */ + + int cursor_pos; /* cursor position in the IME composition. */ + int sel_start; /* beginning of the selection */ + int sel_end; /* end of the selection */ + + bool is_ime_composing; +} wmIMEData; +#endif + /* **************** Paint Cursor ******************* */ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 7222447ac55..a6a3c6b0a28 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -39,8 +39,6 @@ #include "DNA_windowmanager_types.h" -#include "GHOST_C-api.h" - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -59,7 +57,6 @@ #include "WM_types.h" #include "wm_window.h" #include "wm_event_system.h" -#include "wm_event_types.h" #include "wm_draw.h" #include "wm.h" diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 145e9df7eb0..68592b44845 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -45,10 +45,8 @@ #include "BIF_glutil.h" #include "BKE_context.h" -#include "BKE_screen.h" #include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "UI_interface.h" #include "UI_interface_icons.h" @@ -58,8 +56,6 @@ #include "WM_api.h" #include "WM_types.h" #include "wm_event_system.h" -#include "wm.h" - /* ****************************************************** */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 42cb5f36701..d5c88ff156c 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -81,7 +81,6 @@ #include "wm_window.h" #include "wm_event_system.h" #include "wm_event_types.h" -#include "wm_draw.h" #ifndef NDEBUG # include "RNA_enum_types.h" @@ -542,7 +541,7 @@ void WM_event_print(const wmEvent *event) event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier, event->x, event->y, event->ascii, BLI_str_utf8_size(event->utf8_buf), event->utf8_buf, - event->keymap_idname, (void *)event); + event->keymap_idname, (const void *)event); if (ISNDOF(event->type)) { const wmNDOFMotionData *ndof = event->customdata; @@ -1708,16 +1707,12 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand /* remlink now, for load file case before removing*/ BLI_remlink(handlers, handler); - + if (val != EVT_FILESELECT_EXTERNAL_CANCEL) { - if (screen != handler->filescreen) { - ED_screen_full_prevspace(C, CTX_wm_area(C)); - } - else { - ED_area_prevspace(C, CTX_wm_area(C)); - } + ScrArea *sa = CTX_wm_area(C); + ED_screen_retore_temp_type(C, sa, screen != handler->filescreen); } - + wm_handler_op_context(C, handler); /* needed for UI_popup_menu_reports */ @@ -2323,6 +2318,14 @@ void wm_event_do_handlers(bContext *C) } for (sa = win->screen->areabase.first; sa; sa = sa->next) { + /* after restoring a screen from SCREENMAXIMIZED we have to wait + * with the screen handling till the region coordinates are updated */ + if (win->screen->skip_handling == true) { + /* restore for the next iteration of wm_event_do_handlers */ + win->screen->skip_handling = false; + break; + } + if (wm_event_inside_i(event, &sa->totrct)) { CTX_wm_area_set(C, sa); @@ -3050,6 +3053,13 @@ static void wm_event_add_mousemove(wmWindow *win, const wmEvent *event) void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int UNUSED(time), void *customdata) { wmWindow *owin; + + /* Having both, event and evt, can be highly confusing to work with, but is necessary for + * our current event system, so let's clear things up a bit: + * - data added to event only will be handled immediately, but will not be copied to the next event + * - data added to evt only stays, but is handled with the next event -> execution delay + * - data added to event and evt stays and is handled immediately + */ wmEvent event, *evt = win->eventstate; /* initialize and copy state (only mouse x y and modifiers) */ @@ -3190,6 +3200,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U case GHOST_kEventKeyUp: { GHOST_TEventKeyData *kd = customdata; + short keymodifier = KM_NOTHING; event.type = convert_key(kd->key); event.ascii = kd->ascii; memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); /* might be not null terminated*/ @@ -3230,28 +3241,38 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U } } - /* modifiers assign to eventstate, so next event gets the modifer (makes modifier key events work) */ /* assigning both first and second is strange - campbell */ switch (event.type) { - case LEFTSHIFTKEY: case RIGHTSHIFTKEY: - evt->shift = (event.val == KM_PRESS) ? - ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + if (event.val == KM_PRESS) { + if (evt->ctrl || evt->alt || evt->oskey) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.shift = evt->shift = keymodifier; break; - case LEFTCTRLKEY: case RIGHTCTRLKEY: - evt->ctrl = (event.val == KM_PRESS) ? - ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + if (event.val == KM_PRESS) { + if (evt->shift || evt->alt || evt->oskey) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.ctrl = evt->ctrl = keymodifier; break; - case LEFTALTKEY: case RIGHTALTKEY: - evt->alt = (event.val == KM_PRESS) ? - ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + case LEFTALTKEY: + case RIGHTALTKEY: + if (event.val == KM_PRESS) { + if (evt->ctrl || evt->shift || evt->oskey) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.alt = evt->alt = keymodifier; break; case OSKEY: - evt->oskey = (event.val == KM_PRESS) ? - ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + if (event.val == KM_PRESS) { + if (evt->ctrl || evt->alt || evt->shift) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.oskey = evt->oskey = keymodifier; break; default: if (event.val == KM_PRESS && event.keymodifier == 0) @@ -3374,6 +3395,33 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U break; } +#ifdef WITH_INPUT_IME + case GHOST_kEventImeCompositionStart: + { + event.val = KM_PRESS; + win->ime_data = customdata; + win->ime_data->is_ime_composing = true; + event.type = WM_IME_COMPOSITE_START; + wm_event_add(win, &event); + break; + } + case GHOST_kEventImeComposition: + { + event.val = KM_PRESS; + event.type = WM_IME_COMPOSITE_EVENT; + wm_event_add(win, &event); + break; + } + case GHOST_kEventImeCompositionEnd: + { + event.val = KM_PRESS; + win->ime_data->is_ime_composing = false; + event.type = WM_IME_COMPOSITE_END; + wm_event_add(win, &event); + break; + } +#endif /* WITH_INPUT_IME */ + } #if 0 @@ -3480,5 +3528,13 @@ bool WM_event_is_tablet(const struct wmEvent *event) return (event->tablet_data) ? true : false; } +#ifdef WITH_INPUT_IME +/* most os using ctrl/oskey + space to switch ime, avoid added space */ +bool WM_event_is_ime_switch(const struct wmEvent *event) +{ + return event->val == KM_PRESS && event->type == SPACEKEY && + (event->ctrl || event->oskey || event->shift || event->alt); +} +#endif /** \} */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 8a6b5046b73..c1c31f6795d 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -69,6 +69,7 @@ #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" +#include "BKE_appdir.h" #include "BKE_utildefines.h" #include "BKE_autoexec.h" #include "BKE_blender.h" @@ -96,8 +97,6 @@ #include "ED_view3d.h" #include "ED_util.h" -#include "RE_pipeline.h" /* only to report missing engine */ - #include "GHOST_C-api.h" #include "GHOST_Path-api.h" @@ -319,7 +318,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory) } /* update tempdir from user preferences */ - BLI_temp_dir_init(U.tempdir); + BKE_tempdir_init(U.tempdir); BKE_userdef_state(); } @@ -568,7 +567,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c G.relbase_valid = 0; if (!from_memory) { - const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); + const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); if (custom_file) { BLI_strncpy(startstr, custom_file, FILE_MAX); @@ -614,7 +613,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c if (BLI_listbase_is_empty(&wmbase)) { wm_clear_default_size(C); } - BLI_temp_dir_init(U.tempdir); + BKE_tempdir_init(U.tempdir); #ifdef WITH_PYTHON_SECURITY /* use alternative setting for security nuts @@ -727,7 +726,7 @@ void wm_read_history(void) struct RecentFile *recent; const char *line; int num; - const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); + const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); if (!cfgdir) return; @@ -764,7 +763,7 @@ static void write_history(void) return; /* will be NULL in background mode */ - user_config_dir = BLI_get_folder_create(BLENDER_USER_CONFIG, NULL); + user_config_dir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL); if (!user_config_dir) return; @@ -841,7 +840,7 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, OB_SOLID, false, false, R_ADDSKY, err_out); + IB_rect, OB_SOLID, false, false, false, R_ADDSKY, err_out); } else { ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, @@ -1024,7 +1023,7 @@ int wm_homefile_write_exec(bContext *C, wmOperator *op) /* update keymaps in user preferences */ WM_keyconfig_update(wm); - BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE); + BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE); printf("trying to save homefile at %s ", filepath); ED_editors_flush_edits(C, false); @@ -1055,7 +1054,7 @@ int wm_userpref_write_exec(bContext *C, wmOperator *op) /* update keymaps in user preferences */ WM_keyconfig_update(wm); - BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE); + BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE); printf("trying to save userpref at %s ", filepath); if (BKE_write_file_userdef(filepath, op->reports) == 0) { @@ -1096,14 +1095,14 @@ void wm_autosave_location(char *filepath) * BLI_make_file_string will create string that has it most likely on C:\ * through get_default_root(). * If there is no C:\tmp autosave fails. */ - if (!BLI_exists(BLI_temp_dir_base())) { - savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL); + if (!BLI_exists(BKE_tempdir_base())) { + savedir = BKE_appdir_folder_id_create(BLENDER_USER_AUTOSAVE, NULL); BLI_make_file_string("/", filepath, savedir, path); return; } #endif - BLI_make_file_string("/", filepath, BLI_temp_dir_base(), path); + BLI_make_file_string("/", filepath, BKE_tempdir_base(), path); } void WM_autosave_init(wmWindowManager *wm) @@ -1167,7 +1166,7 @@ void wm_autosave_delete(void) if (BLI_exists(filename)) { char str[FILE_MAX]; - BLI_make_file_string("/", str, BLI_temp_dir_base(), BLENDER_QUIT_FILE); + BLI_make_file_string("/", str, BKE_tempdir_base(), BLENDER_QUIT_FILE); /* if global undo; remove tempsave, otherwise rename */ if (U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, false, false); diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 3e287a3907b..46c3909f7bf 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -49,7 +49,6 @@ #include "WM_types.h" #include "wm.h" -#include "wm_event_system.h" #include "wm_subwindow.h" #include "wm_draw.h" diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index f762e19c969..cb03d022afd 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -40,9 +40,6 @@ #include "MEM_guardedalloc.h" -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" - #include "DNA_scene_types.h" #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" @@ -68,6 +65,7 @@ #include "BKE_report.h" #include "BKE_addon.h" +#include "BKE_appdir.h" #include "BKE_sequencer.h" /* free seq clipboard */ #include "BKE_material.h" /* clear_matcopybuf */ #include "BKE_tracking.h" /* free tracking clipboard */ @@ -98,6 +96,7 @@ #include "wm_window.h" #include "ED_armature.h" +#include "ED_gpencil.h" #include "ED_keyframing.h" #include "ED_node.h" #include "ED_render.h" @@ -110,7 +109,6 @@ #include "BLF_translation.h" #include "GPU_buffers.h" -#include "GPU_extensions.h" #include "GPU_draw.h" #include "GPU_init_exit.h" @@ -172,6 +170,8 @@ void WM_init(bContext *C, int argc, const char **argv) BLF_lang_set(NULL); + ED_spacemacros_init(); + /* note: there is a bug where python needs initializing before loading the * startup.blend because it may contain PyDrivers. It also needs to be after * initializing space types and other internal data. @@ -190,8 +190,6 @@ void WM_init(bContext *C, int argc, const char **argv) (void)argv; /* unused */ #endif - ED_spacemacros_init(); - if (!G.background && !wm_start_with_console) GHOST_toggleConsole(3); @@ -219,7 +217,7 @@ void WM_init(bContext *C, int argc, const char **argv) /* allow a path of "", this is what happens when making a new file */ #if 0 if (G.main->name[0] == 0) - BLI_make_file_string("/", G.main->name, BLI_getDefaultDocumentFolder(), "untitled.blend"); + BLI_make_file_string("/", G.main->name, BKE_appdir_folder_default(), "untitled.blend"); #endif BLI_strncpy(G.lib, G.main->name, FILE_MAX); @@ -414,7 +412,7 @@ void WM_exit_ext(bContext *C, const bool do_python) bool has_edited; int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY); - BLI_make_file_string("/", filename, BLI_temp_dir_base(), BLENDER_QUIT_FILE); + BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE); has_edited = ED_editors_flush_edits(C, false); @@ -478,6 +476,7 @@ void WM_exit_ext(bContext *C, const bool do_python) free_anim_copybuf(); free_anim_drivers_copybuf(); free_fmodifiers_copybuf(); + ED_gpencil_strokes_copybuf_free(); ED_clipboard_posebuf_free(); BKE_node_clipboard_clear(); @@ -543,7 +542,7 @@ void WM_exit_ext(bContext *C, const bool do_python) } wm_autosave_delete(); - BLI_temp_dir_session_purge(); + BKE_tempdir_session_purge(); } void WM_exit(bContext *C) diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 74c504050ae..6bc858e861a 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -45,8 +45,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "wm_window.h" -#include "wm_event_system.h" #include "wm_event_types.h" #include "wm.h" @@ -630,17 +628,22 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) } } - /* on file load 'winactive' can be NULL, possibly it should not happen but for now do a NULL check - campbell */ - if (wm->winactive) { - /* if there are running jobs, set the global progress indicator */ - if (jobs_progress > 0) { - float progress = total_progress / (float)jobs_progress; - WM_progress_set(wm->winactive, progress); - } - else { - WM_progress_clear(wm->winactive); - } + + /* if there are running jobs, set the global progress indicator */ + if (jobs_progress > 0) { + wmWindow *win; + float progress = total_progress / (float)jobs_progress; + + for (win = wm->windows.first; win; win = win->next) + WM_progress_set(win, progress); } + else { + wmWindow *win; + + for (win = wm->windows.first; win; win = win->next) + WM_progress_clear(win); + } + } bool WM_jobs_has_running(wmWindowManager *wm) diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index ff90de4b3c6..b52f3819d3f 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -56,7 +56,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "wm_window.h" #include "wm_event_system.h" #include "wm_event_types.h" diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index fe943e11c83..d49a298c424 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -38,8 +38,11 @@ #include <stdio.h> #include <stddef.h> #include <assert.h> +#include <errno.h> -#include "GHOST_C-api.h" +#ifdef WIN32 +# include "GHOST_C-api.h" +#endif #include "MEM_guardedalloc.h" @@ -58,12 +61,14 @@ #include "BLI_blenlib.h" #include "BLI_dial.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ +#include "BLI_linklist_stack.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLO_readfile.h" +#include "BKE_appdir.h" #include "BKE_autoexec.h" #include "BKE_blender.h" #include "BKE_brush.h" @@ -72,12 +77,14 @@ #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" /* BKE_ST_MAXNAME */ +#include "BKE_unit.h" #include "BKE_utildefines.h" #include "BKE_idcode.h" @@ -90,6 +97,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "ED_numinput.h" #include "ED_screen.h" #include "ED_util.h" #include "ED_view3d.h" @@ -99,6 +107,7 @@ #include "RNA_enum_types.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "UI_resources.h" #include "WM_api.h" @@ -1221,27 +1230,27 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } - prop = RNA_def_boolean(ot->srna, "filter_blender", (filter & BLENDERFILE) != 0, "Filter .blend files", ""); + prop = RNA_def_boolean(ot->srna, "filter_blender", (filter & FILE_TYPE_BLENDER) != 0, "Filter .blend files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_backup", (filter & BLENDERFILE_BACKUP) != 0, "Filter .blend files", ""); + prop = RNA_def_boolean(ot->srna, "filter_backup", (filter & FILE_TYPE_BLENDER_BACKUP) != 0, "Filter .blend files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_image", (filter & IMAGEFILE) != 0, "Filter image files", ""); + prop = RNA_def_boolean(ot->srna, "filter_image", (filter & FILE_TYPE_IMAGE) != 0, "Filter image files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_movie", (filter & MOVIEFILE) != 0, "Filter movie files", ""); + prop = RNA_def_boolean(ot->srna, "filter_movie", (filter & FILE_TYPE_MOVIE) != 0, "Filter movie files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_python", (filter & PYSCRIPTFILE) != 0, "Filter python files", ""); + prop = RNA_def_boolean(ot->srna, "filter_python", (filter & FILE_TYPE_PYSCRIPT) != 0, "Filter python files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_font", (filter & FTFONTFILE) != 0, "Filter font files", ""); + prop = RNA_def_boolean(ot->srna, "filter_font", (filter & FILE_TYPE_FTFONT) != 0, "Filter font files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_sound", (filter & SOUNDFILE) != 0, "Filter sound files", ""); + prop = RNA_def_boolean(ot->srna, "filter_sound", (filter & FILE_TYPE_SOUND) != 0, "Filter sound files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_text", (filter & TEXTFILE) != 0, "Filter text files", ""); + prop = RNA_def_boolean(ot->srna, "filter_text", (filter & FILE_TYPE_TEXT) != 0, "Filter text files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_btx", (filter & BTXFILE) != 0, "Filter btx files", ""); + prop = RNA_def_boolean(ot->srna, "filter_btx", (filter & FILE_TYPE_BTX) != 0, "Filter btx files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & COLLADAFILE) != 0, "Filter COLLADA files", ""); + prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & FILE_TYPE_COLLADA) != 0, "Filter COLLADA files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FOLDERFILE) != 0, "Filter folders", ""); + prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL, @@ -1397,6 +1406,64 @@ wmOperator *WM_operator_last_redo(const bContext *C) return op; } +/** + * Use for drag & drop a path or name with operators invoke() function. + */ +ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode) +{ + ID *id = NULL; + /* check input variables */ + if (RNA_struct_property_is_set(op->ptr, "filepath")) { + const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path"); + char path[FILE_MAX]; + bool exists = false; + + RNA_string_get(op->ptr, "filepath", path); + + errno = 0; + + if (idcode == ID_IM) { + id = (ID *)BKE_image_load_exists_ex(path, &exists); + } + else { + BLI_assert(0); + } + + if (!id) { + BKE_reportf(op->reports, RPT_ERROR, "Cannot read %s '%s': %s", + BKE_idcode_to_name(idcode), path, + errno ? strerror(errno) : TIP_("unsupported format")); + return NULL; + } + + if (is_relative_path ) { + if (exists == false) { + Main *bmain = CTX_data_main(C); + + if (idcode == ID_IM) { + BLI_path_rel(((Image *)id)->name, bmain->name); + } + else { + BLI_assert(0); + } + } + } + } + else if (RNA_struct_property_is_set(op->ptr, "name")) { + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "name", name); + id = BKE_libblock_find_name(idcode, name); + if (!id) { + BKE_reportf(op->reports, RPT_ERROR, "%s '%s' not found", + BKE_idcode_to_name(idcode), name); + return NULL; + } + id_us_plus(id); + } + + return id; +} + static void wm_block_redo_cb(bContext *C, void *arg_op, int UNUSED(arg_event)) { wmOperator *op = arg_op; @@ -1774,14 +1841,14 @@ static void wm_block_splash_refreshmenu(bContext *UNUSED(C), void *UNUSED(arg_bl static int wm_resource_check_prev(void) { - const char *res = BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, true); + const char *res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, true); // if (res) printf("USER: %s\n", res); #if 0 /* ignore the local folder */ if (res == NULL) { /* with a local dir, copying old files isn't useful since local dir get priority for config */ - res = BLI_get_folder_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, true); + res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, true); } #endif @@ -1790,7 +1857,7 @@ static int wm_resource_check_prev(void) return false; } else { - return (BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, true) != NULL); + return (BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, true) != NULL); } } @@ -1926,7 +1993,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar BLENDER_VERSION / 100, BLENDER_VERSION % 100); uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url); uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url", - "http://wiki.blender.org/index.php/Doc:2.6/Manual"); + "http://www.blender.org/manual"); uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org"); if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d" @@ -2392,7 +2459,7 @@ static void WM_OT_open_mainfile(wmOperatorType *ot) ot->ui = wm_open_mainfile_ui; /* omit window poll so this can work in background mode */ - WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file"); @@ -2579,6 +2646,13 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) lib = mainl->curlib; BLI_assert(lib); + if (mainl->versionfile < 250) { + BKE_reportf(op->reports, RPT_WARNING, + "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will " + "be done! You may want to re-save your lib file with current Blender", + mainl->versionfile, mainl->subversionfile); + } + if (totfiles == 0) { BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); } @@ -2652,7 +2726,7 @@ static void WM_OT_link(wmOperatorType *ot) ot->flag |= OPTYPE_UNDO; WM_operator_properties_filesel( - ot, FOLDERFILE | BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); @@ -2672,7 +2746,7 @@ static void WM_OT_append(wmOperatorType *ot) ot->flag |= OPTYPE_UNDO; WM_operator_properties_filesel( - ot, FOLDERFILE | BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); @@ -2685,7 +2759,7 @@ void WM_recover_last_session(bContext *C, ReportList *reports) { char filepath[FILE_MAX]; - BLI_make_file_string("/", filepath, BLI_temp_dir_base(), BLENDER_QUIT_FILE); + BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE); /* if reports==NULL, it's called directly without operator, we add a quick check here */ if (reports || BLI_exists(filepath)) { G.fileflags |= G_FILE_RECOVER; @@ -2764,7 +2838,7 @@ static void WM_OT_recover_auto_save(wmOperatorType *ot) ot->exec = wm_recover_auto_save_exec; ot->invoke = wm_recover_auto_save_invoke; - WM_operator_properties_filesel(ot, BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_LONGDISPLAY); } @@ -2842,6 +2916,8 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) (RNA_struct_find_property(op->ptr, "use_mesh_compat") && RNA_boolean_get(op->ptr, "use_mesh_compat")), G_FILE_MESH_COMPAT); +#else +# error "don't remove by accident" #endif if (wm_file_write(C, path, fileflags, op->reports) != 0) @@ -2880,7 +2956,7 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot) ot->check = blend_save_check; /* omit window poll so this can work in background mode */ - WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file"); RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative", @@ -2956,7 +3032,7 @@ static void WM_OT_save_mainfile(wmOperatorType *ot) ot->check = blend_save_check; /* omit window poll so this can work in background mode */ - WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file"); RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative", @@ -3731,6 +3807,7 @@ void WM_OT_straightline_gesture(wmOperatorType *ot) #define WM_RADIAL_CONTROL_DISPLAY_SIZE 200 #define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE 35 #define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) +#define WM_RADIAL_CONTROL_HEADER_LENGTH 180 #define WM_RADIAL_MAX_STR 6 typedef struct { @@ -3748,8 +3825,24 @@ typedef struct { ListBase orig_paintcursors; bool use_secondary_tex; void *cursor; + NumInput num_input; } RadialControl; +static void radial_control_update_header(wmOperator *op, bContext *C) +{ + RadialControl *rc = op->customdata; + char msg[WM_RADIAL_CONTROL_HEADER_LENGTH]; + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + + if (sa && hasNumInput(&rc->num_input)) { + char num_str[NUM_STR_REP_LEN]; + outputNumInput(&rc->num_input, num_str, &scene->unit); + BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %s", RNA_property_ui_name(rc->prop), num_str); + ED_area_headerprint(sa, msg); + } +} + static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *event) { float d[2] = {0, 0}; @@ -4134,6 +4227,13 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve return OPERATOR_CANCELLED; } + /* initialize numerical input */ + initNumInput(&rc->num_input); + rc->num_input.idx_max = 0; + rc->num_input.val_flag[0] |= NUM_NO_NEGATIVE; + rc->num_input.unit_sys = USER_UNIT_NONE; + rc->num_input.unit_type[0] = B_UNIT_LENGTH; + /* get subtype of property */ rc->subtype = RNA_property_subtype(rc->prop); if (!ELEM(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_PERCENTAGE, PROP_ANGLE, PROP_PIXEL)) { @@ -4141,7 +4241,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve MEM_freeN(rc); return OPERATOR_CANCELLED; } - + rc->current_value = rc->initial_value; radial_control_set_initial_mouse(rc, event); radial_control_set_tex(rc); @@ -4178,11 +4278,16 @@ static void radial_control_cancel(bContext *C, wmOperator *op) { RadialControl *rc = op->customdata; wmWindowManager *wm = CTX_wm_manager(C); + ScrArea *sa = CTX_wm_area(C); if (rc->dial) { MEM_freeN(rc->dial); rc->dial = NULL; } + + if (sa) { + ED_area_headerprint(sa, NULL); + } WM_paint_cursor_end(wm, rc->cursor); @@ -4206,126 +4311,182 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even float delta[2], ret = OPERATOR_RUNNING_MODAL; bool snap; float angle_precision = 0.0f; + const bool has_numInput = hasNumInput(&rc->num_input); + bool handled = false; + float numValue; /* TODO: fix hardcoded events */ snap = event->ctrl != 0; - switch (event->type) { - case MOUSEMOVE: - if (rc->slow_mode) { - if (rc->subtype == PROP_ANGLE) { - float position[2] = {event->x, event->y}; - - /* calculate the initial angle here first */ - delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; - delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; - - /* precision angle gets calculated from dial and gets added later */ - angle_precision = -0.1f * BLI_dial_angle(rc->dial, position); - } - else { - delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; - delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; - - if (rc->zoom_prop) { - RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); - delta[0] /= zoom[0]; - delta[1] /= zoom[1]; + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &rc->num_input, event)) { + handled = true; + applyNumInput(&rc->num_input, &numValue); + + if (rc->subtype == PROP_ANGLE) { + numValue = DEG2RADF(numValue); + numValue = fmod(numValue, 2.0f * (float)M_PI); + if (numValue < 0.0f) + numValue += 2.0f * (float)M_PI; + } + + CLAMP(numValue, rc->min_value, rc->max_value); + new_value = numValue; + + radial_control_set_value(rc, new_value); + rc->current_value = new_value; + radial_control_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + handled = false; + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + /* canceled; restore original value */ + radial_control_set_value(rc, rc->initial_value); + ret = OPERATOR_CANCELLED; + break; + + case LEFTMOUSE: + case PADENTER: + case RETKEY: + /* done; value already set */ + RNA_property_update(C, &rc->ptr, rc->prop); + ret = OPERATOR_FINISHED; + break; + + case MOUSEMOVE: + if (!has_numInput) { + if (rc->slow_mode) { + if (rc->subtype == PROP_ANGLE) { + float position[2] = {event->x, event->y}; + + /* calculate the initial angle here first */ + delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; + delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + + /* precision angle gets calculated from dial and gets added later */ + angle_precision = -0.1f * BLI_dial_angle(rc->dial, position); + } + else { + delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; + delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + + if (rc->zoom_prop) { + RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = len_v2(delta); + + delta[0] = event->x - rc->slow_mouse[0]; + delta[1] = event->y - rc->slow_mouse[1]; + + if (rc->zoom_prop) { + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = dist + 0.1f * (delta[0] + delta[1]); + } + } + else { + delta[0] = rc->initial_mouse[0] - event->x; + delta[1] = rc->initial_mouse[1] - event->y; + + if (rc->zoom_prop) { + RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = len_v2(delta); } - - dist = len_v2(delta); - - delta[0] = event->x - rc->slow_mouse[0]; - delta[1] = event->y - rc->slow_mouse[1]; - - if (rc->zoom_prop) { - delta[0] /= zoom[0]; - delta[1] /= zoom[1]; + + /* calculate new value and apply snapping */ + switch (rc->subtype) { + case PROP_NONE: + case PROP_DISTANCE: + case PROP_PERCENTAGE: + case PROP_PIXEL: + new_value = dist; + if (snap) new_value = ((int)new_value + 5) / 10 * 10; + break; + case PROP_FACTOR: + new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH; + if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; + break; + case PROP_ANGLE: + new_value = atan2f(delta[1], delta[0]) + M_PI + angle_precision; + new_value = fmod(new_value, 2.0f * (float)M_PI); + if (new_value < 0.0f) + new_value += 2.0f * (float)M_PI; + if (snap) new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10 * 10); + break; + default: + new_value = dist; /* dummy value, should this ever happen? - campbell */ + break; } - - dist = dist + 0.1f * (delta[0] + delta[1]); + + /* clamp and update */ + CLAMP(new_value, rc->min_value, rc->max_value); + radial_control_set_value(rc, new_value); + rc->current_value = new_value; + handled = true; + break; } - } - else { - delta[0] = rc->initial_mouse[0] - event->x; - delta[1] = rc->initial_mouse[1] - event->y; + break; - if (rc->zoom_prop) { - RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); - delta[0] /= zoom[0]; - delta[1] /= zoom[1]; + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + { + if (event->val == KM_PRESS) { + rc->slow_mouse[0] = event->x; + rc->slow_mouse[1] = event->y; + rc->slow_mode = true; + if (rc->subtype == PROP_ANGLE) { + float initial_position[2] = {UNPACK2(rc->initial_mouse)}; + float current_position[2] = {UNPACK2(rc->slow_mouse)}; + rc->dial = BLI_dial_initialize(initial_position, 0.0f); + /* immediately set the position to get a an initial direction */ + BLI_dial_angle(rc->dial, current_position); + } + handled = true; } - - dist = len_v2(delta); + if (event->val == KM_RELEASE) { + rc->slow_mode = false; + handled = true; + if (rc->dial) { + MEM_freeN(rc->dial); + rc->dial = NULL; + } + } + break; } + } - /* calculate new value and apply snapping */ - switch (rc->subtype) { - case PROP_NONE: - case PROP_DISTANCE: - case PROP_PERCENTAGE: - case PROP_PIXEL: - new_value = dist; - if (snap) new_value = ((int)new_value + 5) / 10 * 10; - break; - case PROP_FACTOR: - new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH; - if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; - break; - case PROP_ANGLE: - new_value = atan2f(delta[1], delta[0]) + M_PI + angle_precision; - new_value = fmod(new_value, 2.0f * (float)M_PI); - if (new_value < 0.0f) - new_value += 2.0f * (float)M_PI; - if (snap) new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10 * 10); - break; - default: - new_value = dist; /* dummy value, should this ever happen? - campbell */ - break; + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &rc->num_input, event)) { + applyNumInput(&rc->num_input, &numValue); + + if (rc->subtype == PROP_ANGLE) { + numValue = DEG2RADF(numValue); + numValue = fmod(numValue, 2.0f * (float)M_PI); + if (numValue < 0.0f) + numValue += 2.0f * (float)M_PI; } - /* clamp and update */ - CLAMP(new_value, rc->min_value, rc->max_value); + CLAMP(numValue, rc->min_value, rc->max_value); + new_value = numValue; + radial_control_set_value(rc, new_value); - rc->current_value = new_value; - break; - - case ESCKEY: - case RIGHTMOUSE: - /* canceled; restore original value */ - radial_control_set_value(rc, rc->initial_value); - ret = OPERATOR_CANCELLED; - break; - - case LEFTMOUSE: - case PADENTER: - /* done; value already set */ - RNA_property_update(C, &rc->ptr, rc->prop); - ret = OPERATOR_FINISHED; - break; - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: - if (event->val == KM_PRESS) { - rc->slow_mouse[0] = event->x; - rc->slow_mouse[1] = event->y; - rc->slow_mode = true; - if (rc->subtype == PROP_ANGLE) { - float initial_position[2] = {UNPACK2(rc->initial_mouse)}; - float current_position[2] = {UNPACK2(rc->slow_mouse)}; - rc->dial = BLI_dial_initialize(initial_position, 0.0f); - /* immediately set the position to get a an initial direction */ - BLI_dial_angle(rc->dial, current_position); - } - } - if (event->val == KM_RELEASE) { - rc->slow_mode = false; - if (rc->dial) { - MEM_freeN(rc->dial); - rc->dial = NULL; - } - } - break; + rc->current_value = new_value; + radial_control_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } } ED_region_tag_redraw(CTX_wm_region(C)); @@ -4547,6 +4708,90 @@ static void WM_OT_dependency_relations(wmOperatorType *ot) ot->exec = dependency_relations_exec; } +/* *************************** Mat/tex/etc. previews generation ************* */ + +typedef struct PreviewsIDEnsureStack { + Scene *scene; + + BLI_LINKSTACK_DECLARE(id_stack, ID *); +} PreviewsIDEnsureStack; + +static void previews_id_ensure(bContext *C, Scene *scene, ID *id) +{ + BLI_assert(ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)); + + /* Only preview non-library datablocks, lib ones do not pertain to this .blend file! + * Same goes for ID with no user. */ + if (!id->lib && (id->us != 0)) { + UI_id_icon_render(C, scene, id, false, false); + UI_id_icon_render(C, scene, id, true, false); + } +} + +static bool previews_id_ensure_callback(void *todo_v, ID **idptr, int UNUSED(cd_flag)) +{ + PreviewsIDEnsureStack *todo = todo_v; + ID *id = *idptr; + + if (id && (id->flag & LIB_DOIT)) { + if (ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)) { + previews_id_ensure(NULL, todo->scene, id); + } + id->flag &= ~LIB_DOIT; /* Tag the ID as done in any case. */ + BLI_LINKSTACK_PUSH(todo->id_stack, id); + } + + return true; +} + +static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + ListBase *lb[] = {&bmain->mat, &bmain->tex, &bmain->image, &bmain->world, &bmain->lamp, NULL}; + PreviewsIDEnsureStack preview_id_stack; + Scene *scene; + ID *id; + int i; + + /* We use LIB_DOIT to check whether we have already handled a given ID or not. */ + BKE_main_id_flag_all(bmain, LIB_DOIT, true); + + BLI_LINKSTACK_INIT(preview_id_stack.id_stack); + + for (scene = bmain->scene.first; scene; scene = scene->id.next) { + preview_id_stack.scene = scene; + id = (ID *)scene; + + do { + /* This will loop over all IDs linked by current one, render icons for them if needed, + * and add them to 'todo' preview_id_stack. */ + BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_stack, IDWALK_READONLY); + } while ((id = BLI_LINKSTACK_POP(preview_id_stack.id_stack))); + } + + BLI_LINKSTACK_FREE(preview_id_stack.id_stack); + + /* Check a last time for ID not used (fake users only, in theory), and + * do our best for those, using current scene... */ + for (i = 0; lb[i]; i++) { + for (id = lb[i]->first; id; id = id->next) { + previews_id_ensure(C, NULL, id); + } + } + + return OPERATOR_FINISHED; +} + +static void WM_OT_previews_ensure(wmOperatorType *ot) +{ + ot->name = "Refresh DataBlock Previews"; + ot->idname = "WM_OT_previews_ensure"; + ot->description = "Ensure datablock previews are available and up-to-date " + "(to be saved in .blend file, only for some types like materials, textures, etc.)"; + + ot->exec = previews_ensure_exec; +} + /* ******************************************************* */ static void operatortype_ghash_free_cb(wmOperatorType *ot) @@ -4610,6 +4855,7 @@ void wm_operatortype_init(void) #if defined(WIN32) WM_operatortype_append(WM_OT_console_toggle); #endif + WM_operatortype_append(WM_OT_previews_ensure); } /* circleselect-like modal operators */ @@ -4667,6 +4913,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "CLIP_OT_select_circle"); WM_modalkeymap_assign(keymap, "MASK_OT_select_circle"); WM_modalkeymap_assign(keymap, "NODE_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); } @@ -4763,6 +5011,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border"); WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */ WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border"); + WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_border"); } /* zoom to border modal operators */ diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 677be734d4b..232c9ad2e4d 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -69,8 +69,6 @@ #include "GHOST_C-api.h" #include "BLF_api.h" -#include "wm_event_types.h" - #include "WM_api.h" /* only for WM_main_playanim */ struct PlayState; diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index e26bcac9b1a..d2df020600a 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -53,7 +53,6 @@ #include "WM_api.h" #include "wm_subwindow.h" -#include "wm_window.h" /* wmSubWindow stored in wmWindow... but not exposed outside this C file */ /* it seems a bit redundant (area regions can store it too, but we keep it diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 46a20d3bf88..52fcdd797cb 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1524,3 +1524,21 @@ bool WM_window_is_fullscreen(wmWindow *win) return win->windowstate == GHOST_kWindowStateFullScreen; } + +#ifdef WITH_INPUT_IME +/* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */ +void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete) +{ + BLI_assert(win); + + GHOST_BeginIME(win->ghostwin, x, win->sizey - y, w, h, complete); +} + +void wm_window_IME_end(wmWindow *win) +{ + BLI_assert(win && win->ime_data); + + GHOST_EndIME(win->ghostwin); + win->ime_data = NULL; +} +#endif /* WITH_INPUT_IME */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index fe6d3431183..2301405a8ea 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -86,6 +86,13 @@ enum { * paint and drawing tools however will want to handle these. */ INBETWEEN_MOUSEMOVE = 0x0011, +/* IME event, GHOST_kEventImeCompositionStart in ghost */ + WM_IME_COMPOSITE_START = 0x0014, +/* IME event, GHOST_kEventImeComposition in ghost */ + WM_IME_COMPOSITE_EVENT = 0x0015, +/* IME event, GHOST_kEventImeCompositionEnd in ghost */ + WM_IME_COMPOSITE_END = 0x0016, + /* *** Start of keyboard codes. *** */ /* standard keyboard. diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 9c9c79d2f54..833234b0f13 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -69,6 +69,11 @@ wmWindow *wm_window_copy (bContext *C, wmWindow *winorig); void wm_window_testbreak (void); +#ifdef WITH_INPUT_IME +void wm_window_IME_begin (wmWindow *win, int x, int y, int w, int h, bool complete); +void wm_window_IME_end (wmWindow *win); +#endif + /* *************** window operators ************** */ int wm_window_duplicate_exec(bContext *C, struct wmOperator *op); int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 56abdfd27b1..9eff3405a2f 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -163,7 +163,9 @@ struct wmWindowManager; #include "../blender/editors/include/ED_render.h" #include "../blender/editors/include/ED_screen.h" #include "../blender/editors/include/ED_space_api.h" +#include "../blender/editors/include/ED_text.h" #include "../blender/editors/include/ED_transform.h" +#include "../blender/editors/include/ED_uvedit.h" #include "../blender/editors/include/ED_view3d.h" #include "../blender/editors/include/UI_interface.h" #include "../blender/editors/include/UI_interface_icons.h" @@ -217,6 +219,7 @@ void EDBM_mesh_load(struct Object *ob) RET_NONE void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob) RET_NONE void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE void *g_system; +bool EDBM_mtexpoly_check(struct BMEditMesh *em) RET_ZERO float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype) RET_NULL float RE_filter_value(int type, float x) RET_ZERO @@ -339,6 +342,8 @@ void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings void ED_space_image_set(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima) RET_NONE void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings) RET_NONE +void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy) RET_NONE + void ED_screen_set_scene(struct bContext *C, struct bScreen *screen, struct Scene *scene) RET_NONE struct MovieClip *ED_space_clip_get_clip(struct SpaceClip *sc) RET_NULL void ED_space_clip_set_clip(struct bContext *C, struct bScreen *screen, struct SpaceClip *sc, struct MovieClip *clip) RET_NONE @@ -349,6 +354,7 @@ void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE void ED_render_engine_changed(struct Main *bmain) RET_NONE void ED_file_read_bookmarks(void) RET_NONE +void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob) RET_NULL void PE_current_changed(struct Scene *scene, struct Object *ob) RET_NONE @@ -461,13 +467,9 @@ bool ED_mesh_color_remove_named(struct Mesh *me, const char *name) RET_ZERO bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name) RET_ZERO void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob) RET_NONE void ED_object_constraint_update(struct Object *ob) RET_NONE -struct bDeformGroup *ED_vgroup_add_name(struct Object *ob, const char *name) RET_NULL void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode) RET_NONE void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum) RET_NONE float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum) RET_ZERO -void ED_vgroup_delete(struct Object *ob, struct bDeformGroup *defgroup) RET_NONE -void ED_vgroup_clear(struct Object *ob) RET_NONE -bool ED_vgroup_object_is_edit_mode(struct Object *ob) RET_ZERO int ED_mesh_mirror_topo_table(struct Object *ob, char mode) RET_ZERO int ED_mesh_mirror_spatial_table(struct Object *ob, struct BMEditMesh *em, const float co[3], char mode) RET_ZERO @@ -481,6 +483,8 @@ bool ED_texture_context_check_lamp(const struct bContext *C) RET_ZERO bool ED_texture_context_check_particles(const struct bContext *C) RET_ZERO bool ED_texture_context_check_others(const struct bContext *C) RET_ZERO +bool ED_text_region_location_from_cursor(SpaceText *st, ARegion *ar, const int cursor_co[2], int r_pixel_co[2]) RET_ZERO + bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode, struct Object **r_ob, float r_obmat[4][4], const float ray_start[3], const float ray_normal[3], float *r_ray_dist, @@ -505,6 +509,7 @@ struct uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align) RE bool uiLayoutGetRedAlert(struct uiLayout *layout) RET_ZERO void uiLayoutSetRedAlert(uiLayout *layout, bool redalert) RET_NONE void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE +void uiItemMenuEnumR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon) RET_NONE void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon) RET_NONE void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon) RET_NONE void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon) RET_NONE @@ -576,6 +581,7 @@ struct RenderStats *RE_GetStats(struct Render *re) RET_NULL struct RenderData *RE_engine_get_render_data(struct Render *re) RET_NULL void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result) RET_NONE void RE_engine_update_progress(struct RenderEngine *engine, float progress) RET_NONE +void RE_engine_set_error_message(RenderEngine *engine, const char *msg) RET_NONE void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results) RET_NONE void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info) RET_NONE void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y) RET_NONE @@ -617,6 +623,7 @@ int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width, i void update_autoflags_fcurve(struct FCurve *fcu, struct bContext *C, struct ReportList *reports, struct PointerRNA *ptr) RET_NONE short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag) RET_ZERO short delete_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag) RET_ZERO +struct bAction *verify_adt_action(struct ID *id, short add) RET_NULL char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op, const bool all_args, const bool macro_args, struct wmOperatorType *ot, struct PointerRNA *opptr) RET_NULL char *WM_operator_pystring(struct bContext *C, struct wmOperator *op, const bool all_args, const bool macro_args) RET_NULL struct wmKeyMapItem *WM_modalkeymap_add_item(struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value) RET_NULL diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 0e596fb0c5f..21cb41ddfa2 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -628,37 +628,54 @@ elseif(WIN32) install(DIRECTORY DESTINATION ${TARGETDIR_VER}/python) install(DIRECTORY DESTINATION ${TARGETDIR_VER}/python/lib) - execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib") + # WARNING: its important that 'CMAKE_INSTALL_CONFIG_NAME' is evaluated at build time + # and _NOT_ configuration time, when modifying the lines below, + # check it works in both Release & Debug mode. + # + # Edit with extreme care! - Campbell - if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" STREQUAL \"Debug\") - add_custom_target(python_std_lib - COMMAND ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_d.tar.gz" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib) - else() - add_custom_target(python_std_lib - COMMAND ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}.tar.gz" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib) - endif() + # extract python + install( + CODE + " + message(STATUS \"Extracting Python to: \${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\") + if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Dd][Ee][Bb][Uu][Gg])$\") + set(PYTHON_ZIP ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_d.tar.gz) + else() + set(PYTHON_ZIP ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}.tar.gz) + endif() - add_dependencies(blender python_std_lib) + execute_process( + COMMAND \${CMAKE_COMMAND} -E make_directory + \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib\" + COMMAND \${CMAKE_COMMAND} -E + chdir \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib\" + \${CMAKE_COMMAND} -E + tar xzfv \"\${PYTHON_ZIP}\" + ) + unset(PYTHON_ZIP) + " + ) # release/site-packages - add_custom_target(python_site-packages - COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/release/site-packages ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/) - - add_dependencies(blender python_site-packages) + install( + DIRECTORY ${LIBDIR}/release/site-packages + DESTINATION ${BLENDER_VERSION}/python/lib + PATTERN ".svn" EXCLUDE + PATTERN "__pycache__" EXCLUDE # * any cache * + PATTERN "*.pyc" EXCLUDE # * any cache * + PATTERN "*.pyo" EXCLUDE # * any cache *) + ) if(WITH_PYTHON_INSTALL_NUMPY) - add_custom_target(python_numpy - COMMAND ${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.8.tar.gz" + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy + COMMAND ${CMAKE_COMMAND} -E tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz" + DEPENDS ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages) + add_custom_target(python_numpy ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy + DESTINATION ${BLENDER_VERSION}/python/lib/site-packages) endif() - - add_dependencies(blender python_numpy) - - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib - DESTINATION ${BLENDER_VERSION}/python ) - endif() unset(_PYTHON_VERSION_NO_DOTS) diff --git a/source/creator/creator.c b/source/creator/creator.c index be03ffe0bda..83741a64ace 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -48,13 +48,6 @@ # include "utfconv.h" #endif -/* for backtrace */ -#if defined(__linux__) || defined(__APPLE__) -# include <execinfo.h> -#elif defined(_MSV_VER) -# include <DbgHelp.h> -#endif - #include <stdlib.h> #include <stddef.h> #include <string.h> @@ -82,6 +75,7 @@ #include "DNA_scene_types.h" #include "DNA_userdef_types.h" +#include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_brush.h" #include "BKE_context.h" @@ -515,73 +509,12 @@ static int set_fpe(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(dat return 0; } -#if defined(__linux__) || defined(__APPLE__) - -/* Unix */ static void blender_crash_handler_backtrace(FILE *fp) { -#define SIZE 100 - void *buffer[SIZE]; - int nptrs; - char **strings; - int i; - fputs("\n# backtrace\n", fp); - - /* include a backtrace for good measure */ - nptrs = backtrace(buffer, SIZE); - strings = backtrace_symbols(buffer, nptrs); - for (i = 0; i < nptrs; i++) { - fputs(strings[i], fp); - fputc('\n', fp); - } - - free(strings); -#undef SIZE + BLI_system_backtrace(fp); } -#elif defined(_MSC_VER) - -static void blender_crash_handler_backtrace(FILE *fp) -{ - (void)fp; - -#if 0 -#define MAXSYMBOL 256 - unsigned short i; - void *stack[SIZE]; - unsigned short nframes; - SYMBOL_INFO *symbolinfo; - HANDLE process; - - process = GetCurrentProcess(); - - SymInitialize(process, NULL, true); - - nframes = CaptureStackBackTrace(0, SIZE, stack, NULL); - symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table"); - symbolinfo->MaxNameLen = MAXSYMBOL - 1; - symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); - - for (i = 0; i < nframes; i++) { - SymFromAddr(process, ( DWORD64 )( stack[ i ] ), 0, symbolinfo); - - fprintf(fp, "%u: %s - 0x%0X\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address); - } - - MEM_freeN(symbolinfo); -#endif -} - -#else /* non msvc/osx/linux */ - -static void blender_crash_handler_backtrace(FILE *fp) -{ - (void)fp; -} - -#endif - static void blender_crash_handler(int signum) { @@ -590,7 +523,7 @@ static void blender_crash_handler(int signum) char fname[FILE_MAX]; if (!G.main->name[0]) { - BLI_make_file_string("/", fname, BLI_temp_dir_base(), "crash.blend"); + BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend"); } else { BLI_strncpy(fname, G.main->name, sizeof(fname)); @@ -611,10 +544,10 @@ static void blender_crash_handler(int signum) char fname[FILE_MAX]; if (!G.main->name[0]) { - BLI_join_dirfile(fname, sizeof(fname), BLI_temp_dir_base(), "blender.crash.txt"); + BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt"); } else { - BLI_join_dirfile(fname, sizeof(fname), BLI_temp_dir_base(), BLI_path_basename(G.main->name)); + BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G.main->name)); BLI_replace_extension(fname, sizeof(fname), ".crash.txt"); } @@ -646,7 +579,7 @@ static void blender_crash_handler(int signum) } /* Delete content of temp dir! */ - BLI_temp_dir_session_purge(); + BKE_tempdir_session_purge(); /* really crash */ signal(signum, SIG_DFL); @@ -1195,7 +1128,7 @@ static int run_python_file(int argc, const char **argv, void *data) return 0; } #else - (void)argc; (void)argv; (void)data; /* unused */ + UNUSED_VARS(argc, argv, data); printf("This blender was built without python support\n"); return 0; #endif /* WITH_PYTHON */ @@ -1225,7 +1158,7 @@ static int run_python_text(int argc, const char **argv, void *data) return 0; } #else - (void)argc; (void)argv; (void)data; /* unused */ + UNUSED_VARS(argc, argv, data); printf("This blender was built without python support\n"); return 0; #endif /* WITH_PYTHON */ @@ -1240,7 +1173,7 @@ static int run_python_console(int UNUSED(argc), const char **argv, void *data) return 0; #else - (void)argv; (void)data; /* unused */ + UNUSED_VARS(argv, data); printf("This blender was built without python support\n"); return 0; #endif /* WITH_PYTHON */ @@ -1258,7 +1191,7 @@ static int set_addons(int argc, const char **argv, void *data) BPY_CTX_SETUP(BPY_string_exec(C, str)); free(str); #else - (void)argv; (void)data; /* unused */ + UNUSED_VARS(argv, data); #endif /* WITH_PYTHON */ return 1; } @@ -1618,13 +1551,28 @@ int main( #endif setCallbacks(); + +#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE) +/* patch to ignore argument finder gives us (pid?) */ + if (argc == 2 && strncmp(argv[1], "-psn_", 5) == 0) { + extern int GHOST_HACK_getFirstFile(char buf[]); + static char firstfilebuf[512]; + + argc = 1; + if (GHOST_HACK_getFirstFile(firstfilebuf)) { + argc = 2; + argv[1] = firstfilebuf; + } + } +#endif + #ifdef __FreeBSD__ fpsetmask(0); #endif /* initialize path to executable */ - BLI_init_program_path(argv[0]); + BKE_appdir_program_path_init(argv[0]); BLI_threadapi_init(); @@ -1703,7 +1651,7 @@ int main( /* this is properly initialized with user defs, but this is default */ /* call after loading the startup.blend so we can read U.tempdir */ - BLI_temp_dir_init(U.tempdir); + BKE_tempdir_init(U.tempdir); } else { #ifndef WITH_PYTHON_MODULE @@ -1713,7 +1661,7 @@ int main( WM_init(C, argc, (const char **)argv); /* don't use user preferences temp dir */ - BLI_temp_dir_init(NULL); + BKE_tempdir_init(NULL); } #ifdef WITH_PYTHON /** diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 2a7e631637e..60b8832b44e 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -280,8 +280,8 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 0) != 0); #endif // bool novertexarrays = (SYS_GetCommandLineInt(syshandle, "novertexarrays", 0) != 0); - bool mouse_state = startscene->gm.flag & GAME_SHOW_MOUSE; - bool restrictAnimFPS = startscene->gm.flag & GAME_RESTRICT_ANIM_UPDATES; + bool mouse_state = (startscene->gm.flag & GAME_SHOW_MOUSE) != 0; + bool restrictAnimFPS = (startscene->gm.flag & GAME_RESTRICT_ANIM_UPDATES) != 0; short drawtype = v3d->drawtype; diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 3dd013dfd63..c756d8695e6 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -256,12 +256,14 @@ bool BL_ActionActuator::Update(double curtime, bool frame) if ((m_flag & ACT_FLAG_PLAY_END) && (m_flag & ACT_FLAG_ACTIVE) && obj->IsActionDone(m_layer)) { m_flag &= ~ACT_FLAG_ACTIVE; - m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; - if (m_playtype == ACT_ACTION_PINGPONG) + if (m_playtype == ACT_ACTION_PINGPONG) { m_flag ^= ACT_FLAG_REVERSE; - else + } + else { + m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; return false; + } } // If a different action is playing, we've been overruled and are no longer active @@ -320,8 +322,9 @@ bool BL_ActionActuator::Update(double curtime, bool frame) case ACT_ACTION_FLIPPER: // Convert into a play action and play back to the beginning + float temp = end; end = start; - start = obj->GetActionFrame(m_layer); + start = curr_action ? obj->GetActionFrame(m_layer) : temp; obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags, 1.f, blendmode); m_flag |= ACT_FLAG_PLAY_END; diff --git a/source/gameengine/Converter/BL_ArmatureChannel.cpp b/source/gameengine/Converter/BL_ArmatureChannel.cpp index cb33ff0e1e3..2b8dfd8f8d1 100644 --- a/source/gameengine/Converter/BL_ArmatureChannel.cpp +++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp @@ -295,7 +295,7 @@ PyObject *BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const str mul_v3_fl(joints,norm); break; } - return Vector_CreatePyObject(joints, 3, Py_NEW, NULL); + return Vector_CreatePyObject(joints, 3, NULL); } int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) diff --git a/source/gameengine/Converter/BL_ModifierDeformer.cpp b/source/gameengine/Converter/BL_ModifierDeformer.cpp index 71dc1bdec87..3bc07113ff6 100644 --- a/source/gameengine/Converter/BL_ModifierDeformer.cpp +++ b/source/gameengine/Converter/BL_ModifierDeformer.cpp @@ -186,6 +186,7 @@ bool BL_ModifierDeformer::Update(void) m_dm->release(m_dm); // HACK! use deformedOnly as a user counter m_dm->deformedOnly = 1; + DM_update_materials(m_dm, blendobj); /* update the graphic controller */ PHY_IGraphicController *ctrl = m_gameobj->GetGraphicController(); if (ctrl) { diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index a20ebb3a081..eb4b9a8124a 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -69,6 +69,7 @@ #include "DNA_scene_types.h" #include "DNA_world_types.h" #include "BKE_main.h" +#include "BKE_fcurve.h" #include "BLI_math.h" @@ -87,6 +88,7 @@ extern "C" #include "BKE_mesh.h" // BKE_mesh_copy #include "DNA_space_types.h" #include "DNA_anim_types.h" +#include "DNA_action_types.h" #include "RNA_define.h" #include "../../blender/editors/include/ED_keyframing.h" } @@ -843,13 +845,26 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() { KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g); if (gameObj->IsRecordAnimation()) { -#if 0 Object* blenderObject = gameObj->GetBlenderObject(); - if (blenderObject && blenderObject->ipo) + if (blenderObject && blenderObject->adt) { + bAction *act = verify_adt_action(&blenderObject->id, false); + FCurve *fcu; + + if (!act) { + continue; + } + + /* for now, not much choice but to run this on all curves... */ + for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) { + /* Note: calling `sort_time_fcurve()` here is not needed, since + * all keys have been added in 'right' order. */ + calchandles_fcurve(fcu); + } +#if 0 // XXX animato Ipo* ipo = blenderObject->ipo; - + //create the curves, if not existing //testhandles_ipocurve checks for NULL testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocX")); @@ -858,8 +873,8 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotX")); testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotY")); testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ")); - } #endif + } } } } diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp index 75e3b490505..5e0eb92eb58 100644 --- a/source/gameengine/Expressions/ListValue.cpp +++ b/source/gameengine/Expressions/ListValue.cpp @@ -432,7 +432,7 @@ static PyObject *listvalue_buffer_concat(PyObject *self, PyObject *other) for (i=0;i<numitems;i++) { - listitemval = listval->ConvertPythonToValue(PyList_GetItem(other,i), true, "cList + pyList: CListValue, "); + listitemval = listval->ConvertPythonToValue(PyList_GET_ITEM(other, i), true, "cList + pyList: CListValue, "); if (listitemval) { listval_new->SetValue(i+numitems_orig, listitemval); diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index c025d439fc0..a65d61bc98b 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -418,7 +418,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * return NULL; } #ifdef USE_MATHUTILS - return Vector_CreatePyObject(val, attrdef->m_imax, Py_NEW, NULL); + return Vector_CreatePyObject(val, attrdef->m_imax, NULL); #else PyObject *resultlist = PyList_New(attrdef->m_imax); for (unsigned int i=0; i<attrdef->m_imax; i++) @@ -435,7 +435,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * return NULL; } #ifdef USE_MATHUTILS - return Matrix_CreatePyObject(val, attrdef->m_imin, attrdef->m_imax, Py_WRAP, NULL); + return Matrix_CreatePyObject_wrap(val, attrdef->m_imin, attrdef->m_imax, NULL); #else PyObject *collist = PyList_New(attrdef->m_imin); for (unsigned int i=0; i<attrdef->m_imin; i++) @@ -458,7 +458,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * #ifdef USE_MATHUTILS float fval[3]; val->getValue(fval); - return Vector_CreatePyObject(fval, 3, Py_NEW, NULL); + return Vector_CreatePyObject(fval, 3, NULL); #else PyObject *resultlist = PyList_New(3); for (unsigned int i=0; i<3; i++) diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index bdef2dbd5b0..286db016476 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -568,7 +568,7 @@ CValue *CValue::ConvertPythonToValue(PyObject *pyobj, const bool do_type_excepti Py_ssize_t numitems = PyList_GET_SIZE(pyobj); for (i=0;i<numitems;i++) { - PyObject *listitem = PyList_GetItem(pyobj,i); /* borrowed ref */ + PyObject *listitem = PyList_GET_ITEM(pyobj,i); /* borrowed ref */ CValue* listitemval = ConvertPythonToValue(listitem, error_prefix); if (listitemval) { diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp index 228adbb942e..daf869e3e61 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp @@ -41,7 +41,9 @@ #include "BLI_path_util.h" -#define SDL_CHECK(x) ((x) != (void*)0) +#ifdef WITH_SDL +# define SDL_CHECK(x) ((x) != (void *)0) +#endif SCA_Joystick::SCA_Joystick(short int index) : @@ -109,7 +111,11 @@ SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex ) char *videodriver = getenv("SDL_VIDEODRIVER"); BLI_setenv("SDL_VIDEODRIVER", "dummy"); +#if SDL_VERSION_ATLEAST(2, 0, 0) + int success = (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1 ); +#else int success = (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) != -1 ); +#endif BLI_setenv("SDL_VIDEODRIVER", videodriver); # endif @@ -154,11 +160,11 @@ void SCA_Joystick::ReleaseInstance() /* The video subsystem is required for joystick input to work. However, * when GHOST is running under SDL, video is freed elsewhere. * Do this once only. */ -# ifdef WITH_GHOST_SDL +#if SDL_VERSION_ATLEAST(2, 0, 0) SDL_QuitSubSystem(SDL_INIT_JOYSTICK); -# else +#else SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO); -# endif +#endif #endif /* WITH_SDL */ } } diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp index 08f4d97ed1b..0033c137eb6 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp @@ -124,6 +124,12 @@ void SCA_Joystick::HandleEvents(void) SCA_Joystick::m_instance[sdl_event.jball.which]->OnBallMotion(&sdl_event); break; #endif +#if SDL_VERSION_ATLEAST(2, 0, 0) + case SDL_JOYDEVICEADDED: + case SDL_JOYDEVICEREMOVED: + /* pass */ + break; +#endif default: printf("SCA_Joystick::HandleEvents, Unknown SDL event (%d), this should not happen\n", sdl_event.type); break; diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index cc203880f94..e5d717e0140 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -511,6 +511,7 @@ PyObject *SCA_KeyboardSensor::pyattr_get_events(void *self_v, const KX_PYATTRIBU PyList_SET_ITEM(keypair,0,PyLong_FromLong(i)); PyList_SET_ITEM(keypair,1,PyLong_FromLong(inevent.m_status)); PyList_Append(resultlist,keypair); + Py_DECREF(keypair); } } return resultlist; diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index d7a63c28da3..2791931fe43 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -567,7 +567,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0) && GPU_display_list_support(); bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0); - bool restrictAnimFPS = gm->flag & GAME_RESTRICT_ANIM_UPDATES; + bool restrictAnimFPS = (gm->flag & GAME_RESTRICT_ANIM_UPDATES) != 0; if (GLEW_ARB_multitexture && GLEW_VERSION_1_1) m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0); diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 1a6501fae6e..915fe614957 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -64,6 +64,7 @@ extern "C" #include "BLO_readfile.h" #include "BLO_runtime.h" +#include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_depsgraph.h" #include "BKE_global.h" @@ -79,6 +80,10 @@ extern "C" #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#ifdef __APPLE__ + int GHOST_HACK_getFirstFile(char buf[]); +#endif + // For BLF #include "BLF_api.h" #include "BLF_translation.h" @@ -296,6 +301,12 @@ static void get_filename(int argc, char **argv, char *filename) if (BLI_exists(argv[argc-1])) { BLI_strncpy(filename, argv[argc-1], FILE_MAX); } + if (::strncmp(argv[argc-1], "-psn_", 5)==0) { + static char firstfilebuf[512]; + if (GHOST_HACK_getFirstFile(firstfilebuf)) { + BLI_strncpy(filename, firstfilebuf, FILE_MAX); + } + } } srclen -= ::strlen("MacOS/blenderplayer"); @@ -430,8 +441,8 @@ int main(int argc, char** argv) sdlewInit(); #endif - BLI_init_program_path(argv[0]); - BLI_temp_dir_init(NULL); + BKE_appdir_program_path_init(argv[0]); + BKE_tempdir_init(NULL); // We don't use threads directly in the BGE, but we need to call this so things like // freeing up GPU_Textures works correctly. @@ -870,7 +881,7 @@ int main(int argc, char** argv) } } else { - bfd = load_game_data(BLI_program_path(), filename[0]? filename: NULL); + bfd = load_game_data(BKE_appdir_program_path(), filename[0]? filename: NULL); } #if defined(DEBUG) @@ -1142,7 +1153,7 @@ int main(int argc, char** argv) MEM_printmemlist(); } - BLI_temp_dir_session_purge(); + BKE_tempdir_session_purge(); return error ? -1 : 0; } diff --git a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt index 0c661cf2c87..cfc6ded4e65 100644 --- a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt +++ b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt @@ -30,6 +30,7 @@ set(INC ../../GameLogic ../../Network ../../SceneGraph + ../../../blender/blenlib ../../../../intern/container ../../../../intern/string ) diff --git a/source/gameengine/Ketsji/KXNetwork/SConscript b/source/gameengine/Ketsji/KXNetwork/SConscript index 355dcc4f78f..ab03e03e74d 100644 --- a/source/gameengine/Ketsji/KXNetwork/SConscript +++ b/source/gameengine/Ketsji/KXNetwork/SConscript @@ -39,6 +39,7 @@ incs = [ '#source/gameengine/Ketsji', '#source/gameengine/Network', '#source/gameengine/SceneGraph', + '../../../blender/blenlib', ] incs = ' '.join(incs) diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index e0761154ed2..ce2fe5f5ad8 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -747,7 +747,7 @@ int KX_Camera::pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -772,7 +772,7 @@ int KX_Camera::pyattr_set_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, P KX_Camera* self = static_cast<KX_Camera*>(self_v); float fov = PyFloat_AsDouble(value); if (fov <= 0.0) { - PyErr_SetString(PyExc_AttributeError, "camera.fov = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.fov = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -796,7 +796,7 @@ int KX_Camera::pyattr_set_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *at KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.ortho_scale = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.ortho_scale = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -816,7 +816,7 @@ int KX_Camera::pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -836,7 +836,7 @@ int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, P KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index a77269c116d..f58fee88d48 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -2044,7 +2044,6 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) cam->NodeUpdateGS(0.f); scene->CalculateVisibleMeshes(m_rasterizer,cam); - scene->UpdateAnimations(m_engine->GetFrameTime()); scene->RenderBuckets(camtrans, m_rasterizer); } diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index dc246406a88..e8b68d20e84 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -575,6 +575,39 @@ CValue* KX_GameObject::GetReplica() return replica; } +float KX_GameObject::getLinearDamping() const +{ + if (m_pPhysicsController) + return m_pPhysicsController->GetLinearDamping(); + return 0; +} + +float KX_GameObject::getAngularDamping() const +{ + if (m_pPhysicsController) + return m_pPhysicsController->GetAngularDamping(); + return 0; +} + +void KX_GameObject::setLinearDamping(float damping) +{ + if (m_pPhysicsController) + m_pPhysicsController->SetLinearDamping(damping); +} + + +void KX_GameObject::setAngularDamping(float damping) +{ + if (m_pPhysicsController) + m_pPhysicsController->SetAngularDamping(damping); +} + + +void KX_GameObject::setDamping(float linear, float angular) +{ + if (m_pPhysicsController) + m_pPhysicsController->SetDamping(linear, angular); +} void KX_GameObject::ApplyForce(const MT_Vector3& force,bool local) @@ -930,27 +963,6 @@ KX_GameObject::SetVisible( } } -bool KX_GameObject::GetCulled() -{ - // If we're set to not cull, double-check with - // the mesh slots first. This is kind of nasty, but - // it allows us to get proper culling information. - if (!m_bCulled) - { - SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); - for (mit.begin(); !mit.end(); ++mit) - { - if ((*mit)->m_bCulled) - { - m_bCulled = true; - break; - } - } - } - - return m_bCulled; -} - static void setOccluder_recursive(SG_Node* node, bool v) { NodeList& children = node->GetSGChildren(); @@ -1824,7 +1836,7 @@ static Mathutils_Callback mathutils_kxgameob_matrix_cb = { void KX_GameObject_Mathutils_Callback_Init(void) { - // register mathutils callbacks, ok to run more then once. + // register mathutils callbacks, ok to run more than once. mathutils_kxgameob_vector_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_vector_cb); mathutils_kxgameob_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_matrix_cb); } @@ -1843,6 +1855,7 @@ PyMethodDef KX_GameObject::Methods[] = { {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS}, + {"setDamping", (PyCFunction) KX_GameObject::sPySetDamping, METH_VARARGS}, {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS}, {"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O}, @@ -1918,6 +1931,8 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("angularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_worldAngularVelocity), KX_PYATTRIBUTE_RW_FUNCTION("localAngularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_localAngularVelocity), KX_PYATTRIBUTE_RW_FUNCTION("worldAngularVelocity", KX_GameObject, pyattr_get_worldAngularVelocity, pyattr_set_worldAngularVelocity), + KX_PYATTRIBUTE_RW_FUNCTION("linearDamping", KX_GameObject, pyattr_get_linearDamping, pyattr_set_linearDamping), + KX_PYATTRIBUTE_RW_FUNCTION("angularDamping", KX_GameObject, pyattr_get_angularDamping, pyattr_set_angularDamping), KX_PYATTRIBUTE_RO_FUNCTION("children", KX_GameObject, pyattr_get_children), KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), @@ -2708,6 +2723,34 @@ int KX_GameObject::pyattr_set_localAngularVelocity(void *self_v, const KX_PYATTR return PY_SET_ATTR_SUCCESS; } +PyObject *KX_GameObject::pyattr_get_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + return PyFloat_FromDouble(self->getLinearDamping()); +} + +int KX_GameObject::pyattr_set_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + float val = PyFloat_AsDouble(value); + self->setLinearDamping(val); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + return PyFloat_FromDouble(self->getAngularDamping()); +} + +int KX_GameObject::pyattr_set_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + float val = PyFloat_AsDouble(value); + self->setAngularDamping(val); + return PY_SET_ATTR_SUCCESS; +} + PyObject *KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { @@ -3004,6 +3047,18 @@ PyObject *KX_GameObject::PySetAngularVelocity(PyObject *args) return NULL; } +PyObject *KX_GameObject::PySetDamping(PyObject *args) +{ + float linear; + float angular; + + if (!PyArg_ParseTuple(args,"ff|i:setDamping", &linear, &angular)) + return NULL; + + setDamping(linear, angular); + Py_RETURN_NONE; +} + PyObject *KX_GameObject::PySetVisible(PyObject *args) { int visible, recursive = 0; diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index d4fa4851696..4538679303f 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -684,6 +684,12 @@ public: bool local ); + virtual float getLinearDamping() const; + virtual float getAngularDamping() const; + virtual void setLinearDamping(float damping); + virtual void setAngularDamping(float damping); + virtual void setDamping(float linear, float angular); + /** * Update the physics object transform based upon the current SG_Node * position. @@ -852,10 +858,10 @@ public: /** * Was this object culled? */ - bool + inline bool GetCulled( void - ); + ) { return m_bCulled; } /** * Set culled flag of this object @@ -965,6 +971,7 @@ public: KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,GetVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,SetDamping); KX_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce); @@ -1070,6 +1077,10 @@ public: static int pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); /* Experimental! */ static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index f76580cd44d..f1d0e4262e9 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -140,6 +140,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_frameTime(0.f), m_clockTime(0.f), m_previousClockTime(0.f), + m_previousAnimTime(0.f), m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), @@ -686,6 +687,16 @@ bool KX_KetsjiEngine::NextFrame() SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); scene->UpdateParents(m_frameTime); + // update levels of detail + scene->UpdateObjectLods(); + + if (!GetRestrictAnimationFPS()) + { + m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); + scene->UpdateAnimations(m_frameTime); + } + m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_PHYSICS2); scene->GetPhysicsEnvironment()->BeginFrame(); @@ -787,6 +798,27 @@ bool KX_KetsjiEngine::NextFrame() m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); } } + + + // Handle the animations independently of the logic time step + if (GetRestrictAnimationFPS()) + { + double clocktime = m_kxsystem->GetTimeInSeconds(); + m_logger->StartLog(tc_animations, clocktime, true); + SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); + + double anim_timestep = 1.0/KX_GetActiveScene()->GetAnimationFPS(); + if (clocktime - m_previousAnimTime > anim_timestep) + { + // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) + // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime)); + m_previousAnimTime = clocktime; + for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) + { + (*sceneit)->UpdateAnimations(clocktime); + } + } + } // Start logging time spend outside main loop m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); @@ -1155,15 +1187,8 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) raslight->BindShadowBuffer(m_canvas, cam, camtrans); /* update scene */ - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); scene->CalculateVisibleMeshes(m_rasterizer, cam, raslight->GetShadowLayer()); - m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); - scene->UpdateAnimations(GetFrameTime()); - - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); - - /* render */ m_rasterizer->ClearDepthBuffer(); m_rasterizer->ClearColorBuffer(); @@ -1295,11 +1320,6 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) scene->CalculateVisibleMeshes(m_rasterizer,cam); - m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); - - scene->UpdateAnimations(GetFrameTime()); - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_RENDER); diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 2b80e3bd69a..e18b203b675 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -111,6 +111,7 @@ private: double m_frameTime;//discrete timestamp of the 'game logic frame' double m_clockTime;//current time double m_previousClockTime;//previous clock time + double m_previousAnimTime; //the last time animations were updated double m_remainingTime; static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ diff --git a/source/gameengine/Ketsji/KX_MouseActuator.cpp b/source/gameengine/Ketsji/KX_MouseActuator.cpp index aae5d18189a..8774abe04b2 100644 --- a/source/gameengine/Ketsji/KX_MouseActuator.cpp +++ b/source/gameengine/Ketsji/KX_MouseActuator.cpp @@ -126,24 +126,33 @@ bool KX_MouseActuator::Update() float movement[2]; MT_Vector3 rotation; float setposition[2] = {0.0}; + float center_x = 0.5, center_y = 0.5; getMousePosition(position); movement[0] = position[0]; movement[1] = position[1]; + //preventing undesired drifting when resolution is odd + if ((m_canvas->GetWidth() % 2) != 0) { + center_x = ((m_canvas->GetWidth() - 1.0) / 2.0) / (m_canvas->GetWidth()); + } + if ((m_canvas->GetHeight() % 2) != 0) { + center_y = ((m_canvas->GetHeight() - 1.0) / 2.0) / (m_canvas->GetHeight()); + } + //preventing initial skipping. if ((m_oldposition[0] <= -0.9) && (m_oldposition[1] <= -0.9)) { if (m_reset_x) { - m_oldposition[0] = 0.5; + m_oldposition[0] = center_x; } else { m_oldposition[0] = position[0]; } if (m_reset_y) { - m_oldposition[1] = 0.5; + m_oldposition[1] = center_y; } else { m_oldposition[1] = position[1]; @@ -156,8 +165,8 @@ bool KX_MouseActuator::Update() if (m_use_axis_x) { if (m_reset_x) { - setposition[0] = 0.5; - movement[0] -= 0.5; + setposition[0] = center_x; + movement[0] -= center_x; } else { setposition[0] = position[0]; @@ -166,12 +175,10 @@ bool KX_MouseActuator::Update() movement[0] *= -1.0; - /* Don't apply the rotation when width resolution is odd (+ little movement) to - avoid undesired drifting or when we are under a certain threshold for mouse + /* Don't apply the rotation when we are under a certain threshold for mouse movement */ - if (!((m_canvas->GetWidth() % 2 != 0) && MT_abs(movement[0]) < 0.01) && - ((movement[0] > (m_threshold[0] / 10.0)) || + if (((movement[0] > (m_threshold[0] / 10.0)) || ((movement[0] * (-1.0)) > (m_threshold[0] / 10.0)))) { movement[0] *= m_sensitivity[0]; @@ -209,15 +216,15 @@ bool KX_MouseActuator::Update() } } else { - setposition[0] = 0.5; + setposition[0] = center_x; } //Calculating Y axis. if (m_use_axis_y) { if (m_reset_y) { - setposition[1] = 0.5; - movement[1] -= 0.5; + setposition[1] = center_y; + movement[1] -= center_y; } else { setposition[1] = position[1]; @@ -226,12 +233,10 @@ bool KX_MouseActuator::Update() movement[1] *= -1.0; - /* Don't apply the rotation when height resolution is odd (+ little movement) to - avoid undesired drifting or when we are under a certain threshold for mouse + /* Don't apply the rotation when we are under a certain threshold for mouse movement */ - if (!((m_canvas->GetHeight() % 2 != 0) && MT_abs(movement[1]) < 0.01) && - ((movement[1] > (m_threshold[1] / 10.0)) || + if (((movement[1] > (m_threshold[1] / 10.0)) || ((movement[1] * (-1.0)) > (m_threshold[1] / 10.0)))) { movement[1] *= m_sensitivity[1]; @@ -270,7 +275,7 @@ bool KX_MouseActuator::Update() } } else { - setposition[1] = 0.5; + setposition[1] = center_y; } setMousePosition(setposition[0], setposition[1]); @@ -399,8 +404,8 @@ int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF if (PyList_Size(value) != 2) return PY_SET_ATTR_FAIL; - item1 = PyList_GetItem(value, 0); - item2 = PyList_GetItem(value, 1); + item1 = PyList_GET_ITEM(value, 0); + item2 = PyList_GET_ITEM(value, 1); if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { return PY_SET_ATTR_FAIL; @@ -430,8 +435,8 @@ int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF if (PyList_Size(value) != 2) return PY_SET_ATTR_FAIL; - item1 = PyList_GetItem(value, 0); - item2 = PyList_GetItem(value, 1); + item1 = PyList_GET_ITEM(value, 0); + item2 = PyList_GET_ITEM(value, 1); if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { return PY_SET_ATTR_FAIL; @@ -461,8 +466,8 @@ int KX_MouseActuator::pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *a if (PyList_Size(value) != 2) return PY_SET_ATTR_FAIL; - item1 = PyList_GetItem(value, 0); - item2 = PyList_GetItem(value, 1); + item1 = PyList_GET_ITEM(value, 0); + item2 = PyList_GET_ITEM(value, 1); if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { return PY_SET_ATTR_FAIL; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index a9f6bb0d2ff..c2c83266791 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -269,8 +269,8 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport); /* Check if the mouse is in the viewport */ - if (( m_x < viewport.m_x2 && // less then right - m_x > viewport.m_x1 && // more then then left + if (( m_x < viewport.m_x2 && // less than right + m_x > viewport.m_x1 && // more than then left m_y_inv < viewport.m_y2 && // below top m_y_inv > viewport.m_y1) == 0) // above bottom { diff --git a/source/gameengine/Ketsji/KX_PyMath.cpp b/source/gameengine/Ketsji/KX_PyMath.cpp index 804e8de2ad1..76332e75204 100644 --- a/source/gameengine/Ketsji/KX_PyMath.cpp +++ b/source/gameengine/Ketsji/KX_PyMath.cpp @@ -100,7 +100,7 @@ PyObject *PyObjectFrom(const MT_Matrix4x4 &mat) #ifdef USE_MATHUTILS float fmat[16]; mat.getValue(fmat); - return Matrix_CreatePyObject(fmat, 4, 4, Py_NEW, NULL); + return Matrix_CreatePyObject(fmat, 4, 4, NULL); #else PyObject *collist = PyList_New(4); PyObject *col; @@ -124,7 +124,7 @@ PyObject *PyObjectFrom(const MT_Matrix3x3 &mat) #ifdef USE_MATHUTILS float fmat[9]; mat.getValue3x3(fmat); - return Matrix_CreatePyObject(fmat, 3, 3, Py_NEW, NULL); + return Matrix_CreatePyObject(fmat, 3, 3, NULL); #else PyObject *collist = PyList_New(3); PyObject *col; @@ -148,7 +148,7 @@ PyObject *PyObjectFrom(const MT_Quaternion &qrot) /* NOTE, were re-ordering here for Mathutils compat */ float fvec[4]; qrot.getValue(fvec); - return Quaternion_CreatePyObject(fvec, Py_NEW, NULL); + return Quaternion_CreatePyObject(fvec, NULL); } #endif @@ -157,7 +157,7 @@ PyObject *PyObjectFrom(const MT_Tuple4 &vec) #ifdef USE_MATHUTILS float fvec[4]; vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 4, Py_NEW, NULL); + return Vector_CreatePyObject(fvec, 4, NULL); #else PyObject *list = PyList_New(4); PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); @@ -173,7 +173,7 @@ PyObject *PyObjectFrom(const MT_Tuple3 &vec) #ifdef USE_MATHUTILS float fvec[3]; vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(fvec, 3, NULL); #else PyObject *list = PyList_New(3); PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); @@ -188,7 +188,7 @@ PyObject *PyObjectFrom(const MT_Tuple2 &vec) #ifdef USE_MATHUTILS float fvec[2]; vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 2, Py_NEW, NULL); + return Vector_CreatePyObject(fvec, 2, NULL); #else PyObject *list = PyList_New(2); PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index fefc64b4bad..3ddd53b971f 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -130,12 +130,16 @@ extern "C" { #include "DNA_scene_types.h" #include "PHY_IPhysicsEnvironment.h" + +extern "C" { #include "BKE_main.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_appdir.h" #include "BLI_blenlib.h" #include "GPU_material.h" #include "MEM_guardedalloc.h" +} /* for converting new scenes */ #include "KX_BlenderSceneConverter.h" @@ -2071,7 +2075,7 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur * somehow it remembers the sys.path - Campbell */ static bool first_time = true; - const char * const py_path_bundle = BLI_get_folder(BLENDER_SYSTEM_PYTHON, NULL); + const char * const py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL); #if 0 // TODO - py3 STR_String pname = progname; diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index d0eab9de1c1..b6fd69fe1f4 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -218,7 +218,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_bucketmanager=new RAS_BucketManager(); - bool showObstacleSimulation = scene->gm.flag & GAME_SHOW_OBSTACLE_SIMULATION; + bool showObstacleSimulation = (scene->gm.flag & GAME_SHOW_OBSTACLE_SIMULATION) != 0; switch (scene->gm.obstacleSimulation) { case OBSTSIMULATION_TOI_rays: @@ -1502,6 +1502,15 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int bool dbvt_culling = false; if (m_dbvt_culling) { + /* Reset KX_GameObject m_bCulled to true before doing culling + * since DBVT culling will only set it to false. + * This is similar to what RAS_BucketManager does for RAS_MeshSlot culling. + */ + for (int i = 0; i < m_objectlist->GetCount(); i++) { + KX_GameObject *gameobj = static_cast<KX_GameObject*>(m_objectlist->GetValue(i)); + gameobj->SetCulled(true); + } + // test culling through Bullet MT_Vector4 planes[6]; // get the clip planes @@ -1531,9 +1540,6 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer); } } - - // Now that we know visible meshes, update LoDs - UpdateObjectLods(); } // logic stuff @@ -1642,20 +1648,6 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t void KX_Scene::UpdateAnimations(double curtime) { - KX_KetsjiEngine *engine = KX_GetActiveEngine(); - - if (engine->GetRestrictAnimationFPS()) - { - // Handle the animations independently of the logic time step - double anim_timestep = 1.0 / GetAnimationFPS(); - if (curtime - m_previousAnimTime < anim_timestep) - return; - - // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) - // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime)); - m_previousAnimTime = curtime; - } - TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime); for (int i=0; i<m_animatedlist->GetCount(); ++i) { diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index c5840c28041..2e1ee9f101d 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -289,8 +289,6 @@ protected: double m_suspendedtime; double m_suspendeddelta; - double m_previousAnimTime; //the last time animations were updated - struct Scene* m_blenderScene; RAS_2DFilterManager m_filtermanager; diff --git a/source/gameengine/Network/CMakeLists.txt b/source/gameengine/Network/CMakeLists.txt index bae00c464f2..019fc3e6032 100644 --- a/source/gameengine/Network/CMakeLists.txt +++ b/source/gameengine/Network/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC . ../../../intern/container ../../../intern/string + ../../blender/blenlib ) set(INC_SYS diff --git a/source/gameengine/Network/SConscript b/source/gameengine/Network/SConscript index 1d78cdba174..feb14e29552 100644 --- a/source/gameengine/Network/SConscript +++ b/source/gameengine/Network/SConscript @@ -31,6 +31,7 @@ sources = env.Glob('*.cpp') #'NG_NetworkMessage.cpp NG_NetworkObject.cpp NG_Netw incs = [ '.', + '../../blender/blenlib', '#intern/container', '#intern/string', '#intern/moto/include', diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 72c3b13e301..ff68021f09e 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -207,6 +207,11 @@ btRigidBody* CcdPhysicsController::GetRigidBody() { return btRigidBody::upcast(m_object); } +const btRigidBody* CcdPhysicsController::GetRigidBody() const +{ + return btRigidBody::upcast(m_object); +} + btCollisionObject* CcdPhysicsController::GetCollisionObject() { return m_object; @@ -1354,6 +1359,42 @@ void CcdPhysicsController::Jump() void CcdPhysicsController::SetActive(bool active) { } + +float CcdPhysicsController::GetLinearDamping() const +{ + const btRigidBody* body = GetRigidBody(); + if (body) + return body->getLinearDamping(); + return 0; +} + +float CcdPhysicsController::GetAngularDamping() const +{ + const btRigidBody* body = GetRigidBody(); + if (body) + return body->getAngularDamping(); + return 0; +} + +void CcdPhysicsController::SetLinearDamping(float damping) +{ + SetDamping(damping, GetAngularDamping()); +} + +void CcdPhysicsController::SetAngularDamping(float damping) +{ + SetDamping(GetLinearDamping(), damping); +} + +void CcdPhysicsController::SetDamping(float linear, float angular) +{ + btRigidBody* body = GetRigidBody(); + if (!body) return; + + body->setDamping(linear, angular); +} + + // reading out information from physics MT_Vector3 CcdPhysicsController::GetLinearVelocity() { @@ -2265,7 +2306,7 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA /* transverts are only used for deformed RAS_Meshes, the RAS_TexVert data * is too hard to get at, see below for details */ float (*transverts)[3] = NULL; - int transverts_tot= 0; /* with deformed meshes - should always be greater then the max orginal index, or we get crashes */ + int transverts_tot= 0; /* with deformed meshes - should always be greater than the max orginal index, or we get crashes */ if (deformer) { /* map locations from the deformed array diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 4d0d96e07c6..557a5fe603a 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -522,6 +522,7 @@ protected: btRigidBody* GetRigidBody(); + const btRigidBody* GetRigidBody() const; btCollisionObject* GetCollisionObject(); btSoftBody* GetSoftBody(); btKinematicCharacterController* GetCharacterController(); @@ -573,6 +574,12 @@ protected: virtual void Jump(); virtual void SetActive(bool active); + virtual float GetLinearDamping() const; + virtual float GetAngularDamping() const; + virtual void SetLinearDamping(float damping); + virtual void SetAngularDamping(float damping); + virtual void SetDamping(float linear, float angular); + // reading out information from physics virtual MT_Vector3 GetLinearVelocity(); virtual MT_Vector3 GetAngularVelocity(); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index e17d4402556..38e7df6c573 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -504,9 +504,9 @@ bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr btRigidBody* body = ctrl->GetRigidBody(); if (body) { - for (int i=body->getNumConstraintRefs()-1;i>=0;i--) + for (int i = m_dynamicsWorld->getNumConstraints()-1;i>=0;i--) { - btTypedConstraint* con = body->getConstraintRef(i); + btTypedConstraint *con = m_dynamicsWorld->getConstraint(i); m_dynamicsWorld->removeConstraint(con); body->removeConstraintRef(con); //delete con; //might be kept by python KX_ConstraintWrapper diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h index f9975484fa7..1717f8d90cb 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h @@ -89,6 +89,12 @@ class PHY_IPhysicsController : public PHY_IController virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0; virtual void ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0; + virtual float GetLinearDamping() const=0; + virtual float GetAngularDamping() const=0; + virtual void SetLinearDamping(float damping)=0; + virtual void SetAngularDamping(float damping)=0; + virtual void SetDamping(float linear, float angular)=0; + virtual void SuspendDynamics(bool ghost=false)=0; virtual void RestoreDynamics()=0; diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 617e7fd1d8e..57b2e85845c 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -274,8 +274,6 @@ void ImageRender::Render() m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); - m_scene->UpdateAnimations(m_engine->GetFrameTime()); - m_scene->RenderBuckets(camtrans, m_rasterizer); m_scene->RenderFonts(); diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp index edf3c58bcbe..db76ba5822a 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -86,6 +86,13 @@ VideoFFmpeg::~VideoFFmpeg () { } +void VideoFFmpeg::refresh(void) +{ + // a fixed image will not refresh because it is loaded only once at creation + if (m_isImage) + return; + m_avail = false; +} // release components bool VideoFFmpeg::release() diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.h b/source/gameengine/VideoTexture/VideoFFmpeg.h index 4a948fe61de..4834a7cef6d 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.h +++ b/source/gameengine/VideoTexture/VideoFFmpeg.h @@ -85,7 +85,8 @@ public: /// release video source virtual bool release (void); - + /// overwrite base refresh to handle fixed image + virtual void refresh(void); /// play video virtual bool play (void); /// pause video |